From 6aa301b9466351538d779b98e3b756ac5bd34236 Mon Sep 17 00:00:00 2001
From: Julien Gouesse
- * NOTE: AudioEngine developers should not subclass this class directly.
- * Subclass AudioEngine3DL2 instead.
- */
-public abstract class AudioEngine implements AudioDevice {
-
- /*
- * This device's UNIX file descriptor
- */
- int fileDescriptor;
-
- /*
- * Type of audio output device J3D sound is played over:
- * HEADPHONE, MONO_SPEAKER, STEREO_SPEAKERS
- */
- int audioPlaybackType = HEADPHONES;
-
- /*
- * Distance from center ear (midpoint between ears) to physical speaker.
- * Default reflects distance for headphones.
- * For two speakers it is assumed that the speakers are the same
- * distance from the listener and that
- */
- float distanceToSpeaker = 0.0f;
-
- /*
- * Angle between the vector from center ear parallel to head coordiate
- * Z axis and the vector from the center ear to the speaker.
- * For two speakers it is assumed that the speakers are placed at the
- * same angular offset from the listener.
- */
- float angleOffsetToSpeaker = 0.0f;
-
- /*
- * Channels currently available
- */
- int channelsAvailable = 8;
-
- /*
- * Total number of Channels ever available
- */
- int totalChannels = 8;
-
- /**
- * Construct a new AudioEngine with the specified P.E.
- * @param physicalEnvironment the physical environment object where we
- * want access to this device.
- */
- public AudioEngine(PhysicalEnvironment physicalEnvironment ) {
- physicalEnvironment.setAudioDevice(this);
- }
-
- /**
- * Code to initialize the device
- * @return flag: true is initialized sucessfully, false if error
- */
- @Override
- public abstract boolean initialize();
-
- /**
- * Code to close the device
- * @return flag: true is closed sucessfully, false if error
- */
- @Override
- public abstract boolean close();
-
- /*
- * Audio Playback Methods
- */
- /**
- * Set Type of Audio Playback physical transducer(s) sound is output to.
- * Valid types are HEADPHONE, MONO_SPEAKER, STEREO_SPEAKERS
- * @param type of audio output device
- */
- @Override
- public void setAudioPlaybackType(int type) {
- audioPlaybackType = type;
- }
-
- /**
- * Get Type of Audio Playback Output Device
- * returns audio playback type to which sound is currently output
- */
- @Override
- public int getAudioPlaybackType() {
- return audioPlaybackType;
- }
-
- /**
- * Set Distance from the Center Ear to a Speaker
- * @param distance from the center ear and to the speaker
- */
- @Override
- public void setCenterEarToSpeaker(float distance) {
- distanceToSpeaker = distance;
- }
-
- /**
- * Get Distance from Ear to Speaker
- * returns value set as distance from listener's ear to speaker
- */
- @Override
- public float getCenterEarToSpeaker() {
- return distanceToSpeaker;
- }
-
- /**
- * Set Angle Offset To Speaker
- * @param angle in radian between head coordinate Z axis and vector to speaker */
- @Override
- public void setAngleOffsetToSpeaker(float angle) {
- angleOffsetToSpeaker = angle;
- }
-
- /**
- * Get Angle Offset To Speaker
- * returns value set as angle between vector to speaker and Z head axis
- */
- @Override
- public float getAngleOffsetToSpeaker() {
- return angleOffsetToSpeaker;
- }
-
- /**
- * Query total number of channels available for sound rendering
- * for this audio device.
- * returns number of maximum sound channels you can run with this
- * library/device-driver.
- */
- @Override
- public int getTotalChannels() {
- // this method should be overridden by a device specific implementation
- return (totalChannels);
- }
-
- /**
- * Query number of channels currently available for use by the
- * returns number of sound channels currently available (number
- * not being used by active sounds.
- */
- @Override
- public int getChannelsAvailable() {
- return (channelsAvailable);
- }
-
- /**
- * Query number of channels that would be used to render a particular
- * sound node.
- * @param sound refenence to sound node that query to be performed on
- * returns number of sound channels used by a specific Sound node
- * @deprecated This method is now part of the Sound class
- */
- @Override
- public int getChannelsUsedForSound(Sound sound) {
- if (sound != null)
- return sound.getNumberOfChannelsUsed();
- else
- return -1;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/audioengines/AudioEngine3D.java b/src/classes/share/com/sun/j3d/audioengines/AudioEngine3D.java
deleted file mode 100644
index dcf334a..0000000
--- a/src/classes/share/com/sun/j3d/audioengines/AudioEngine3D.java
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.audioengines;
-
-import java.util.ArrayList;
-
-import javax.media.j3d.AudioDevice3D;
-import javax.media.j3d.MediaContainer;
-import javax.media.j3d.PhysicalEnvironment;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.View;
-import javax.vecmath.Point3d;
-import javax.vecmath.Vector3d;
-
-
-/**
- * The AudioEngine3D Class defines an audio output device that generates
- * sound 'image' from high-level sound parameters passed to it during
- * scene graph.
- *
- *
- * The methods in this class are meant to be optionally overridden by an
- * extended class. This extended class would provice device specific code.
- *
- *
- * Error checking on all parameters passed to these methods is already
- * explicitly being done by the Java 3D core code that calls these methods.
- *
- *
- * NOTE: AudioEngine developers should not subclass this class directly.
- * Subclass AudioEngine3DL2 instead.
- */
-
-public abstract class AudioEngine3D extends AudioEngine implements AudioDevice3D
-{
- /*
- * Identifiers of sample associated with sound source
- * This array grows as the AudioDevice3D implementation requires it larger.
- */
- protected ArrayList samples = new ArrayList(64);
-
- /**
- * Current View sound is being rendered
- */
- protected View currentView = (View)null;
-
- /*
- * current Aural attribute Parameters
- */
- protected AuralParameters attribs = new AuralParameters();
-
- /**
- * Construct a new AudioEngine with the specified PhysicalEnvironment.
- * @param physicalEnvironment the physical environment object where we
- * want access to this device.
- */
- public AudioEngine3D(PhysicalEnvironment physicalEnvironment ) {
- super(physicalEnvironment);
- }
-
- /*
- *
- * Methods that affect AudioEngine3D fields that are NOT associated
- * with a specific sound sample
- *
- */
-
- /**
- * Save a reference to the current View object.
- * @param reference to current view object
- */
- @Override
- public void setView(View reference) {
- currentView = reference;
- return;
- }
- /**
- * Get reference to the current View object.
- * @return reference to current view object
- */
- public View getView() {
- return (currentView);
- }
-
- /*
- *
- * Methods explicitly affect sound rendering and that require
- * audio device specific methods that override this class.
- *
- */
-
- /**
- * Prepare Sound in device.
- * Makes sound assessible to device - in this case attempts to load sound
- * Stores sound type and data.
- * @param soundType denotes type of sound: Background, Point or Cone
- * @param soundData descrition of sound source data
- * @return index into sample vector of Sample object for sound
- */
- @Override
- public int prepareSound(int soundType, MediaContainer soundData) {
- // This method must be overridden by device specific implementation
- return Sample.NULL_SAMPLE;
- }
-
- /**
- * Clear Sound.
- * Removes/clears associated sound data with this sound source node
- * @param index device specific reference number to device driver sample
- */
- @Override
- public abstract void clearSound(int index);
-
- /**
- * Set the transform for local to virtual world coordinate space
- * @param index device specific reference number to device driver sample
- * @param trans is a reference to virtual world composite transform
- */
- @Override
- public void setVworldXfrm(int index, Transform3D trans) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.vworldXfrm.set(trans);
- return;
- }
- /**
- * Start sample playing on audio device
- * @param index device specific reference number to device driver sample
- * @return status: < 0 denotes an error
- */
- @Override
- public abstract int startSample(int index);
-
- /**
- * Stop sample playing on audio device
- * @param index device specific reference number to device driver sample
- * @return status: < 0 denotes an error
- */
- @Override
- public abstract int stopSample(int index);
-
- /**
- * Update sample.
- * Implies that some parameters affecting rendering have been modified.
- * @param index device specific reference number to device driver sample
- */
- // TODO: The update method exists on a TEMPORARY basis.
- @Override
- public abstract void updateSample(int index);
-
- /**
- * Mute sample.
- * @param index device specific reference number to device driver sample
- */
- @Override
- public abstract void muteSample(int index);
-
- /**
- * Unmute sample.
- * @param index device specific reference number to device driver sample
- */
- @Override
- public abstract void unmuteSample(int index);
-
- /**
- * Pause sample.
- * @param index device specific reference number to device driver sample
- */
- @Override
- public abstract void pauseSample(int index);
-
- /**
- * Unpause sample.
- * @param index device specific reference number to device driver sample
- */
- @Override
- public abstract void unpauseSample(int index);
-
- /*
- *
- * Methods that affect fields associated with the sound sample
- * and that may cause implicit rendering.
- *
- */
- /**
- * Set gain scale factor applied to sample.
- * @param index device specific reference number to device driver sample
- * @param scaleFactor floating point multiplier applied to sample amplitude
- */
- @Override
- public void setSampleGain(int index, float scaleFactor) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.setGain(scaleFactor);
- return;
- }
-
- /**
- * Set number of times sample is looped.
- * @param index device specific reference number to device driver sample
- * @param count number of times sample is repeated
- */
- @Override
- public void setLoop(int index, int count) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.setLoopCount(count);
- return;
- }
-
- /**
- * Set location of sample.
- * @param index device specific reference number to device driver sample
- * @param position point location in virtual world coordinate of sample
- */
- @Override
- public void setPosition(int index, Point3d position) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.setPosition(position);
- return;
- }
-
- /* Set elliptical distance attenuation arrays applied to sample amplitude.
- * @param index device specific reference number to device driver sample
- * @param frontDistance defines an array of distance along the position axis
- * thru which ellipses pass
- * @param frontAttenuationScaleFactor gain scale factors
- * @param backDistance defines an array of distance along the negative axis
- * thru which ellipses pass
- * @param backAttenuationScaleFactor gain scale factors
- */
- @Override
- public void setDistanceGain(int index,
- double[] frontDistance, float[] frontAttenuationScaleFactor,
- double[] backDistance, float[] backAttenuationScaleFactor) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.setDistanceGain(frontDistance, frontAttenuationScaleFactor,
- backDistance, backAttenuationScaleFactor);
- return;
- }
-
- /**
- * Set direction vector of sample.
- * @param index device specific reference number to device driver sample
- * @param direction vector in virtual world coordinate.
- */
- @Override
- public void setDirection(int index, Vector3d direction) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.setDirection(direction);
- return;
- }
-
- /**
- * Set angular attenuation arrays affecting angular amplitude attenuation
- * and angular distance filtering.
- * @param index device specific reference number to device driver sample
- * @param filterType denotes type of filtering (on no filtering) applied
- * to sample.
- * @param angle array containing angular distances from sound axis
- * @param attenuationScaleFactor array containing gain scale factor
- * @param filterCutoff array containing filter cutoff frequencies.
- * The filter values for each tuples can be set to Sound.NO_FILTER.
- */
- @Override
- public void setAngularAttenuation(int index, int filterType,
- double[] angle, float[] attenuationScaleFactor, float[] filterCutoff) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.setAngularAttenuation(filterType, angle,
- attenuationScaleFactor, filterCutoff);
- return;
- }
-
- /**
- * Set rolloff value for current aural attribute applied to all samples.
- * @param rolloff scale factor applied to standard speed of sound.
- */
- @Override
- public void setRolloff(float rolloff) {
- attribs.rolloff = rolloff;
- return;
- }
-
- /**
- * Set reverberation surface reflection coefficient value for current aural
- * attribute applied to all samples.
- * @param coefficient applied to amplitude of reverbation added at each
- * iteration of reverb processing.
- */
- @Override
- public void setReflectionCoefficient(float coefficient) {
- attribs.reflectionCoefficient = coefficient;
- return;
- }
-
- /**
- * Set reverberation delay time for current aural attribute applied to
- * all samples.
- * @param reverbDelay amount of time in millisecond between each
- * iteration of reverb processing.
- */
- @Override
- public void setReverbDelay(float reverbDelay) {
- attribs.reverbDelay = reverbDelay;
- return;
- }
-
- /**
- * Set reverberation order for current aural attribute applied to all
- * samples.
- * @param reverbOrder number of times reverb process loop is iterated.
- */
- @Override
- public void setReverbOrder(int reverbOrder) {
- attribs.reverbOrder = reverbOrder;
- return;
- }
-
- /**
- * Set distance filter for current aural attribute applied to all samples.
- * @param filterType denotes type of filtering (on no filtering) applied
- * to all sample based on distance between listener and sound.
- * @param dist is an attenuation array of distance and low-pass filter values.
- */
- @Override
- public void setDistanceFilter(int filterType,
- double[] dist, float[] filterCutoff) {
- attribs.setDistanceFilter(filterType, dist, filterCutoff);
- return;
- }
-
- /**
- * Set frequency scale factor for current aural attribute applied to all
- * samples.
- * @param scaleFactor frequency scale factor applied to samples normal
- * playback rate.
- */
- @Override
- public void setFrequencyScaleFactor(float scaleFactor) {
- attribs.frequencyScaleFactor = scaleFactor;
- return;
- }
- /**
- * Set velocity scale factor for current aural attribute applied to all
- * samples when Doppler is calculated.
- * @param scaleFactor scale factor applied to postional samples'
- * listener-to-soundSource velocity.
- * playback rate.
- */
- @Override
- public void setVelocityScaleFactor(float scaleFactor) {
- attribs.velocityScaleFactor = scaleFactor;
- return;
- }
-
- /**
- * Get number of channels used by a particular sample on the audio device.
- * @param index device specific reference number to device driver sample
- * @return number of channels currently being used by this sample.
- */
- @Override
- public int getNumberOfChannelsUsed(int index) {
- // This method must be overridden by device specific implementation
- Sample sample = getSample(index);
- if (sample != null)
- return (sample.getNumberOfChannelsUsed());
- else
- return 0;
- }
-
- /**
- * Get number of channels that would be used by a particular sample on
- * the audio device given the mute flag passed in as a parameter.
- * @param index device specific reference number to device driver sample
- * @param muteFlag denotes the mute state to assume while executing this
- * query. This mute value does not have to match the current mute state
- * of the sample.
- * @return number of channels that would be used by this sample if it
- * were playing.
- */
- @Override
- public int getNumberOfChannelsUsed(int index, boolean muteFlag) {
- // This method must be overridden by device specific implementation
- Sample sample = getSample(index);
- if (sample != null)
- return (sample.getNumberOfChannelsUsed());
- else
- return 0;
- }
-
- /**
- * Get length of time a sample would play if allowed to play to completion.
- * @param index device specific reference number to device driver sample
- * @return length of sample in milliseconds
- */
- @Override
- public long getSampleDuration(int index) {
- Sample sample = getSample(index);
- if (sample != null)
- return (sample.getDuration());
- else
- return 0L;
- }
-
- /**
- * Get time this sample begun playing on the audio device.
- * @param index device specific reference number to device driver sample
- * @return system clock time sample started
- */
- @Override
- public long getStartTime(int index) {
- Sample sample = getSample(index);
- if (sample != null)
- return (sample.getStartTime());
- else
- return 0L;
- }
-
- /**
- * Get reference to the array list of samples
- * @return reference to samples list
- * @deprecated unsafe to get reference to samples list with this method.
- * It's better to directly reference samples list within a synchronized
- * block which also contains calls to .getSample(index).
- */
- protected ArrayList getSampleList() {
- return (samples);
- }
-
- public int getSampleListSize() {
- return (samples.size());
- }
-
- /**
- * Get specific sample from indexed sample list
- * Checks for valid index before attempting to get sample from list.
- * @param index device specific reference number to device driver sample
- * @return reference to sample; returns null if index out of range.
- *
- * @since Java 3D 1.2.1
- */
- public Sample getSample(int index) {
- synchronized(samples) {
- if ((index >= 0) && (index < samples.size())) {
- Sample sample = (Sample)samples.get(index);
- return (sample);
- }
- else
- return null;
- }
- }
-
- /*
- * Get reference to current aural attribute parameters associated with
- * this audio device.
- * @return reference to current aural attribute parameters
- */
- public AuralParameters getAuralParameters() {
- return (attribs);
- }
-}
diff --git a/src/classes/share/com/sun/j3d/audioengines/AudioEngine3DL2.java b/src/classes/share/com/sun/j3d/audioengines/AudioEngine3DL2.java
deleted file mode 100644
index 1bffd52..0000000
--- a/src/classes/share/com/sun/j3d/audioengines/AudioEngine3DL2.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.audioengines;
-
-import javax.media.j3d.AudioDevice3DL2;
-import javax.media.j3d.AuralAttributes;
-import javax.media.j3d.PhysicalEnvironment;
-import javax.media.j3d.Sound;
-
-
-/**
- * The AudioEngine3DL2 Class defines an audio output device that generates
- * sound 'image' from high-level sound parameters passed to it during
- * scene graph.
- *
- *
- * The methods in this class are meant to be optionally overridden by an
- * extended class. This extended class would provice device specific code.
- *
- *
- * Error checking on all parameters passed to these methods is already
- * explicitly being done by the Java 3D core code that calls these methods.
- *
- *
- * These methods should NOT be called by any application if the audio engine
- * is associated with a Physical Environment used by Java3D Core.
- *
- * @since Java 3D 1.3
- */
-public abstract class AudioEngine3DL2 extends AudioEngine3D implements AudioDevice3DL2 {
- /**
- * Construct a new AudioEngine3DL2 with the specified PhysicalEnvironment.
- * @param physicalEnvironment the physical environment object where we
- * want access to this device.
- */
- public AudioEngine3DL2(PhysicalEnvironment physicalEnvironment ) {
- super(physicalEnvironment);
- }
-
- /*
- *
- * Methods that affect AudioEngine3DLD fields that are NOT associated
- * with a specific sound sample
- *
- */
-
- /**
- * Pauses audio device engine without closing the device and associated
- * threads.
- * Causes all cached sounds to be paused and all streaming sounds to be
- * stopped.
- */
- @Override
- public abstract void pause();
-
- /**
- * Resumes audio device engine (if previously paused) without
- * reinitializing the device.
- * Causes all paused cached sounds to be resumed and all streaming
- * sounds restarted.
- */
- @Override
- public abstract void resume();
-
- /**
- * Set overall gain control of all sounds playing on the audio device.
- * @param scaleFactor scale factor applied to calculated amplitudes for
- * all sounds playing on this device
- */
- @Override
- public abstract void setGain(float scaleFactor);
-
- /*
- *
- * Methods explicitly affect a particular sound rendering and that
- * require audio device specific methods that override this class.
- *
- */
-
- /**
- * Set scale factor applied to sample playback rate for a particular sound
- * associated with the audio device.
- * Changing the device sample rate affects both the pitch and speed.
- * This scale factor is applied to ALL sound types.
- * Changes (scales) the playback rate of a sound independent of
- * Doppler rate changes.
- * @param index device specific reference to device driver sample
- * @param scaleFactor non-negative factor applied to calculated
- * amplitudes for all sounds playing on this device
- * @see Sound#setRateScaleFactor
- */
- @Override
- public void setRateScaleFactor(int index, float scaleFactor) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.setRateScaleFactor(scaleFactor);
- return;
- }
-
-
- /*
- *
- * Methods explicitly affect aural attributes of the listening space
- * used to calculated reverberation during sound rendering.
- * These require audio device specific methods that override this class.
- *
- */
-
- /**
- * Set late reflection (referred to as 'reverb') attenuation.
- * This scale factor is applied to iterative, indistinguishable
- * late reflections that constitute the tail of reverberated sound in
- * the aural environment.
- * This parameter, along with the early reflection coefficient, defines
- * the reflective/absorptive characteristic of the surfaces in the
- * current listening region.
- * @param coefficient late reflection attenuation factor
- * @see AuralAttributes#setReverbCoefficient
- */
- @Override
- public void setReverbCoefficient(float coefficient) {
- attribs.reverbCoefficient = coefficient;
- return;
- }
-
-
- /**
- * Sets the early reflection delay time.
- * In this form, the parameter specifies the delay time between each order
- * of reflection (while reverberation is being rendered) explicitly given
- * in milliseconds.
- * @param reflectionDelay time between each order of early reflection
- * @see AuralAttributes#setReflectionDelay
- */
- @Override
- public void setReflectionDelay(float reflectionDelay) {
- attribs.reflectionDelay = reflectionDelay;
- return;
- }
-
- /**
- * Set reverb decay time.
- * Defines the reverberation decay curve.
- * @param time decay time in milliseconds
- * @see AuralAttributes#setDecayTime
- */
- @Override
- public void setDecayTime(float time) {
- attribs.decayTime = time;
- return;
- }
-
- /**
- * Set reverb decay filter.
- * This provides for frequencies above the given cutoff frequency to be
- * attenuated during reverb decay at a different rate than frequencies
- * below this value. Thus, defining a different reverb decay curve for
- * frequencies above the cutoff value.
- * @param frequencyCutoff value of frequencies in Hertz above which a
- * low-pass filter is applied.
- * @see AuralAttributes#setDecayFilter
- */
- @Override
- public void setDecayFilter(float frequencyCutoff) {
- attribs.decayFrequencyCutoff = frequencyCutoff;
- return;
- }
-
- /**
- * Set reverb diffusion.
- * This defines the echo dispersement (also referred to as 'echo density').
- * The value of this reverb parameter is expressed as a percent of the
- * audio device's minimum-to-maximum values.
- * @param diffusion percentage expressed within the range of 0.0 and 1.0
- * @see AuralAttributes#setDiffusion
- */
- @Override
- public void setDiffusion(float diffusion) {
- attribs.diffusion = diffusion;
- return;
- }
-
- /**
- * Set reverb density.
- * This defines the modal density (also referred to as 'spectral
- * coloration').
- * The value of this parameter is expressed as a percent of the audio
- * device's minimum-to-maximum values for this reverb parameter.
- * @param density reverb density expressed as a percentage,
- * within the range of 0.0 and 1.0
- * @see AuralAttributes#setDensity
- */
- @Override
- public void setDensity(float density) {
- attribs.density = density;
- return;
- }
-
-
- /**
- * Set the obstruction gain control. This method allows for attenuating
- * sound waves traveling between the sound source and the listener
- * obstructed by objects. Direct sound signals/waves for obstructed sound
- * source are attenuated but not indirect (reflected) waves.
- * There is no corresponding Core AuralAttributes method at this time.
- * @param index device specific reference to device driver sample
- * @param scaleFactor non-negative factor applied to direct sound gain
- */
- @Override
- public void setObstructionGain(int index, float scaleFactor) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.setObstructionGain(scaleFactor);
- return;
- }
-
- /**
- * Set the obstruction filter control.
- * This provides for frequencies above the given cutoff frequency
- * to be attenuated, during while the gain of an obstruction signal
- * is being calculated, at a different rate than frequencies
- * below this value.
- * There is no corresponding Core AuralAttributes method at this time.
- * @param index device specific reference to device driver sample
- * @param frequencyCutoff value of frequencies in Hertz above which a
- * low-pass filter is applied.
- */
-
- @Override
- public void setObstructionFilter(int index, float frequencyCutoff) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.setObstructionFilter(frequencyCutoff);
- return;
- }
-
- /**
- * Set the occlusion gain control. This method allows for attenuating
- * sound waves traveling between the sound source and the listener
- * occluded by objects. Both direct and indirect sound signals/waves
- * for occluded sound sources are attenuated.
- * There is no corresponding Core AuralAttributes method at this time.
- * @param index device specific reference to device driver sample
- * @param scaleFactor non-negative factor applied to direct sound gain
- */
- @Override
- public void setOcclusionGain(int index, float scaleFactor) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.setObstructionGain(scaleFactor);
- return;
- }
-
- /**
- * Set the occlusion filter control.
- * This provides for frequencies above the given cutoff frequency
- * to be attenuated, during while the gain of an occluded signal
- * is being calculated, at a different rate than frequencies below
- * this value.
- * There is no corresponding Core AuralAttributes method at this time.
- * @param index device specific reference to device driver sample
- * @param frequencyCutoff value of frequencies in Hertz above which a
- * low-pass filter is applied.
- */
- @Override
- public void setOcclusionFilter(int index, float frequencyCutoff) {
- Sample sample = getSample(index);
- if (sample != null)
- sample.setObstructionFilter(frequencyCutoff);
- return;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/audioengines/AudioEngineThread.java b/src/classes/share/com/sun/j3d/audioengines/AudioEngineThread.java
deleted file mode 100644
index be16a6e..0000000
--- a/src/classes/share/com/sun/j3d/audioengines/AudioEngineThread.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.audioengines;
-
-/*
- * Audio Engine Thread
- */
-
-
-/**
- * The Thread Class extended for Audio Device engines that must process
- * calls dynamically, in 'real-time" to asynchronously change engine
- * parameters.
- *
- *
- * NOTE: this class is probably not needed for those Audio Device implementations
- * that handle all dynamic parameters in the low-level audio library.
- */
-public class AudioEngineThread extends Thread {
-
- // Debug print flag
- static final protected boolean debugFlag = false;
-
-
- protected void debugPrint(String message) {
- if (debugFlag)
- System.out.println(message);
- }
-
- /**
- * The classification types.
- */
- protected static final int WORK_THREAD = 0x01;
- protected static final int UPDATE_THREAD = 0x02;
-
- /**
- * This runMonitor action puts the thread into an initial wait state
- */
- protected static final int WAIT = 0;
-
- /**
- * This runMonitor action notifies MasterControl that this thread
- * has completed and wait.
- */
- protected static final int NOTIFY_AND_WAIT = 1;
-
- /**
- * This runMonitor action tells the thread to run N number of
- * iterations.
- */
- protected static final int RUN = 2;
-
- /**
- * This runMonitor action tells the thread to stop running
- */
- protected static final int STOP = 3;
-
- /**
- * This indicates that this thread has been activated by MC
- */
- protected boolean active = false;
-
- /**
- * This indicates that this thread is alive and running
- */
- protected boolean running = true;
-
-
- /**
- * This indicates that this thread is ready
- */
- protected boolean started = false;
-
- /**
- * The time values passed into this thread
- */
- protected long referenceTime;
-
- /**
- * Use to assign threadOpts WAIT_ALL_THREADS
- */
- protected long lastWaitTimestamp = 0;
-
- /**
- * The type of this thread. It is one of the above constants.
- */
- protected int type;
-
- /**
- * The classification of this thread. It is one of the above constants.
- */
- protected int classification = WORK_THREAD;
-
- /**
- * The arguments passed in for this thread
- */
- protected Object[] args = null;
-
- /**
- * Flag to indicate that user initiate a thread stop
- */
- protected boolean userStop = false;
-
- /**
- * Flag to indicate that this thread is waiting to be notify
- */
- protected boolean waiting = false;
-
- /**
- * Some variables used to name threads correctly
- */
- protected static int numInstances = 0;
- protected int instanceNum = -1;
-
- /**
- * This constructor simply assigns the given id.
- */
- public AudioEngineThread(ThreadGroup t, String threadName) {
- super(t, threadName);
- if (debugFlag)
- debugPrint("AudioEngineThread.constructor("+threadName +")");
- }
-
- synchronized int newInstanceNum() {
- return (++numInstances);
- }
-
- int getInstanceNum() {
- if (instanceNum == -1)
- instanceNum = newInstanceNum();
- return instanceNum;
- }
-
- /**
- * This method is defined by all slave threads to implement
- * one iteration of work.
- */
- synchronized public void doWork() {
- if (debugFlag)
- debugPrint("AudioEngineThread.doWork()");
- }
-
- /**
- * This initializes this thread. Once this method returns, the thread is
- * ready to do work.
- */
- public void initialize() {
- if (debugFlag)
- debugPrint("AudioEngineThread.initialize()");
- this.start();
- while (!started) {
- try {
- Thread.currentThread().sleep(1, 0);
- } catch (InterruptedException e) {
- }
- }
- }
-
- /**
- * This causes the threads run method to exit.
- */
- public void finish() {
- while (!waiting) {
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {}
- }
- runMonitor(STOP, 0,null);
- }
-
- /*
- * This thread controls the syncing of all the canvases attached to
- * this view.
- */
- @Override
- public void run() {
- if (debugFlag)
- debugPrint("AudioEngineThread.run");
- runMonitor(WAIT, 0, null);
- while (running) {
- doWork();
- runMonitor(WAIT, 0, null);
- }
- // resource clean up
- shutdown();
- }
-
- synchronized public void runMonitor(int action, long referenceTime, Object[] args){
- switch (action) {
- case WAIT:
- if (debugFlag)
- debugPrint("AudioEngineThread.runMonitor(WAIT)");
- try {
- started = true;
- waiting = true;
- wait();
- } catch (InterruptedException e) {
- System.err.println(e);
- }
- waiting = false;
- break;
- case RUN:
- if (debugFlag)
- debugPrint("AudioEngineThread.runMonitor(RUN)");
- this.referenceTime = referenceTime;
- this.args = args;
- notify();
- break;
- case STOP:
- if (debugFlag)
- debugPrint("AudioEngineThread.runMonitor(STOP)");
- running = false;
- notify();
- break;
- }
- }
-
- public void shutdown() {
- }
-
- // default resource clean up method
- public void cleanup() {
- active = false;
- running = true;
- started = true;
- lastWaitTimestamp = 0;
- classification = WORK_THREAD;
- args = null;
- userStop = false;
- referenceTime = 0;
-
- }
-}
diff --git a/src/classes/share/com/sun/j3d/audioengines/AuralParameters.java b/src/classes/share/com/sun/j3d/audioengines/AuralParameters.java
deleted file mode 100644
index f2d4627..0000000
--- a/src/classes/share/com/sun/j3d/audioengines/AuralParameters.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.audioengines;
-
-
-/**
- * The AuralParameters Class defines a set of fields that define the
- * Aural listening environment. Many of the parameters correspond to
- * AuralAttribute fields.
- *
- *
- * Error checking on all parameters passed to these methods is already
- * explicitly being done by the Java 3D core code that calls these methods.
- */
-
-public class AuralParameters
-{
- // Speed of Sound in meters/milliseconds
- public static final float SPEED_OF_SOUND = 0.344f;
- public static final int NO_FILTERING = -1;
-
- public float rolloff = 1.0f;
- public float reflectionCoefficient = 0.0f;
- public float reverbDelay = 40.0f;
- public int reverbOrder = 0;
- public float frequencyScaleFactor = 1.0f;
- public float velocityScaleFactor = 0.0f;
- int filterType = NO_FILTERING;
- double[] filterDistance = null;
- float[] filterCutoff = null;
-
- /*
- * @since Java 3D 1.3
- */
- public float reverbCoefficient = 1.0f;
- public float reflectionDelay = 20.0f;
- public float decayTime = 1000.0f;
- public float decayFrequencyCutoff = 5000.0f;
- public float diffusion = 1.0f; // 100%
- public float density = 1.0f; // 100%
-
- /**
- * Construct a new AuralParameters object
- */
- public AuralParameters() {
- frequencyScaleFactor = 1.0f;
- velocityScaleFactor = 0.0f;
- rolloff = 1.0f;
- reflectionCoefficient = 0.0f;
- reflectionDelay = 20.0f;
- reverbCoefficient = 1.0f;
- reverbDelay = 40.0f;
- reverbOrder = 0;
- filterType = NO_FILTERING;
- filterDistance = new double[2]; // start out with array of two
- filterCutoff = new float[2]; // start out with array of two
- decayTime = 1000.0f;
- decayFrequencyCutoff = 5000.0f;
- diffusion = 1.0f; // 100%
- density = 1.0f; // 100%
- }
-
- public void setDistanceFilter(int filterType, double[] distance,
- float[] filterCutoff) {
- boolean error = false;
- boolean allocate = false;
- int attenuationLength = 0;
- if (distance == null || filterCutoff == null) {
- error = true;
- }
- else {
- attenuationLength = distance.length;
- if (attenuationLength == 0 || filterType == NO_FILTERING) {
- error = true;
- }
- }
- if (error) {
- this.filterType = NO_FILTERING;
- this.filterDistance = null;
- this.filterCutoff = null;
- if (debugFlag)
- debugPrint("setDistanceFilter NO_FILTERING");
- return;
- }
- this.filterType = filterType;
- if (debugFlag)
- debugPrint("setDistanceFilter type = " + filterType);
- if ((filterDistance == null) || (filterCutoff == null)) {
- allocate = true;
- }
- else if (attenuationLength > filterDistance.length) {
- allocate = true;
- }
- if (allocate) {
- if (debugFlag)
- debugPrint("setDistanceFilter length = " + attenuationLength);
- this.filterDistance = new double[attenuationLength];
- this.filterCutoff = new float[attenuationLength];
- }
- System.arraycopy(distance, 0, this.filterDistance, 0,
- attenuationLength);
- System.arraycopy(filterCutoff, 0, this.filterCutoff, 0,
- attenuationLength);
-
- if (debugFlag) {
- debugPrint("setDistanceFilter arrays = ");
- for (int i=0; i
- * NOTE: This class is not yet implemented.
- */
-
-class JSStream extends JSChannel {
- private static boolean warningReported = false;
-
- JSStream() {
- // Report a "not implemented" warning message
- if (!warningReported) {
- System.err.println("***");
- System.err.println("*** WARNING: JavaSoundMixer: Streaming (uncached) audio not implemented");
- System.err.println("***");
- warningReported = true;
- }
- }
-}
diff --git a/src/classes/share/com/sun/j3d/audioengines/javasound/JSThread.java b/src/classes/share/com/sun/j3d/audioengines/javasound/JSThread.java
deleted file mode 100644
index 0d5a090..0000000
--- a/src/classes/share/com/sun/j3d/audioengines/javasound/JSThread.java
+++ /dev/null
@@ -1,854 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.audioengines.javasound;
-
-/*
- * JavaSound engine Thread
- *
- * IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs
- * to be rewritten. When this is done, we may or may not need this class.
- */
-
-import com.sun.j3d.audioengines.AudioEngine3D;
-import com.sun.j3d.audioengines.AudioEngine3DL2;
-
-/**
- * The Thread Class extended for JavaSound Mixer specific audio device
- * calls that dynamically, in 'real-time" change engine parameters
- * such as volume/gain and sample-rate/frequency(pitch).
- */
-
-class JSThread extends com.sun.j3d.audioengines.AudioEngineThread {
-
- /**
- * The thread data for this thread
- */
- int totalChannels = 0;
- /**
- * flags denoting if dynamic gain or rate interpolation is to be performed
- */
- boolean rampGain = false;
-
- // global thread flat rampRate set true only when setTargetRate called
- // for any sample. but it is cleared only by doWork when no sample
- // has a need for the rate to be ramped any further.
- boolean rampRate = false;
-
-/*** TODO:
- *
- * scalefactors applied to current sample rate to determine delta changes
- * in rate (in Hz)
- *
- float currentGain = 1.0f;
- float targetGain = 1.0f;
-***********/
-
- // reference to engine that created this thread
- AudioEngine3D audioEngine = null;
-
- /**
- * This constructor simply assigns the given id.
- */
- JSThread(ThreadGroup t, AudioEngine3DL2 engine) {
- super(t, "J3D-JavaSoundThread");
- audioEngine = engine;
- // TODO: really get total JavaSound channels
- totalChannels = 32;
- if (debugFlag)
- debugPrint("JSThread.constructor("+t+")");
- }
-
-
-
- /**
- * This method performs one iteration of pending work to do
- *
- * Wildly "garbled" sounds was caused by unequal changes in delta
- * time verses delta distances (resulting in jumps in rate factors
- * calculated for Doppler. This work thread is meant to smoothly
- * increment/decrement changes in rate (and other future parameters)
- * until the target value is reached.
- */
- @Override
- synchronized public void doWork() {
- if (debugFlag)
- debugPrint("JSThread.doWork()");
-/*******
- while (rampRate || rampGain) {
-*********/
-/****** DESIGN
-// Loop while sound is playing, reget attributes and gains/reverb,... params
-// update lowlevel params then read modify then copy to line(s)
-
-can keep my own loop count for streams??? not really
-
-*******/
- // QUESTION: will size ever get smaller after get performed???
- int numSamples = audioEngine.getSampleListSize();
- JSSample sample = null;
- int numRateRamps = 0;
- for (int index = 0; index < numSamples; index++) {
- // loop thru samples looking for ones needing rate incremented
- sample = (JSSample)audioEngine.getSample(index);
- if (sample == null)
- continue;
- if (sample.getRampRateFlag()) {
- if (debugFlag)
- debugPrint(" rampRate true");
- boolean endOfRampReached = adjustRate(sample);
- sample.setRampRateFlag(!endOfRampReached);
- if (!endOfRampReached)
- numRateRamps++;
- }
- // TODO: support changes in gain this way as well
- }
- if (numRateRamps > 0) {
- rampRate = true;
-runMonitor(RUN, 0, null);
- }
- else
- rampRate = false;
-/*********
- try {
- Thread.sleep(4);
- } catch (InterruptedException e){}
-*********/
-/********
- } // while
-*********/
- // otherwise do nothing
- }
-
- int getTotalChannels() {
- return (totalChannels);
- }
-
- /**
- * Gradually change rate scale factor
- *
- * If the rate change is too great suddenly, it sounds like a
- * jump, so we need to change gradually over time.
- * Since an octive delta change up is 2.0 but down is 0.5, forced
- * "max" rate of change is different for both.
- * @return true if target rate value was reached
- */
- boolean adjustRate(JSSample sample) {
- // QUESTION: what should max delta rate changes be
- // Using 1/32 of a half-step (1/12 of an octive)???
- double maxRateChangeDown = 0.00130213;
- double maxRateChangeUp = 0.00260417;
-
- double lastActualRateRatio = sample.getCurrentRateRatio();
- double requestedRateRatio = sample.getTargetRateRatio();
- boolean endOfRamp = false; // flag denotes if target rate reached
- if ( lastActualRateRatio > 0 ) {
- double sampleRateRatio = requestedRateRatio; // in case diff = 0
- double diff = 0.0;
- if (debugFlag) {
- debugPrint("JSThread.adjustRate: between " +
- lastActualRateRatio + " & " + requestedRateRatio);
- }
- diff = requestedRateRatio - lastActualRateRatio;
- if (diff > 0.0) { // direction of movement is towards listener
- // inch up towards the requested target rateRatio
- if (diff >= maxRateChangeUp) {
- sampleRateRatio = lastActualRateRatio + maxRateChangeUp;
- if (debugFlag) {
- debugPrint(" adjustRate: " +
- "diff >= maxRateChangeUp so ");
- debugPrint(" adjustRate: " +
- " sampleRateRatio incremented up by max");
- }
- endOfRamp = false; // target value not reached
- }
- /*
- * otherwise delta change is within tolerance
- * so use requested RateRatio as calculated w/out change
- */
- else {
- sampleRateRatio = requestedRateRatio;
- if (debugFlag) {
- debugPrint(" adjustRate: " +
- " requestedRateRatio reached");
- }
- endOfRamp = true; // reached
- }
- }
- else if (diff < 0.0) { // movement is away from listener
- // inch down towards the requested target rateRatio
- if ((-diff) >= maxRateChangeDown) {
- sampleRateRatio = lastActualRateRatio - maxRateChangeDown;
- if (debugFlag) {
- debugPrint(" adjustRate: " +
- "-(diff) >= maxRateChangeUp so ");
- debugPrint(" adjustRate: " +
- " sampleRateRatio incremented down by max ");
- }
- endOfRamp = false; // target value not reached
- }
- /*
- * otherwise negitive delta change is within tolerance so
- * use sampleRateRatio as calculated w/out change
- */
- else {
- sampleRateRatio = requestedRateRatio;
- if (debugFlag) {
- debugPrint(" adjustRate: " +
- " requestedRateRatio reached");
- }
- endOfRamp = true; // reached
- }
- }
- else // there is no difference between last set and requested rates
- return true;
-
- this.setSampleRate(sample, (float)sampleRateRatio);
- }
- else {
- // this is the first time thru with a rate change
- if (debugFlag) {
- debugPrint(" adjustRate: " +
- "last requested rateRatio not set yet " +
- "so sampleRateRatio left unchanged");
- }
- this.setSampleRate(sample, (float)requestedRateRatio);
- endOfRamp = false; // target value not reached
- }
- return endOfRamp;
- } // adjustRate
-
- void setSampleRate(JSSample sample, JSAuralParameters attribs) {
-// TODO:
- }
-
- // gain set at start sample time as well
- void setSampleGain(JSSample sample, JSAuralParameters attribs) {
-/*******
- // take fields as already set in sample and updates gain
- // called after sample.render performed
- if (debugFlag)
- debugPrint("JSThread.setSampleGain()");
-leftGain, rightGain
- if (debugFlag) {
- debugPrint(" " +
- "StereoGain during update " + leftGain +
- ", " + rightGain);
- debugPrint(" " +
- "StereoDelay during update " + leftDelay +
- ", " + rightDelay);
- }
- int dataType = sample.getDataType();
- int soundType = sample.getSoundType();
- boolean muted = sample.getMuteFlag();
-
- if (debugFlag)
- debugPrint("setStereoGain for sample "+sample+" " + leftGain +
- ", " + rightGain);
- if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA ||
- dataType == JSAuralParameters.BUFFERED_AUDIO_DATA ) {
- thread.setSampleGain(sample, leftGain);
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- thread.setSampleGain(
- ((JSPositionalSample)sample).getSecondIndex(), rightGain); thread.setSampleGain(
- ((JSPositionalSample)sample).getReverbIndex(), reverbGain);
- }
- }
- // TODO: JavaSound does not support MIDI song panning yet
- else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
-
- dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
- // Stereo samples not used for Midi Song playback
- thread.setSampleGain(sample, (leftGain+rightGain) );
- ******
- // -1.0 far left, 0.0 center, 1.0 far right
- position = (leftGain - rightGain) / (leftGain + rightGain);
- JSMidi.setSamplePan(sample, position);
-
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- JSMidi.setSampleGain(
- ((JSPositionalSample)sample).getSecondIndex(), rightGain); JSMidi.setSampleGain(
- ((JSPositionalSample)sample).getReverbIndex(), reverbGain);
- }
- ******
- }
- else {
- if (debugFlag)
- debugPrint( "JSThread: Internal Error setSampleGain dataType " +
- dataType + " invalid");
- return;
- }
- *****
- // force specific gain
- // go ahead and set gain immediately
- this.setSampleGain(sample, scaleFactor);
- rampGain = false; // disable ramping of gain
-******/
- }
-
- void setSampleDelay(JSSample sample, JSAuralParameters attribs) {
-/******
- // take fields as already set in sample and updates delay
- // called after sample.render performed
- // adjust by attrib rolloff
- float delayTime = attribs.reverbDelay * attribs.rolloff;
-
- leftDelay = (int)(sample.leftDelay * attribs.rolloff);
- rightDelay = (int)(sample.rightDelay * attribs.rolloff);
-leftDelay, rightDelay
- int dataType = sample.getDataType();
- int soundType = sample.getSoundType();
- if (debugFlag)
- debugPrint("setStereoDelay for sample "+sample+" " + leftDelay +
- ", " + rightDelay);
- if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- JSStream.setSampleDelay(
- sample, leftDelay);
- JSStream.setSampleDelay(
- ((JSPositionalSample)sample).getSecondIndex(), rightDelay);
- }
- else
- JSStream.setSampleDelay(sample, 0);
- }
- else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- JSClip.setSampleDelay(
- sample, leftDelay);
- JSClip.setSampleDelay(
- ((JSPositionalSample)sample).getSecondIndex(), rightDelay);
- }
- else
- JSClip.setSampleDelay(sample, 0);
- }
- else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
-
- dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
- ********
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- JSMidi.setSampleDelay(
- sample, leftDelay);
- JSMidi.setSampleDelay(
- ((JSPositionalSample)sample).getSecondIndex(), rightDelay);
- }
- else
- ********
- JSMidi.setSampleDelay(sample, 0);
- }
- else {
- if (debugFlag)
- debugPrint( "JSThread: Internal Error setSampleDelay dataType " +
- dataType + " invalid");
- return;
- }
-******/
- }
-
- void setTargetGain(JSSample sample, float scaleFactor) {
-/**********
-// TODO: implement this
- // current gain is used as starting scalefactor for ramp
-// TEMPORARY: for now just set gain
- this.setSampleGain(sample, scaleFactor);
- rampGain = false;
- rampGain = true;
- targetGain = scaleFactor;
- runMonitor(RUN, 0, null);
-**********/
- }
-
- void setRate(JSSample sample, float rateScaleFactor) {
- // force specific rate
- // go ahead and set rate immediately
- // take fields as already set in sample and updates rate
- // called after sample.render performed
- this.setSampleRate(sample, rateScaleFactor);
- // disables rate from being gradually increased or decreased
- // don't set global thread flat rampRate false just because
- // one sample's rate is set to a specific value.
- sample.setRampRateFlag(false);
- }
-
- void setTargetRate(JSSample sample, float rateScaleFactor) {
- // make gradual change in rate factors up or down to target rate
- sample.setRampRateFlag(true);
- sample.setTargetRateRatio(rateScaleFactor);
- rampRate = true;
- runMonitor(RUN, 0, null);
- }
-
-// TODO: should have methods for delay and pan as well
-
- void setSampleGain(JSSample sample, float gain) {
-/***********
-// QUESTION: What needs to be synchronized???
- if (debugFlag)
- debugPrint("JSThread.setSampleGain for sample "+sample+" " + gain );
- int dataType = sample.getDataType();
- int soundType = sample.getSoundType();
- boolean muted = sample.getMuteFlag();
-// TODO:
- if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA)
-{
- com.sun.j3d.audio.J3DHaeStream.setSampleGain(index, gain);
- }
- else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
- com.sun.j3d.audio.J3DHaeClip.setSampleGain(index, gain);
- }
- else {
- // dataType==JSAuralParameters.STREAMING_MIDI_DATA
- // dataType==JSAuralParameters.BUFFERED_MIDI_DATA
- com.sun.j3d.audio.J3DHaeMidi.setSampleGain(index, gain);
- }
-***************/
- }
-
- void setSampleRate(JSSample sample, float scaleFactor) {
-/*********
-// QUESTION: What needs to be synchronized???
- // TODO: use sample.rateRatio??
- if (debugFlag)
- debugPrint("JSThread.setSampleRate sample " +
- sample + ", scale factor = " + scaleFactor);
- int dataType = sample.getDataType();
- int soundType = sample.getSoundType();
-
-// TODO:
- if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
- com.sun.j3d.audio.J3DHaeStream.scaleSampleRate(index, scaleFactor);
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- com.sun.j3d.audio.J3DHaeStream.scaleSampleRate(
- ((JSPositionalSample)sample).getSecondIndex(),
- scaleFactor);
- com.sun.j3d.audio.J3DHaeStream.scaleSampleRate(
- ((JSPositionalSample)sample).getReverbIndex(),
- scaleFactor);
- }
- }
- else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
- com.sun.j3d.audio.J3DHaeClip.scaleSampleRate(index, scaleFactor);
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- com.sun.j3d.audio.J3DHaeClip.scaleSampleRate(
- ((JSPositionalSample)sample).getSecondIndex(),
- scaleFactor);
- com.sun.j3d.audio.J3DHaeClip.scaleSampleRate(
- ((JSPositionalSample)sample).getReverbIndex(),
- scaleFactor);
- }
- }
- else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
- dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
- com.sun.j3d.audio.J3DHaeMidi.scaleSampleRate(index, scaleFactor);
- // TODO: MIDI only supported for Background sounds
- }
-***********/
- sample.setCurrentRateRatio(scaleFactor);
- }
-
- boolean startSample(JSSample sample) {
-/**********
-// QUESTION: should this have a return values - error - or not??
-
- int returnValue = 0;
- AuralParameters attribs = audioEngine.getAuralParameters();
- int soundType = sample.getSoundType();
- boolean muted = sample.getMuteFlag();
- int dataType = sample.getDataType();
- int loopCount = sample.getLoopCount();
- float leftGain = sample.leftGain;
- float rightGain = sample.rightGain;
- int leftDelay = (int)(sample.leftDelay * attribs.rolloff);
- int rightDelay = (int)(sample.rightDelay * attribs.rolloff);
- if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
- if (soundType == AudioDevice3D.BACKGROUND_SOUND) {
- returnValue = JSStream.startSample(sample,
- loopCount, leftGain);
- if (debugFlag)
- debugPrint("JSThread " +
- "start stream backgroundSound with gain " + leftGain);
- }
- else { // soundType is POINT_SOUND or CONE_SOUND
- // start up main left and right channels for spatial rendered sound
- returnValue = JSStream.startSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex(),
- loopCount, leftGain, rightGain, leftDelay, rightDelay);
- //
- // start up reverb channel w/out delay even if reverb not on now //
- float reverbGain = 0.0f;
- if (!muted && auralParams.reverbFlag) {
- reverbGain = sample.getGain() *
- attribs.reflectionCoefficient;
- }
- int reverbRtrnVal = JSStream.startSample(
- ((JSPositionalSample)sample).getReverbIndex(), loopCount, reverbGain);
- if (debugFlag)
- debugPrint("JSThread " +
- "start stream positionalSound with gain "+ leftGain +
- ", " + rightGain);
- }
- }
-
- else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
- if (soundType == AudioDevice3D.BACKGROUND_SOUND) {
- returnValue = JSClip.startSample(sample,
- loopCount, leftGain );
- if (debugFlag)
- debugPrint("JSThread " +
- "start buffer backgroundSound with gain " + leftGain);
- }
- else { // soundType is POINT_SOUND or CONE_SOUND
- // start up main left and right channels for spatial rendered sound
- returnValue = JSClip.startSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex(),
- loopCount, leftGain, rightGain, leftDelay, rightDelay);
- //
- // start up reverb channel w/out delay even if reverb not on now //
- float reverbGain = 0.0f;
- if (!muted && auralParams.reverbFlag) {
- reverbGain = sample.getGain() *
- attribs.reflectionCoefficient;
- }
- int reverbRtrnVal = JSClip.startSample(
- ((JSPositionalSample)sample).getReverbIndex(),
- loopCount, reverbGain);
-
- if (debugFlag)
- debugPrint("JSThread " +
- "start stream positionalSound with gain " + leftGain
- + ", " + rightGain);
- }
- }
- else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
- dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
- if (soundType == AudioDevice3D.BACKGROUND_SOUND) {
- returnValue = JSMidi.startSample(sample,
- loopCount, leftGain);
- if (debugFlag)
- debugPrint("JSThread " +
- "start Midi backgroundSound with gain " + leftGain);
- }
- else { // soundType is POINT_SOUND or CONE_SOUND
- // start up main left and right channels for spatial rendered sound
- returnValue = JSMidi.startSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex(),
- loopCount, leftGain, rightGain, leftDelay, rightDelay);
- *******
- // TODO: positional MIDI sounds not supported.
- // The above startSamples really just start on sample
- // Don't bother with reverb channel for now.
-
- //
- // start up reverb channel w/out delay even if reverb not on now //
- float reverbGain = 0.0f;
- if (!muted && auralParams.reverbFlag) {
- reverbGain = sample.getGain() *
- attribs.reflectionCoefficient;
- }
- int reverbRtrnVal = JSMidi.startSample(
- ((JSPositionalSample)sample).getReverbIndex(), loopCount, reverbGain);
- *******
- if (debugFlag)
- debugPrint("JSThread " +
- "start Midi positionalSound with gain "+ leftGain +
- ", " + rightGain);
- }
- }
-
- else {
- if (debugFlag)
- debugPrint(
- "JSThread: Internal Error startSample dataType " +
- dataType + " invalid");
- return false;
- }
- // TODO: have to look at return values and conditionally return 'success'
-**********/
- return true;
- }
-
- boolean stopSample(JSSample sample) {
-/***********
-// QUESTION: should this have a return values - error - or not??
- int dataType = sample.getDataType();
- int soundType = sample.getSoundType();
-
- int returnValue = 0;
- if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- returnValue = JSStream.stopSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex());
- returnValue = JSStream.stopSample(
- ((JSPositionalSample)sample).getReverbIndex());
- }
- else
- returnValue = JSStream.stopSample(sample);
- }
- else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- returnValue = JSClip.stopSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex());
- returnValue = JSClip.stopSample(
- ((JSPositionalSample)sample).getReverbIndex());
- }
- else
- returnValue = JSClip.stopSample(sample);
- }
- else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
- dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
-
- *****
- // TODO: positional sounds NOT supported yet
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- returnValue = JSMidi.stopSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex());
- returnValue = JSMidi.stopSample(
- ((JSPositionalSample)sample).getReverbIndex());
- }
- else
- *****
- returnValue = JSMidi.stopSample(sample);
- }
- else {
- if (debugFlag)
- debugPrint( "JSThread: Internal Error stopSample dataType " +
- dataType + " invalid");
- return -1;
- }
-
-************/
- return true;
- }
-
-
- void pauseSample(JSSample sample) {
-/**********
- int dataType = sample.getDataType();
- int soundType = sample.getSoundType();
- int returnValue = 0;
- if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- returnValue = JSStream.pauseSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex());
- returnValue = JSStream.pauseSample(
- ((JSPositionalSample)sample).getReverbIndex());
- }
- else
- returnValue = JSStream.pauseSample(sample);
- }
- else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- returnValue = JSClip.pauseSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex());
- returnValue = JSClip.pauseSample(
- ((JSPositionalSample)sample).getReverbIndex());
- }
- else
- returnValue = JSClip.pauseSample(sample);
- }
- else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
-
- dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
- *******
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- returnValue = JSMidi.pauseSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex());
- returnValue = JSMidi.pauseSample(
- ((JSPositionalSample)sample).getReverbIndex());
- }
- else
- *****
- returnValue = JSMidi.pauseSample(sample);
- }
- else {
- if (debugFlag)
- debugPrint(
- "JSThread: Internal Error pauseSample dataType " +
- dataType + " invalid");
- }
- if (returnValue < 0) {
- if (debugFlag)
- debugPrint( "JSThread: Internal Error pauseSample " +
- "for sample " + sample + " failed");
- }
-// QUESTION: return value or not???
- return;
-*************/
- }
-
- void unpauseSample(JSSample sample) {
-/**************
- int dataType = sample.getDataType();
- int soundType = sample.getSoundType();
- int returnValue = 0;
- if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- returnValue = JSStream.unpauseSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex());
- returnValue = JSStream.unpauseSample(
- ((JSPositionalSample)sample).getReverbIndex());
- }
- else
- returnValue = JSStream.unpauseSample(sample);
- }
- else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- returnValue = JSClip.unpauseSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex());
- returnValue = JSClip.unpauseSample(
- ((JSPositionalSample)sample).getReverbIndex());
- }
- else
- returnValue = JSClip.unpauseSample(sample);
- }
- else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
-
- dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
- *********
- // TODO: positional Midi sounds
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- returnValue = JSMidi.unpauseSamples(sample,
- ((JSPositionalSample)sample).getSecondIndex());
- returnValue = JSMidi.unpauseSample(
- ((JSPositionalSample)sample).getReverbIndex());
- }
- else
- *********
- returnValue = JSMidi.unpauseSample(sample);
- }
- else {
- if (debugFlag)
- debugPrint(
- "JSThread: Internal Error unpauseSample dataType " + dataType + " invalid");
- }
- if (returnValue < 0) {
- if (debugFlag)
- debugPrint( "JSThread: Internal Error unpauseSample " +
- "for sample " + sample + " failed");
-
- }
-// QUESTION: return value or not???
- return;
-*************/
- }
-
-// TODO:
- void muteSample(JSSample sample) {
- // is this already muted? if so don't do anytning
-
- // This determines if mute is done as a zero gain or
- // as a stop, advance restart...
- }
-
-// TODO:
- void unmuteSample(JSSample sample) {
- if (debugFlag)
- debugPrint( "JSThread.unmuteSample not implemented");
- }
-
- int startStreams() {
-// QUESTION: return value or not???
- return 0;
- }
- int startStream() {
-// QUESTION: return value or not???
- return 0;
- }
- int startClips() {
-// QUESTION: return value or not???
- return 0;
- }
- int startClip() {
-// QUESTION: return value or not???
- return 0;
- }
-
- /**
- * This initializes this thread. Once this method returns, the thread is
- * ready to do work.
- */
- @Override
- public void initialize() {
- super.initialize();
- // this.setPriority(Thread.MAX_PRIORITY);
- // TODO: init values of fields???
- if (debugFlag)
- debugPrint("JSThread.initialize()");
- // TODO: doesn't do anything yet
- }
-
- /**
- * Code to close the device
- * @return flag: true is closed sucessfully, false if error
- */
- boolean close() {
- // TODO: for now do nothing
- return false;
- }
-
- @Override
- public void shutdown() {
- }
-
-
-
-
- // default resource clean up method
- @Override
- public void cleanup() {
- super.cleanup();
- if (debugFlag)
- debugPrint("JSThread.cleanup()");
- }
-}
diff --git a/src/classes/share/com/sun/j3d/audioengines/javasound/JavaSoundMixer.java b/src/classes/share/com/sun/j3d/audioengines/javasound/JavaSoundMixer.java
deleted file mode 100644
index 1e96fee..0000000
--- a/src/classes/share/com/sun/j3d/audioengines/javasound/JavaSoundMixer.java
+++ /dev/null
@@ -1,984 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-/*
- * Audio device driver using Java Sound Mixer Engine.
- *
- * IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs
- * to be rewritten.
- */
-
-package com.sun.j3d.audioengines.javasound;
-
-import javax.media.j3d.AudioDevice3D;
-import javax.media.j3d.MediaContainer;
-import javax.media.j3d.PhysicalEnvironment;
-import javax.media.j3d.Sound;
-import javax.media.j3d.Transform3D;
-import javax.vecmath.Point3d;
-import javax.vecmath.Vector3d;
-
-import com.sun.j3d.audioengines.AudioEngine3DL2;
-import com.sun.j3d.audioengines.Sample;
-
-/**
- * The JavaSoundMixer Class defines an audio output device that accesses
- * JavaSound functionality stream data.
- */
-public class JavaSoundMixer extends AudioEngine3DL2 {
-
- // Debug print flags and methods
- static final boolean debugFlag = false;
- static final boolean internalErrors = false;
-
- void debugPrint(String message) {
- if (debugFlag)
- System.out.println(message);
- }
-
- void debugPrintln(String message) {
- if (debugFlag)
- System.out.println(message);
- }
-
- // Determines method to call for added or setting sound into ArrayList
- static final int ADD_TO_LIST = 1;
- static final int SET_INTO_LIST = 2;
-
- // current Aural Parameters = Aural Attributes from core + JavaSound
- // specific fields, including reverberation parameters.
- JSAuralParameters auralParams = null;
-
- // thread for dynamically changing audio parameters such as volume
- // and sample rate.
- JSThread thread = null;
-
- /*
- * new fields in extended class
- */
- protected float deviceGain = 1.0f;
-
- protected static final int NOT_PAUSED = 0;
- protected static final int PAUSE_PENDING = 1;
- protected static final int PAUSED = 2;
- protected static final int RESUME_PENDING = 3;
- protected int pause = NOT_PAUSED;
-
- /*
- * Construct a new JavaSoundMixer with the specified P.E.
- * @param physicalEnvironment the physical environment object where we
- * want access to this device.
- */
- public JavaSoundMixer(PhysicalEnvironment physicalEnvironment ) {
- super(physicalEnvironment);
- thread = new JSThread(Thread.currentThread().getThreadGroup(), this);
- }
-
- /**
- * Query total number of channels available for sound rendering
- * for this audio device.
- * Overridden method from AudioEngine.
- * @return number of maximum voices play simultaneously on JavaSound Mixer.
- */
- @Override
- public int getTotalChannels() {
- if (thread != null)
- return thread.getTotalChannels();
- else
- return 32;
- }
-
- /**
- * Code to initialize the device
- * New interface to mixer/engine specific methods
- * @return flag: true is initialized sucessfully, false if error
- */
- @Override
- public boolean initialize() {
- if (thread == null) {
- return false;
- }
- // init JavaSound dynamic thread
- thread.initialize();
- auralParams = new JSAuralParameters();
- if (debugFlag)
- debugPrintln("JavaSoundMixer: JSStream.initialize returned true");
- return true;
- }
-
- /**
- * Code to close the device.
- * New interface to mixer/engine specific methods
- * @return flag: true is closed sucessfully, false if error
- */
- @Override
- public boolean close() {
- if (thread == null)
- return false;
- if (thread.close()) {
- if (debugFlag)
- debugPrintln("JavaSoundMixer: JSStream.close returned true");
- return true;
- }
- else {
- if (debugFlag)
- debugPrintln("JavaSoundMixer: JSStream.close returned false");
- return false;
- }
- }
-
-
- /**
- * Code to load sound data into a channel of device mixer.
- * Load sound as one or mores sample into the Java Sound Mixer:
- * a) as either a STREAM or CLIP based on whether cached is enabled
- * b) positional and directional sounds use three samples per
- * sound
- * Overriden method from AudioEngine3D.
- *
- * Sound type determines if this is a Background, Point or Cone
- * sound source and thus the JSXxxxSample object type
- * Call JSXxxxxSample.loadSample()
- * If no error
- * Get the next free index in the samples list.
- * Store a reference to JSXxxxSample object in samples list.
- * @return index to the sample in samples list.
- */
- @Override
- public int prepareSound(int soundType, MediaContainer soundData) {
- int index = JSSample.NULL_SAMPLE;
- int methodType = ADD_TO_LIST;
- if (soundData == null)
- return JSSample.NULL_SAMPLE;
- synchronized(samples) {
- // for now force to just add to end of samples list
- int samplesSize = samples.size();
- index = samplesSize;
- samples.ensureCapacity(index+1);
- boolean error = false;
-
- if (soundType == AudioDevice3D.CONE_SOUND) {
- if (debugFlag)
- debugPrintln("JavaSoundMixer.prepareSound type=CONE");
- JSDirectionalSample dirSample = new JSDirectionalSample();
- error = dirSample.load(soundData);
- if (error)
- return JSSample.NULL_SAMPLE;
- if (methodType == SET_INTO_LIST)
- samples.set(index, dirSample);
- else
- samples.add(index, dirSample);
- /*
- * Since no error occurred while loading, save all the
- * characterstics for the sound in the sample.
- */
- dirSample.setDirtyFlags(0xFFFF);
- dirSample.setSoundType(soundType);
- dirSample.setSoundData(soundData);
-
- }
- else if (soundType == AudioDevice3D.POINT_SOUND) {
- if (debugFlag)
- debugPrintln("JavaSoundMixer.prepareSound type=POINT");
- JSPositionalSample posSample = new JSPositionalSample();
- error = posSample.load(soundData);
- if (error)
- return JSSample.NULL_SAMPLE;
- if (methodType == SET_INTO_LIST)
- samples.set(index, posSample);
- else
- samples.add(index, posSample);
- posSample.setDirtyFlags(0xFFFF);
- posSample.setSoundType(soundType);
- posSample.setSoundData(soundData);
- }
- else { // soundType == AudioDevice3D.BACKGROUND_SOUND
- if (debugFlag)
- debugPrintln("JavaSoundMixer.prepareSound type=BACKGROUND");
- JSSample sample = null;
- sample = new JSSample();
- error = sample.load(soundData);
- if (error)
- return JSSample.NULL_SAMPLE;
- if (methodType == SET_INTO_LIST)
- samples.set(index, sample);
- else
- samples.add(index, sample);
- sample.setDirtyFlags(0xFFFF);
- sample.setSoundType(soundType);
- sample.setSoundData(soundData);
- }
- }
-
- if (debugFlag) {
- debugPrint(" prepareSound type = "+soundType);
- debugPrintln("JavaSoundMixer.prepareSound returned "+index);
- }
- return index;
- }
-
- /**
- * Clears the fields associated with sample data for this sound.
- * Overriden method from AudioEngine3D.
- */
- @Override
- public void clearSound(int index) {
- // TODO: call JSXXXX clear method
- JSSample sample = null;
- if ( (sample = (JSSample)getSample(index)) == null)
- return;
- sample.clear();
- synchronized(samples) {
- samples.set(index, null);
- }
- }
-
- /**
- * Save a reference to the local to virtual world coordinate space
- * Overriden method from AudioEngine3D.
- */
- @Override
- public void setVworldXfrm(int index, Transform3D trans) {
- if (debugFlag)
- debugPrintln("JavaSoundMixer: setVworldXfrm for index " + index);
- super.setVworldXfrm(index, trans);
- if (debugFlag) {
- double[] matrix = new double[16];
- trans.get(matrix);
- debugPrintln("JavaSoundMixer column-major transform ");
- debugPrintln("JavaSoundMixer " + matrix[0]+", "+matrix[1]+
- ", "+matrix[2]+", "+matrix[3]);
- debugPrintln("JavaSoundMixer " + matrix[4]+", "+matrix[5]+
- ", "+matrix[6]+", "+matrix[7]);
- debugPrintln("JavaSoundMixer " + matrix[8]+", "+matrix[9]+
- ", "+matrix[10]+", "+matrix[11]);
- debugPrintln("JavaSoundMixer " + matrix[12]+", "+matrix[13]+
- ", "+matrix[14]+", "+matrix[15]);
- }
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return;
- int soundType = sample.getSoundType();
-
- if (soundType == AudioDevice3D.CONE_SOUND) {
- JSDirectionalSample dirSample = null;
- if ((dirSample = (JSDirectionalSample)getSample(index)) == null)
- return;
- dirSample.setXformedDirection();
- dirSample.setXformedPosition();
- // flag that VirtualWorld transform set
- dirSample.setVWrldXfrmFlag(true);
- }
- else if (soundType == AudioDevice3D.POINT_SOUND) {
- JSPositionalSample posSample = null;
- if ((posSample = (JSPositionalSample)getSample(index)) == null)
- return;
- posSample.setXformedPosition();
- // flag that VirtualWorld transform set
- posSample.setVWrldXfrmFlag(true);
- }
- return;
- }
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public void setPosition(int index, Point3d position) {
- if (debugFlag)
- debugPrintln("JavaSoundMixer: setPosition for index " + index);
- super.setPosition(index, position);
- JSPositionalSample posSample = null;
- if ((posSample = (JSPositionalSample)getSample(index)) == null)
- return;
- int soundType = posSample.getSoundType();
- if ( (soundType == AudioDevice3D.POINT_SOUND) ||
- (soundType == AudioDevice3D.CONE_SOUND) ) {
- posSample.setXformedPosition();
- }
- return;
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public void setDirection(int index, Vector3d direction) {
- if (debugFlag)
- debugPrintln("JavaSoundMixer: setDirection for index " + index);
- super.setDirection(index, direction);
- JSDirectionalSample dirSample = null;
- if ((dirSample = (JSDirectionalSample)getSample(index)) == null)
- return;
- int soundType = dirSample.getSoundType();
- if (soundType == AudioDevice3D.CONE_SOUND) {
- dirSample.setXformedDirection();
- }
- return;
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public void setReflectionCoefficient(float coefficient) {
- super.setReflectionCoefficient(coefficient);
- auralParams.reverbDirty |= JSAuralParameters.REFLECTION_COEFF_CHANGED;
- return;
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public void setReverbDelay(float reverbDelay) {
- super.setReverbDelay(reverbDelay);
- auralParams.reverbDirty |= JSAuralParameters.REVERB_DELAY_CHANGED;
- return;
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public void setReverbOrder(int reverbOrder) {
- super.setReverbOrder(reverbOrder);
- auralParams.reverbDirty |= JSAuralParameters.REVERB_ORDER_CHANGED;
- return;
- }
-
- /*
- * QUESTION: if this is used, for now, exclusively, to start a Background
- * or any single sampled Sounds, why are there if-else cases to handle
- * Point and Cone sounds??
- *
- * For now background sounds are not reverberated
- *
- * Overriden method from AudioEngine3D.
- */
- @Override
- public int startSample(int index) {
- // TODO: Rewrite this function
-
- if (debugFlag)
- debugPrintln("JavaSoundMixer: STARTSample for index " + index);
-
- JSSample sample = null;
- if ( ( (sample = (JSSample)getSample(index)) == null) ||
- thread == null )
- return JSSample.NULL_SAMPLE;
-
- int soundType = sample.getSoundType();
- boolean muted = sample.getMuteFlag();
- if (muted) {
- if (debugFlag)
- debugPrintln(" MUTEd start");
- thread.muteSample(sample);
- if (soundType != AudioDevice3D.BACKGROUND_SOUND)
- setFilter(index, false, Sound.NO_FILTER);
- }
- else {
- sample.render(sample.getDirtyFlags(), getView(), auralParams);
- this.scaleSampleRate(index, sample.rateRatio);
- // filtering
- if (soundType != AudioDevice3D.BACKGROUND_SOUND)
- setFilter(index, sample.getFilterFlag(), sample.getFilterFreq());
- }
-
- boolean startSuccessful;
- startSuccessful = thread.startSample(sample);
-
- sample.channel.startSample(sample.getLoopCount(), sample.getGain(), 0);
-
- if (!startSuccessful) {
- if (internalErrors)
- debugPrintln(
- "JavaSoundMixer: Internal Error startSample for index " +
- index + " failed");
- return JSSample.NULL_SAMPLE;
- }
- else {
- if (debugFlag)
- debugPrintln(" startSample worked, " +
- "returning " + startSuccessful);
- // NOTE: Set AuralParameters AFTER sound started
- // Setting AuralParameters before you start sound doesn't work
- if (!muted) {
- if (auralParams.reverbDirty > 0) {
- if (debugFlag) {
- debugPrintln("startSample: reverb settings are:");
- debugPrintln(" coeff = "+
- auralParams.reflectionCoefficient +
- ", delay = " + auralParams.reverbDelay +
- ", order = " + auralParams.reverbOrder);
- }
- float delayTime = auralParams.reverbDelay * auralParams.rolloff;
- calcReverb(sample);
- }
- // NOTE: it apprears that reverb has to be reset in
- // JavaSound engine when sound re-started??
- // force reset of reverb parameters when sound is started
- setReverb(sample);
- }
- return index;
- }
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public int stopSample(int index) {
- // TODO: Rewrite this function
-
- if (debugFlag)
- debugPrintln("JavaSoundMixer: STOPSample for index " + index);
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return -1;
-
- int dataType = sample.getDataType();
- int soundType = sample.getSoundType();
-
- boolean stopSuccessful = true;
- stopSuccessful = thread.stopSample(sample);
-
- sample.channel.stopSample();
-
- if (!stopSuccessful) {
- if (internalErrors)
- debugPrintln( "JavaSoundMixer: Internal Error stopSample(s) for index " +
- index + " failed");
- return -1;
- }
- else {
- // set fields in sample to reset for future start
- sample.reset();
- if (debugFlag)
- debugPrintln("JavaSoundMixer: stopSample for index " +
- index + " worked, returning " + stopSuccessful);
- return 0;
- }
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public void pauseSample(int index) {
- if (debugFlag)
- debugPrintln("JavaSoundMixer: PAUSESample for index " + index);
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return;
- // check thread != null
- thread.pauseSample(sample);
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public void unpauseSample(int index) {
- if (debugFlag)
- debugPrintln("JavaSoundMixer: UNPAUSESample for index " + index);
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return;
- thread.unpauseSample(sample);
- }
-
- /*
- * Force thread to update sample.
- * Overriden method from AudioEngine3D.
- */
-
- @Override
- public void updateSample(int index) {
- if (debugFlag)
- debugPrintln("JavaSoundMixer: UPDATESample for index " + index);
- JSSample sample = null;
- if ( ( (sample = (JSSample)getSample(index)) == null) ||
- thread == null )
- return;
-
- int soundType = sample.getSoundType();
- boolean muted = sample.getMuteFlag();
-
- if (muted) {
- if (soundType != AudioDevice3D.BACKGROUND_SOUND)
- setFilter(index, false, Sound.NO_FILTER);
- thread.muteSample(sample);
- if (debugFlag)
- debugPrintln(" Mute during update");
- }
- else {
- // If reverb parameters changed resend to audio device
- if (auralParams.reverbDirty > 0) {
- if (debugFlag) {
- debugPrintln("updateSample: reverb settings are:");
- debugPrintln(" coeff = " + auralParams.reflectionCoefficient+
- ", delay = " + auralParams.reverbDelay +
- ", order = " + auralParams.reverbOrder);
- }
- float delayTime = auralParams.reverbDelay * auralParams.rolloff;
- calcReverb(sample);
- }
- // TODO: Only re-set reverb if values different
- // For now force reset to ensure that reverb is currently correct
- setReverb(sample); // ensure reverb is current/correct
-
- // TODO: For now sum left & rightGains for reverb gain
- float reverbGain = 0.0f;
- if (!muted && auralParams.reverbFlag) {
- reverbGain = sample.getGain() * auralParams.reflectionCoefficient;
- }
-
- sample.render(sample.getDirtyFlags(), getView(), auralParams);
-
- // filtering
- if (soundType != AudioDevice3D.BACKGROUND_SOUND)
- setFilter(index, sample.getFilterFlag(), sample.getFilterFreq());
- thread.setSampleGain(sample, auralParams);
- thread.setSampleRate(sample, auralParams);
- thread.setSampleDelay(sample, auralParams);
- }
- return;
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public void muteSample(int index) {
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return;
-
- if (debugFlag)
- debugPrintln("JavaSoundMixer: muteSample");
- sample.setMuteFlag(true);
- thread.muteSample(sample);
- return;
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public void unmuteSample(int index) {
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return;
-
- if (debugFlag)
- debugPrintln("JavaSoundMixer: unmuteSample");
- sample.setMuteFlag(false);
-
- // since while mute the reverb type and state was not updated...
- // Reverb has to be recalculated when sound is unmuted .
- auralParams.reverbDirty = 0xFFFF; // force an update of reverb params
- sample.setDirtyFlags(0xFFFF); // heavy weight forcing of gain/delay update
-
- // TODO: force an update of ALL parameters that could have changed
- // while muting disabled...
-
- thread.unmuteSample(sample);
- return;
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public long getSampleDuration(int index) {
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return Sample.DURATION_UNKNOWN;
- long duration;
-
- if (sample != null)
- duration = sample.getDuration();
- else
- duration = Sample.DURATION_UNKNOWN;
- if (debugFlag)
- debugPrintln(" return duration " + duration);
- return duration;
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public int getNumberOfChannelsUsed(int index) {
- /*
- * Calls same method with different signature containing the
- * sample's mute flag passed as the 2nd parameter.
- */
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return 0;
- else
- return getNumberOfChannelsUsed(index, sample.getMuteFlag());
- }
-
- /**
- * Overriden method from AudioEngine3D.
- */
- @Override
- public int getNumberOfChannelsUsed(int index, boolean muted) {
- /*
- * The JavaSoundMixer implementation uses THREE channels to render
- * the stereo image of each Point and Cone Sounds:
- * Two for rendering the right and left portions of the rendered
- * spatialized sound image - panned hard right or left respectively.
- * This implementation uses one channel to render Background sounds
- * whether the sample is mono or stereo.
- *
- * TODO: When muted is implemented, that flag should be check
- * so that zero is returned.
- */
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return 0;
-
- int soundType = sample.getSoundType();
- int dataType = sample.getDataType();
-
- // TODO: for now positional Midi sound used only 1 sample
- if (dataType == JSSample.STREAMING_MIDI_DATA ||
- dataType == JSSample.BUFFERED_MIDI_DATA)
- return 1;
-
- if (soundType == BACKGROUND_SOUND)
- return 1;
- else // for Point and Cone sounds
- return 3;
- }
-
- /*
- * Overriden method from AudioEngine3D.
- */
- @Override
- public long getStartTime(int index) {
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return 0L;
- if (sample.channel == null)
- return 0L;
- return (long)sample.channel.startTime;
- }
-
- /*
- * Methods called during rendering
- */
- void scaleSampleRate(int index, float scaleFactor) {
- if (debugFlag)
- debugPrintln("JavaSoundMixer: scaleSampleRate index " +
- index + ", scale factor = " + scaleFactor);
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null ||
- thread == null)
- return;
- int dataType = sample.getDataType();
- if (debugFlag)
- debugPrintln(" scaleSampleRate.dataType = " + dataType +
- "using sample " + sample + " from samples[" +
- index +"]");
- int soundType = sample.getSoundType();
-
- if (dataType == JSSample.STREAMING_AUDIO_DATA ||
- dataType == JSSample.BUFFERED_AUDIO_DATA) {
- thread.setSampleRate(sample, scaleFactor);
- /**********
- // TODO:
- if (soundType != AudioDevice3D.BACKGROUND_SOUND) {
- thread.setSampleRate( ((JSPositionalSample)sample).getSecondIndex(),
- scaleFactor);
- thread.setSampleRate(((JSPositionalSample)sample).getReverbIndex(),
- scaleFactor);
- }
- **********/
- }
- else if (dataType == JSSample.STREAMING_MIDI_DATA ||
- dataType == JSSample.BUFFERED_MIDI_DATA) {
- thread.setSampleRate(sample, scaleFactor);
- /**********
- if (soundType != AudioDevice3D.BACKGROUND_SOUND) {
- thread.setSampleRate(((JSPositionalSample)sample).getSecondIndex(),
- scaleFactor);
- thread.setSampleRate(((JSPositionalSample)sample).getReverbIndex(),
- scaleFactor);
- }
- **********/
- }
- else {
- if (internalErrors)
- debugPrintln(
- "JavaSoundMixer: Internal Error scaleSampleRate dataType " +
- dataType + " invalid");
- }
- }
-
- /*
- * Methods called during rendering
- */
- void calcReverb(JSSample sample) {
- /*
- * Java Sound reverb parameters are a subset of Java 3D parameters
- */
- int dataType = sample.getDataType();
- int soundType = sample.getSoundType();
- float decay = auralParams.decayTime;
- float delay = auralParams.reverbDelay * auralParams.rolloff;
- float reflection = auralParams.reflectionCoefficient;
- int order = auralParams.reverbOrder;
- /*
- * Remember Coeff change is choosen over Order change if BOTH made
- * otherwise the last one changed take precidence.
- */
- if (auralParams.reflectionCoefficient == 0.0f ||
- auralParams.reverbCoefficient == 0.0f)
- auralParams.reverbFlag = false;
- else {
- auralParams.reverbFlag = true;
- if (order > 0) {
- // clamp reverb decay time to order*delay
- float clampedTime = order * delay;
- if ( clampedTime < decay)
- decay = clampedTime;
- }
- if (delay < 100.0f) {
- // "small" reverberant space
- if (decay <= 1500.0f)
- auralParams.reverbType = 2;
- else
- auralParams.reverbType = 4;
- }
- else if (delay < 500.0f) {
- // "medium" reverberant space
- if (decay <= 1500.0f)
- auralParams.reverbType = 3;
- else
- auralParams.reverbType = 6;
- }
- else { // delay >= 500.0f
- // "large" reverberant space
- if (decay <= 1500.0f)
- auralParams.reverbType = 6;
- else
- auralParams.reverbType = 5;
- }
- }
-
- if (debugFlag)
- debugPrintln("JavaSoundMixer: setReverb for " +
- sample + ", type = " + auralParams.reverbType + ", flag = " + auralParams.reverbFlag);
-
- auralParams.reverbDirty = 0; // clear the attribute reverb dirty flags
- }
-
- /*
- * Interal method for setting reverb parameters called during rendering.
- * This not called by SoundScheduler.
- */
- void setReverb(JSSample sample) {
- /*
- * Only third sample of multisample sounds has reverb parameters set.
- * For now, only positional and directional sounds are reverberated.
- */
- int soundType = sample.getSoundType();
- int dataType = sample.getDataType();
-
- // QUESTION: Should reverb be applied to background sounds?
- if ( (soundType == AudioDevice3D.CONE_SOUND) ||
- (soundType == AudioDevice3D.POINT_SOUND) ) {
- if (debugFlag)
- debugPrintln("setReverb called with type, on = " +
- auralParams.reverbType + ", " + auralParams.reverbFlag);
- if (sample == null)
- return;
- JSPositionalSample posSample = (JSPositionalSample)sample;
- if (posSample.channel == null)
- return;
-
- /**********
- // NOTE: no support for reverb channel yet...
- int reverbIndex = posSample.getReverbIndex();
- **********/
- if (dataType == JSSample.STREAMING_AUDIO_DATA) {
- JSStream stream = (JSStream)posSample.channel;
- stream.setSampleReverb(auralParams.reverbType, auralParams.reverbFlag);
- }
- else if (dataType == JSSample.BUFFERED_AUDIO_DATA) {
- JSClip clip = (JSClip)posSample.channel;
- clip.setSampleReverb(auralParams.reverbType, auralParams.reverbFlag);
- }
- /**********
- // TODO:
- else if (dataType == JSSample.STREAMING_MIDI_DATA ||
- dataType == JSSample.BUFFERED_MIDI_DATA) {
- JSMidi.setSampleReverb(reverbIndex,
- auralParams.reverbType, auralParams.reverbFlag);
- }
- **********/
- else {
- if (internalErrors)
- debugPrintln( "JavaSoundMixer: Internal Error setReverb " +
- "dataType " + dataType + " invalid");
- }
- }
- }
-
- // TEMPORARY: Override of method due to bug in Java Sound
- @Override
- public void setLoop(int index, int count) {
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return;
- int dataType = sample.getDataType();
-
- // WORKAROUND:
- // Bug in Java Sound engine hangs when INFINITE_LOOP count
- // for Audio Wave data. Leave count unchanged for Midi data.
- if (dataType==JSSample.STREAMING_AUDIO_DATA ||
- dataType==JSSample.BUFFERED_AUDIO_DATA) {
- if (count == Sound.INFINITE_LOOPS) {
- // LoopCount of 'loop Infinitely' forced to largest positive int
- count = 0x7FFFFFF;
- }
- }
- super.setLoop(index, count);
- return;
- }
-
- // Perform device specific filtering
- // Assumes that this is called for positional and directional sounds
- // not background sounds, so there are at lease two samples assigned
- // per sound.
- // TODO: remove assumption from method
- void setFilter(int index, boolean filterFlag, float filterFreq) {
- JSPositionalSample posSample = null;
- if ((posSample = (JSPositionalSample)getSample(index)) == null)
- return;
- if (posSample.channel == null)
- return;
- int dataType = posSample.getDataType();
-
- // Filtering can NOT be performed on MIDI Songs
- if (dataType == JSSample.STREAMING_MIDI_DATA ||
- dataType == JSSample.BUFFERED_MIDI_DATA) {
- return;
- }
-
- /****
- // TODO: multiple clips per channel
- int secondIndex = posSample.getSecondIndex();
- *****/
- if (dataType == JSSample.BUFFERED_AUDIO_DATA) {
- JSClip clip = (JSClip)posSample.channel;
- clip.setSampleFiltering(filterFlag,filterFreq);
- /*****
- JSClip.setSampleFiltering(econdIndex, filterFlag, filterFreq);
- ******/
- }
- else { // dataType == JSSample.STREAMING_AUDIO_DATA
- JSStream stream = (JSStream)posSample.channel;
- stream.setSampleFiltering(filterFlag,filterFreq);
- /*****
- JSStream.setSampleFiltering(secondIndex, ilterFlag, filterFreq);
- ******/
- }
- // QUESTION: should reverb channel be filtered???
-
- if (debugFlag) {
- debugPrintln("JavaSoundMixer:setFilter " +
- "of non-backgroundSound by (" +
- filterFlag + ", " + filterFreq + ")");
- }
- }
- //
- // Set overall gain for device
- // @since Java 3D 1.3
- //
- @Override
- public void setGain(float scaleFactor) {
- float oldDeviceGain = deviceGain;
- float gainFactor = scaleFactor/oldDeviceGain;
- // TODO: for each sample, change gain by gainFactor
- deviceGain = scaleFactor; // set given scalefactor as new device gain
- return;
- }
-
- /*
- * Set sample specific sample rate scale factor gain
- * @since Java 3D 1.3
- */
- @Override
- public void setRateScaleFactor(int index, float rateScaleFactor) {
- JSSample sample = null;
- if ((sample = (JSSample)getSample(index)) == null)
- return;
- sample.setRateScaleFactor(rateScaleFactor);
- this.scaleSampleRate(index, rateScaleFactor);
- }
-
- /**
- * Pauses audio device engine without closing the device and associated
- * threads.
- * Causes all cached sounds to be paused and all streaming sounds to be
- * stopped.
- */
- @Override
- public void pause() {
- pause = PAUSE_PENDING;
- // TODO: pause all sounds
- return;
- }
- /**
- * Resumes audio device engine (if previously paused) without reinitializing * the device.
- * Causes all paused cached sounds to be resumed and all streaming sounds
- * restarted.
- */
- @Override
- public void resume() {
- pause = RESUME_PENDING;
- // TODO: unpause all sounds
- return;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/audioengines/javasound/package.html b/src/classes/share/com/sun/j3d/audioengines/javasound/package.html
deleted file mode 100644
index 5897bc9..0000000
--- a/src/classes/share/com/sun/j3d/audioengines/javasound/package.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
- Provides a JavaSound-based implementation of a Java 3D audio device. Provides abstract classes for creating Java 3D audio devices.
- * NOTE: this is an experimental interface, which is not intended for use
- * by applications.
- *
- * @author pepe
- *
- * @since Java 3D 1.5
- */
-public interface AutoOffScreenCanvas3D extends javax.media.j3d.AutoOffScreenCanvas3D {}
diff --git a/src/classes/share/com/sun/j3d/exp/swing/package.html b/src/classes/share/com/sun/j3d/exp/swing/package.html
deleted file mode 100644
index e1cff44..0000000
--- a/src/classes/share/com/sun/j3d/exp/swing/package.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
- EXPERIMENTAL: Provides a lightweight JCanvas3D class.
-Note that the API in this package is highly experimental and
-subject to change at any time.
- * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2
- * community source release on java.net. We should be able to get rid
- * of this class.
- */
-
-public abstract class BufferWrapper {
-
- /**
- * Value returned from getBufferType(), this indicates
- * that the BufferWrapper contains a null buffer.
- */
- public static final int TYPE_NULL = 0;
-
- /**
- * Value returned from getBufferType(), this indicates
- * that the BufferWrapper does not hold data of type
- * byte, float, or double.
- */
- public static final int TYPE_UNKNOWN = 1;
-
- /**
- * Value returned from getBufferType(), this indicates
- * that the BufferWrapper contains a java.nio.ByteBuffer.
- */
- public static final int TYPE_BYTE = 2;
-
- /**
- * Value returned from getBufferType(), this indicates
- * that the BufferWrapper contains a java.nio.FloatBuffer.
- */
- public static final int TYPE_FLOAT = 3;
-
- /**
- * Value returned from getBufferType(), this indicates
- * that the BufferWrapper contains a java.nio.DoubleBuffer.
- */
- public static final int TYPE_DOUBLE = 4;
-
- /**
- * Never used - this class is abstract.
- */
- public BufferWrapper() {
- }
-
- /**
- * Must be implemented by sublasses.
- */
- abstract Buffer getBuffer();
-
- /**
- * @return Buffer as object of type Object.
- */
- public Object getBufferAsObject() {
- return getBuffer();
- }
-
- // Wrapper for all relevant Buffer methods.
-
- /**
- * @return This buffer's capacity (set at initialization in
- * allocateDirect() ).
- * @see ByteBufferWrapper#allocateDirect
- */
- public int capacity() {
- return getBuffer().capacity();
- }
-
- /**
- * @return This buffer's limit.
- */
- public int limit() {
- return getBuffer().limit();
- }
-
- /**
- * @return This buffer's position.
- */
- public int position() {
- return getBuffer().position();
- }
-
- /**
- * Sets this buffer's position.
- * @return This buffer.
- */
- public BufferWrapper position(int newPosition){
- getBuffer().position(newPosition);
- return this;
- }
-
- /**
- * Resets this buffer's position to the previously marked
- * position.
- * @return This buffer.
- */
- public BufferWrapper rewind() {
- getBuffer().rewind();
- return this;
- }
-
- /**
- * @return An integer indicating the type of data held in
- * this buffer.
- * @see #TYPE_NULL
- * @see #TYPE_BYTE
- * @see #TYPE_FLOAT
- * @see #TYPE_DOUBLE
- * @see #TYPE_UNKNOWN
- */
- public static int getBufferType(J3DBuffer b) {
- int bufferType;
- Buffer buffer = b.getBuffer();
-
- if (buffer == null) {
- bufferType = TYPE_NULL;
- }
- else if (buffer instanceof java.nio.ByteBuffer) {
- bufferType = TYPE_BYTE;
- }
- else if (buffer instanceof java.nio.FloatBuffer) {
- bufferType = TYPE_FLOAT;
- }
- else if (buffer instanceof java.nio.DoubleBuffer) {
- bufferType = TYPE_DOUBLE;
- }
- else {
- bufferType = TYPE_UNKNOWN;
- }
- return bufferType;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/internal/ByteBufferWrapper.java b/src/classes/share/com/sun/j3d/internal/ByteBufferWrapper.java
deleted file mode 100644
index 9d30fa9..0000000
--- a/src/classes/share/com/sun/j3d/internal/ByteBufferWrapper.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.internal;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-import javax.media.j3d.J3DBuffer;
-
-/**
- * NIO Buffers are new in Java 1.4 but we need to run on 1.3
- * as well, so this class was created to hide the NIO classes
- * from non-1.4 Java 3D users.
- *
- *
- * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2
- * community source release on java.net. We should be able to get rid
- * of this class.
- */
-
-public class ByteBufferWrapper extends BufferWrapper {
-
- private ByteBuffer buffer = null;
-
- /**
- * Constructor initializes buffer with a
- * java.nio.ByteBuffer object.
- */
- public ByteBufferWrapper(ByteBuffer buffer) {
- this.buffer = buffer;
- }
-
- /**
- * Constructor initializes buffer with a
- * javax.media.j3d.J3DBuffer object.
- */
- public ByteBufferWrapper(J3DBuffer b) {
- buffer = (ByteBuffer)(b.getBuffer());
- }
-
- /**
- * Allocate a direct ByteBuffer with the given capacity.
- * @return New ByteBufferWrapper containing the
- * new buffer.
- */
- public static ByteBufferWrapper allocateDirect(int capacity) {
- ByteBuffer bb = ByteBuffer.allocateDirect(capacity);
- return new ByteBufferWrapper(bb);
- }
-
- /**
- * Returns the java.nio.Buffer contained within this
- * ByteBufferWrapper.
- */
- @Override
- public java.nio.Buffer getBuffer() {
- return this.buffer;
- }
-
- // Wrapper for all relevant ByteBuffer methods.
-
- /**
- * @return A boolean indicating whether the java.nio.Buffer
- * object contained within this ByteBuffer is direct or
- * indirect.
- */
- public boolean isDirect() {
- return buffer.isDirect();
- }
-
- /**
- * Reads the byte at this buffer's current position,
- * and then increments the position.
- */
- public byte get() {
- return buffer.get();
- }
-
- /**
- * Reads the byte at the given offset into the buffer.
- */
- public byte get(int index) {
- return buffer.get(index);
- }
-
- /**
- * Bulk get method. Transfers
- * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2
- * community source release on java.net. We should be able to get rid
- * of this class.
- */
-
-public class DoubleBufferWrapper extends BufferWrapper {
-
- private DoubleBuffer buffer = null;
-
- /**
- * Constructor initializes buffer with a
- * java.nio.DoubleBuffer object.
- */
- public DoubleBufferWrapper(DoubleBuffer buffer) {
- this.buffer = buffer;
- }
-
- /**
- * Constructor initializes buffer with a
- * javax.media.j3d.J3DBuffer object.
- */
- public DoubleBufferWrapper(J3DBuffer b) {
- buffer = (DoubleBuffer)(b.getBuffer());
- }
-
- /**
- * Returns the java.nio.Buffer contained within this
- * DoubleBufferWrapper.
- */
- @Override
- public java.nio.Buffer getBuffer() {
- return this.buffer;
- }
-
- // Wrapper for all relevant DoubleBuffer methods.
-
- /**
- * @return A boolean indicating whether the java.nio.Buffer
- * object contained within this DoubleBuffer is direct or
- * indirect.
- */
- public boolean isDirect() {
- return buffer.isDirect();
- }
-
- /**
- * Reads the double at this buffer's current position,
- * and then increments the position.
- */
- public double get() {
- return buffer.get();
- }
-
- /**
- * Reads the double at the given offset into the buffer.
- */
- public double get(int index) {
- return buffer.get(index);
- }
-
- /**
- * Bulk get method. Transfers
- * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2
- * community source release on java.net. We should be able to get rid
- * of this class.
- */
-
-public class FloatBufferWrapper extends BufferWrapper {
-
- private FloatBuffer buffer = null;
-
- /**
- * Constructor initializes buffer with a
- * java.nio.FloatBuffer object.
- */
- public FloatBufferWrapper(FloatBuffer buffer) {
- this.buffer = buffer;
- }
-
- /**
- * Constructor initializes buffer with a
- * javax.media.j3d.J3DBuffer object.
- */
- public FloatBufferWrapper(javax.media.j3d.J3DBuffer b) {
- this.buffer = (FloatBuffer)(b.getBuffer());
- }
-
- /**
- * Returns the java.nio.Buffer contained within this
- * FloatBufferWrapper.
- */
- @Override
- public java.nio.Buffer getBuffer() {
- return this.buffer;
- }
-
- // Wrapper for all relevant FloatBuffer methods.
-
- /**
- * @return A boolean indicating whether the java.nio.Buffer
- * object contained within this FloatBuffer is direct or
- * indirect.
- */
- public boolean isDirect() {
- return buffer.isDirect();
- }
-
- /**
- * Reads the float at this buffer's current position,
- * and then increments the position.
- */
- public float get() {
- return buffer.get();
- }
-
- /**
- * Reads the float at the given offset into the buffer.
- */
- public float get(int index) {
- return buffer.get(index);
- }
-
- /**
- * Bulk get method. Transfers Provides a Java 3D loader for Lightwave 3D scene files.
- * Lightweight canvas also handles redirection to heavyweight canvas for the
- * following events:
- * - InputMethodEvent
- * - KeyEvent
- * - FocusEvent
- * - ComponentKeyEvent
- * - MouseWheelEvent
- * - MouseEvent
- * - MouseMotionEvent
- *
- *
- * When Swing is waiting for a canvas to be retrieved and that canvas is in
- * rendering stage,a loop takes place, which includes small calls to wait().
- * The canvas status is tested for readiness before and after the wait(). If
- * the canvas is not ready to be retrieved after the wait(), counter is
- * decremented and control is given back to awt thread, which will repaint old
- * buffer. If the loop goes over a certain amount of iterations, the canvas is
- * declared 'crashed' and won't be updated anymore. This was done so that a
- * crashed canvas/universe does not remove control over your GUI and does not
- * leave you with a frozen application. In current implementation, the delay
- * before a canvas is declared crashed is of :
- * 30 Math.max(20.0, getView().getMinimumFrameCycleTime() )
- *
- * @author Frederic 'pepe' Barachant
- *
- * @see getLightweightComponent()
- * @see setResizeValidationDelay()
- * @see setResizeMode()
- *
- * @since Java 3D 1.5
- */
-public class JCanvas3D extends JPanel implements AncestorListener {
- /**
- * Resizing the canvas or component will be done immediately. This
- * operation might take some time and make the application look sluggish.
- *
- * @see setResizeMode()
- */
- public final static int RESIZE_IMMEDIATELY = 0;
-
- /**
- * Resizing the canvas or component will be done if no resizing
- * occurs after expiration of a certain delay. Rendering will be
- * eventually stretched or deformed. It can be useful on certain
- * applications where smooth update of UI during layout is needed or
- * desired.
- *
- * @see setResizeMode()
- */
- public final static int RESIZE_DELAYED = 1;
-
- //TODO: FBA: this had been taken from javax.media.j3d.Screen3D. When/IF proper dpi handling comes one day, that part will have to be changed also for consistency
- /** size of a pixel */
- private static double METERS_PER_PIXEL = 0.0254 / 90.0;
-
- /** the template to be used for this canvas */
- private GraphicsConfigTemplate3D template;
-
- /** the graphics configuration used for this canvas */
- private GraphicsConfiguration graphicsConfig;
-
- /** The canvas that is linked to the component. */
- private InternalCanvas3D canvas;
-
- /** flag indicating that the JCanvas3D has been added to a container */
- private boolean hasBeenAdded = false;
-
- /** The resize mode currently being used. */
- int resizeMode;
-
- /**
- * the idle delay that will trigger a real resize. ('idle' being
- * the lack of resizing action from the user)
- */
- int resizeValidationDelay;
-
- /** the device to be used by this canvas */
- private GraphicsDevice device;
-
- //TODO: FBA: the constructor below should be callable. Code should be changed so that it is possible, in order for the canvas to be useable into netbeans.
- //TODO: FBA: create a netbeans module that installs J3D as a library and the JCanvas3D as a new item in a new J3D category of the swing palette (take from the java.net swash project)
-
- /**
- * Constructs and initializes a new JCanvas3D object that Java 3D
- * can render into. The screen device is obtained from
- * GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
,
- * which might not be the one you should use if you are in a multiscreen environment.
- * The JCanvas3D is constructed using the following default parameters:
- * resize mode : RESIZE_IMMEDIATELY
- * validation delay : 100ms
- * double buffer enable : false
- * stereo enable : false
- */
- public JCanvas3D() {
- this(null, GraphicsEnvironment.getLocalGraphicsEnvironment().
- getDefaultScreenDevice());
- }
-
- /**
- * Constructs and initializes a new Canvas3D object that Java 3D
- * can render into, using the specified graphics device.
- *
- * @param device the screen graphics device that will be used to construct
- * a GraphicsConfiguration.
- */
- public JCanvas3D(GraphicsDevice device) {
- this(null, device);
- }
-
- /**
- * Constructs and initializes a new Canvas3D object that Java 3D
- * can render into, using the specified template.
- * The screen device is obtained from
- * GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
,
- * which might not be the one you should use if you are
- * in a multiscreen environment.
- *
- * @param template The template that will be used to construct a
- * GraphicsConfiguration. The stereo and doublebuffer properties
- * are forced to UNNECESSARY.
- */
- public JCanvas3D(GraphicsConfigTemplate3D template) {
- this(template, GraphicsEnvironment.getLocalGraphicsEnvironment().
- getDefaultScreenDevice());
- }
-
- /**
- * Constructs and initializes a new Canvas3D object that Java 3D
- * can render into, using the specified template and graphics device.
- *
- * @param template The template that will be used to construct a
- * GraphicsConfiguration. The stereo and doublebuffer properties
- * are forced to UNNECESSARY.
- * @param device the screen graphics device that will be used to construct
- * a GraphicsConfiguration in conjunction with the template.
- */
- public JCanvas3D(GraphicsConfigTemplate3D template, GraphicsDevice device) {
- this.device = device;
- this.template = new GraphicsConfigTemplate3D();
-
- if (template != null) {
- // Clone template (it would be easier if GCT3D were cloneable)
- this.template.setRedSize(template.getRedSize());
- this.template.setGreenSize(template.getGreenSize());
- this.template.setBlueSize(template.getBlueSize());
- this.template.setDepthSize(template.getDepthSize());
- this.template.setSceneAntialiasing(template.getSceneAntialiasing());
- this.template.setStencilSize(template.getStencilSize());
- this.template.setDoubleBuffer(template.getDoubleBuffer());
-// this.template.setStereo(template.getStereo());
- }
-
- // Force double-buffer and stereo to UNNECESSARY
- this.template.setStereo(GraphicsConfigTemplate.UNNECESSARY);
-
- graphicsConfig = this.device.getBestConfiguration(this.template);
-
- addAncestorListener(this);
- setDoubleBuffered(false);
- setResizeMode(RESIZE_IMMEDIATELY);
- setResizeValidationDelay(100);
-
- // so that key events and such can be received.
- setFocusable(true);
- }
-
- /**
- * {@inheritDoc}
- *
- * @param event {@inheritDoc}
- */
- @Override
- public void ancestorAdded(javax.swing.event.AncestorEvent event) {
- // if ( true == isVisible( ) ) // check if the component itself is visible.
- {
- Dimension sz = getSize();
-
- if (0 == sz.width) {
- sz.width = 100;
- }
-
- if (0 == sz.height) {
- sz.height = 100;
- }
-
- createCanvas(sz.width, sz.height);
- canvas.addNotifyFlag = true; // make it so that i can call addNotify() without being rejected.
- canvas.addNotify();
- hasBeenAdded = true;
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @param event {@inheritDoc}
- */
- @Override
- public void ancestorMoved(javax.swing.event.AncestorEvent event) {
- }
-
- /**
- * {@inheritDoc}
- *
- * @param event {@inheritDoc}
- */
- @Override
- public void ancestorRemoved(javax.swing.event.AncestorEvent event) {
- hasBeenAdded = false;
- canvas.removeNotify();
- }
-
- /**
- * Computes the physical dimensions of the screen in space.
- */
- private void computePhysicalDimensions() {
- // Fix to Issue : 433 - JCanvas3D crashed when using jogl pipe.
- Rectangle screenRect = this.graphicsConfig.getBounds();
- int screenWidth = (int) screenRect.getWidth();
- int screenHeight = (int) screenRect.getHeight();
- canvas.getScreen3D().setSize(screenWidth, screenHeight);
- canvas.getScreen3D()
- .setPhysicalScreenWidth(((double) screenWidth) * METERS_PER_PIXEL);
- canvas.getScreen3D()
- .setPhysicalScreenHeight(((double) screenHeight) * METERS_PER_PIXEL);
- }
-
- /**
- * Creates a heavyweight canvas and initializes it, or changes the
- * size of the current one if present. Current heavyweight canvas is
- * changed only if size is different from the actual one. No canvas is
- * created if this component has no parent, that is, was not added to a
- * container.
- *
- * @param width the width of the canvas to create.
- * @param height the height of the canvas to create.
- */
- void createCanvas(int width, int height) {
- if (getParent() == null) {
- return;
- }
-
- if (null != canvas) {
- // i had a canvas, i need to check if i really need to change it
- if ((width != canvas.getWidth()) || (height != canvas.getHeight())) {
- if ((null != canvas.getOffScreenBuffer()) &&
- (null != canvas.getOffScreenBuffer().getImage())) {
- canvas.getOffScreenBuffer().getImage().flush(); // flushing so that eventual resources are freed.
- }
- } else {
- return;
- }
- } else {
- // no canvas, i have to create it.
- canvas = new InternalCanvas3D(this.graphicsConfig, this);
- }
-
- createOffScreenBuffer(width, height); // whatever happened right above, i need to create the offscreen buffer.
- }
-
- /**
- * Creates an offscreen buffer to be attached to the heavyweight
- * buffer. Buffer is created 'byreference'
- *
- * @param width the width of the buffer.
- * @param height the height of the buffer.
- */
- private void createOffScreenBuffer(int width, int height) {
- computePhysicalDimensions();
-
- // this.canvas.setDoubleBufferEnable( false );
- java.awt.image.BufferedImage bImage = new java.awt.image.BufferedImage(width,
- height, java.awt.image.BufferedImage.TYPE_INT_ARGB);
- javax.media.j3d.ImageComponent2D image = new javax.media.j3d.ImageComponent2D(javax.media.j3d.ImageComponent2D.FORMAT_RGBA8,
- bImage, true, false );
- image.setCapability(image.ALLOW_IMAGE_READ);
- image.setCapability(image.ALLOW_IMAGE_WRITE);
-
- this.canvas.stopRenderer();
-
- // offscreenrendering might occur even if the renderer is stopped. For that reason, i'm waiting for an hypothetical offscreen render to finish before setting offscreen rendering.
- // Otherwise, rendering will stop with an exception.
- this.canvas.waitForOffScreenRendering();
-
- this.canvas.setOffScreenBuffer(image);
- this.canvas.startRenderer();
- }
-
- /**
- * Returns the offscreen heavyweight canvas of that lightweight
- * component.
- *
- * @return the heavyweight canvas that lies in the deepness of this
- * Component.
- */
- public Canvas3D getOffscreenCanvas3D() {
- if (null == this.canvas) {
- createCanvas(getWidth(), getHeight());
- }
-
- return this.canvas;
- }
-
- /**
- * Retrieves the resize mode for that component.
- *
- * @return the resize mode, which can be one of RESIZE_IMMEDIATELY or
- * RESIZE_DELAYED
- */
- public int getResizeMode() {
- return resizeMode;
- }
-
- /**
- * Retrieves the validation delay for that canvas, whatever the
- * resize mode is set to.
- *
- * @return the validation delay.
- */
- public int getResizeValidationDelay() {
- return resizeValidationDelay;
- }
-
- /**
- * Paints the result of the rendering. If the rendered buffer is
- * not useable (render thread being between [code]postRender()[/code] and
- * [code]postSwap()[/code]), it will wait for it to be ready. Otherwise it
- * will directly paint the previous buffer.
- *
- * @param g {@inheritDoc}
- */
- @Override
- public void paintComponent(java.awt.Graphics g) {
- super.paintComponent(g); //paint background
-
- // Wait for and display image if JCanvas3D was added to an ancestor
- if (hasBeenAdded) {
- if ((false == canvas.canvasCrashed) &&
- (true == canvas.isRendererRunning())) {
- // System.err.println("paintComponentWaitforSwap");
- canvas.waitForSwap();
-
- // System.err.println("wait is over");
- }
-
- if (null != canvas.bi) {
- // can eventually be null if the canvas did not send the result in the desired timeframe
- // for first render. In that case, we don't paint and keep the background as-is.
- g.drawImage(canvas.bi, 0, 0, getWidth(), getHeight(), null);
- }
- }
- }
-
- /**
- * Redirects event to canvas and to superclass.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processComponentKeyEvent(java.awt.event.KeyEvent e) {
- super.processComponentKeyEvent(e);
-
- Object src = e.getSource();
- e.setSource(canvas);
- canvas.processComponentEvent(e);
- e.setSource(src);
- }
-
- /**
- * Redirects event to canvas and to superclass.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processFocusEvent(java.awt.event.FocusEvent e) {
- super.processFocusEvent(e);
-
- Object src = e.getSource();
- e.setSource(canvas);
- canvas.processFocusEvent(e);
- e.setSource(src);
- }
-
- /**
- * Redirects event to canvas and to superclass.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processInputMethodEvent(java.awt.event.InputMethodEvent e) {
- super.processInputMethodEvent(e);
-
- Object src = e.getSource();
- e.setSource(canvas);
- canvas.processInputMethodEvent(e);
- e.setSource(src);
- }
-
- /**
- * Redirects event to canvas and to superclass.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processKeyEvent(java.awt.event.KeyEvent e) {
- super.processKeyEvent(e);
-
- Object src = e.getSource();
- e.setSource(canvas);
- canvas.processKeyEvent(e);
- e.setSource(src);
- }
-
- /**
- * Redirects event to canvas and to superclass.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processMouseEvent(java.awt.event.MouseEvent e) {
- super.processMouseEvent(e);
-
- Object src = e.getSource();
- e.setSource(canvas);
- canvas.processMouseEvent(e);
- e.setSource(src);
- }
-
- /**
- * Redirects event to canvas and to superclass.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processMouseMotionEvent(java.awt.event.MouseEvent e) {
- super.processMouseMotionEvent(e);
-
- Object src = e.getSource();
- e.setSource(canvas);
- canvas.processMouseMotionEvent(e);
- e.setSource(src);
- }
-
- /**
- * Redirects event to canvas and to superclass.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processMouseWheelEvent(java.awt.event.MouseWheelEvent e) {
- super.processMouseWheelEvent(e);
-
- Object src = e.getSource();
- e.setSource(canvas);
- canvas.processMouseWheelEvent(e);
- e.setSource(src);
- }
-
- /**
- * {@inheritDoc}
- *
- * @param x {@inheritDoc}
- * @param y {@inheritDoc}
- * @param width {@inheritDoc}
- * @param height {@inheritDoc}
- */
- @Override
- public void setBounds(int x, int y, int width, int height) {
- super.setBounds(x, y, width, height);
-
- if ((null == canvas) || (null == canvas.getOffScreenBuffer()) ||
- (JCanvas3D.RESIZE_IMMEDIATELY == getResizeMode())) //whatever the resize mode, i create on first setbounds(). (not doing so would create a deadlock in DELAYED mode when trying to do the first paint
- {
- createCanvas(width, height);
- } else if ((JCanvas3D.RESIZE_DELAYED == getResizeMode()) &&
- ((null != canvas.getParent()) &&
- (true == canvas.getParent().isVisible()))) {
- if ((null == canvas.resizeThread) ||
- (false == canvas.resizeThread.isAlive())) {
- canvas.resizeThread = new ResizeThread(width, height,
- getResizeValidationDelay(), this);
- canvas.resizeThread.start();
- } else {
- canvas.resizeThread.setWidth(width);
- canvas.resizeThread.setHeight(height);
- }
- }
- }
-
- /**
- * Sets resize mode to be used on this component. Resize mode
- * permits to have smoother canvas resizes. The time taken by a canvas to
- * be resized can be pretty long: renderer has to stop, current render has
- * to end, everything has to be initialized again, and after all that has
- * been done, renderer is started again, then the image is displayed once
- * rendered. Resize mode uses a timer to make those steps only after the
- * last refresh request occured. 'Latest refresh' is determined by the
- * amount of time between now and the last time you asked for a size
- * change. If that time expires, a real resize is done. In between, the
- * same size is rendered, but the drawn image is scaled down/up. This has
- * some drawbacks, as the image can appear blocked, imprecise, distorted,
- * incomplete for that while, but most of the time only some of the
- * drawbacks will be users will see nothing. Default delay is set to
- * 100ms, which is low enough for common human not to be able to really
- * see that the rendered image is scaled.
- *
- * @param resizeMode can be one of RESIZE_IMMEDIATELY or RESIZE_DELAYED
- * @see #RESIZE_IMMEDIATELY
- * @see #RESIZE_DELAYED
- */
- public void setResizeMode(int resizeMode) {
- this.resizeMode = resizeMode;
- }
-
- /**
- * Sets the validation delay for the component. The validation
- * delay is the maximum time allowed for the canvas resizing to occur
- * using rendered buffer scaling. Once that delay expired, the canvas is
- * resized at the lowest level possible, thus in the rendering pipeline.
- * Note: Changing this field is only useful if resize mode is set to
- * RESIZE_IMMEDIATELY or RESIZE_DELAYED
- *
- * @param resizeValidationDelay the delay before a real resize would occur.
- * @see #RESIZE_IMMEDIATELY
- * @see #RESIZE_DELAYED
- */
- public void setResizeValidationDelay(int resizeValidationDelay) {
- this.resizeValidationDelay = resizeValidationDelay;
- }
-
- /**
- * This class is the internal Canvas3D that is used and sent to
- * Java 3D. It is remote controlled through JCanvas3D and is modified to be
- * able to tell the lightweight component when refreshes are needed.
- */
- static class InternalCanvas3D extends Canvas3D
- implements AutoOffScreenCanvas3D {
-
- // These two constants define the maximum amount of time
- // to wait for the readback of the off-screen buffer to complete.
- // The total time is MAX_WAIT_LOOPS * MAX_WAIT_TIME msec.
- private static final int MAX_WAIT_LOOPS = 5;
- private static final long MAX_WAIT_TIME = 10;
-
- /**
- * the bufferedImage that will be displayed as the result
- * of the computations.
- */
- BufferedImage bi = null;
-
- /**
- * This is the lightweight canvas that is linked to that
- * offscreen canvas.
- */
- JCanvas3D lwCanvas;
-
- /**
- * If delayed resizing is selected, a thread handling
- * resising will be started.
- */
- ResizeThread resizeThread;
-
- /**
- * flag used to sort a call to addnotify() from user and
- * from the lightweight component. Lightweight component calls
- * addNotify() so that the rendering begins and uses normal routines,
- * but this is a method that user must not call.
- */
- boolean addNotifyFlag;
-
- /**
- * flag indicating that the canvas crashed in a way or an
- * other, making swing to wait for the swap for much too long.
- */
- protected boolean canvasCrashed;
-
- /**
- * flag used to know when image can be painted or not. This
- * is to avoid component potentially displaying a buffer with an
- * unfinished blit. There is already a flag (imageReady) in Canvas3D
- * that does this but it can't be used because of restrictions. This
- * flag is not really fine grained, being set from end of postRender()
- * to end of postSwap()
- */
- boolean imageReadyBis;
-
- /**
- * Flag to indicate that the component is waiting for the
- * canvas to acomplish its swap, and that the component has to be
- * notified when done.
- */
- boolean waitingForSwap;
-
- /**
- * Creates a new instance of JCanvas3D. Resize mode is set
- * to RESIZE_IMMEDIATELY and validation delay to 100ms.
- *
- * @param graphicsConfiguration The graphics configuration to be used.
- * @param lwCanvas the lightweight canvas that is linked to that
- * heavyweight canvas.
- */
- public InternalCanvas3D(GraphicsConfiguration graphicsConfiguration,
- JCanvas3D lwCanvas) {
- super(graphicsConfiguration, true);
- this.lwCanvas = lwCanvas;
- imageReadyBis = false;
- waitingForSwap = false;
- addNotifyFlag = false;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addNotify() {
- if (false == addNotifyFlag) {
- throw new UnsupportedOperationException("CHANGE ME");
- } else {
- addNotifyFlag = false;
- super.addNotify();
- }
- }
-
- /**
- * Normally, returns the parent of that component. As the
- * canvas ought to never be added to any component, it has no parent.
- * Java 3D expects it to have a parent for some operations, so we in
- * fact cheat it by returning the parent of the lightweight component.
- *
- * @return the parent of the lightweight component, if any. Returns
- * null if the component is not created or if it has no
- * parent.
- */
- @Override
- public java.awt.Container getParent() {
- if (null == this.lwCanvas) {
- return null;
- }
-
- return this.lwCanvas.getParent();
- }
-
- /**
- * Blocks the retrieval of the render buffer.
- */
- @Override
- public void postRender() {
- imageReadyBis = false;
- }
-
- /**
- * Retrieves the buffer from canvas, if possible, and
- * calls/notifies component to be repainted, if necessary.
- */
- @Override
- synchronized public void postSwap() {
- if (true == isRendererRunning()) { // as weird as it can look, there can be postswaps without rendered running. (?!!) Anyway, in that case we should not refresh.
- bi = getOffScreenBuffer().getImage();
- imageReadyBis = true;
-
- if (false == waitingForSwap) {
- // System.err.println("repaint " + System.currentTimeMillis());
- this.lwCanvas.repaint();
- } else {
- notify();
- }
- } else {
- // System.err.println("SWAP WITHOUT RENDERER RUNNING");
- }
- }
-
- /**
- * Overriden so that the JComponent can access it.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processComponentEvent(java.awt.event.ComponentEvent e) {
- super.processComponentEvent(e);
- }
-
- /**
- * Overriden so that the JComponent can access it.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processFocusEvent(java.awt.event.FocusEvent e) {
- super.processFocusEvent(e);
- }
-
- /**
- * Overriden so that the JComponent can access it.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processInputMethodEvent(
- java.awt.event.InputMethodEvent e) {
- super.processInputMethodEvent(e);
- }
-
- /**
- * Overriden so that the JComponent can access it.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processKeyEvent(java.awt.event.KeyEvent e) {
- super.processKeyEvent(e);
- }
-
- /**
- * Overriden so that the JComponent can access it.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processMouseEvent(java.awt.event.MouseEvent e) {
- super.processMouseEvent(e);
- }
-
- /**
- * Overriden so that the JComponent can access it.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processMouseMotionEvent(java.awt.event.MouseEvent e) {
- super.processMouseMotionEvent(e);
- }
-
- /**
- * Overriden so that the JComponent can access it.
- *
- * @param e {@inheritDoc}
- */
- @Override
- protected void processMouseWheelEvent(java.awt.event.MouseWheelEvent e) {
- super.processMouseWheelEvent(e);
- }
-
- /**
- * If the Canvas is in a state that forbids the retrieving
- * of the buffer, wait a bit before trying again.
- */
- synchronized void waitForSwap() {
- int counter = MAX_WAIT_LOOPS;
- while (false == imageReadyBis) {
- try {
- waitingForSwap = true;
- wait(MAX_WAIT_TIME);
- waitingForSwap = false;
-
- if (!imageReadyBis && --counter <= 0) {
- //if i've waited too long for the canvas to be there, let us declare it crashed.
- //System.err.println("CANVAS CRASHED!!!");
- canvasCrashed = true;
- return;
- }
- } catch (InterruptedException ex) {
- System.err.println(ex);
- }
- }
- }
-
- }
-
- /**
- * This Runnable is the class used when the canvas has to be
- * resized.
- */
- static class ResizeSwingRunnable implements Runnable {
- /** The component that is displaying the canvas */
- JCanvas3D canvas;
-
- /** latest height that was requested */
- int height;
-
- /** latest width that was requested */
- int width;
-
- /**
- * Creates a new ResizeSwingRunnable object.
- */
- private ResizeSwingRunnable() {
- }
-
- /**
- * Creates a new ResizeSwingRunnable object.
- *
- * @param canvas the canvas to check
- * @param width the width that is requested
- * @param height the height that is requested
- */
- public ResizeSwingRunnable(JCanvas3D canvas, int width, int height) {
- this.canvas = canvas;
- this.width = width;
- this.height = height;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void run() {
- canvas.createCanvas(width, height);
- }
- }
-
- /**
- * This Thread handles the resizing changes and handles the timer
- * up to the moment when the resizing has to really occur.
- */
- static class ResizeThread extends Thread {
- //TODO: refactor so that it can handle a list of canvases, delays and start delay date, and change to a singleton. Actually, each JCanvas3D that would have to resize would spawn its own thread, which ought to be seen as "a bad thing"
- /** the canvas that has to be checked */
- JCanvas3D canvas;
-
- /** A flag indicating that since last check, size got changed again and the delay has to be reset */
- boolean sizeChanged;
-
- /** the delay that has to occur between last size change and real resize */
- int delay;
-
- /** latest height that was requested */
- int height;
-
- /** latest width that was requested */
- int width;
-
- /**
- * Creates a new ResizeThread object.
- */
- private ResizeThread() {
- }
-
- /**
- * Creates a new ResizeThread object.
- *
- * @param width initial width change
- * @param height initial height change
- * @param delay delay to be used
- * @param canvas the canvas that has to be checked
- */
- public ResizeThread(int width, int height, int delay, JCanvas3D canvas) {
- this.width = width;
- this.height = height;
- this.delay = delay;
- this.sizeChanged = true;
- this.canvas = canvas;
- }
-
- /**
- * returns the latest height that is being requested for change
- *
- * @return latest height requested
- */
- public int getHeight() {
- return height;
- }
-
- /**
- * returns the latest width that is being requested for change
- *
- * @return latest width requested
- */
- public int getWidth() {
- return width;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void run() {
- try {
- while (true == sizeChanged) // the double loop is made so that if a change of size arrives while the canvas is already resizing, the same thread can keep up with subsequent resizes.
- { // the effect of the double loop is to simplify some subtle race conditions at higher level.
-
- while (true == sizeChanged) {
- sizeChanged = false;
- Thread.sleep(delay); // while the thread sleeps, value can change. if value changes, flag will be true, and i'll have to wait again. if size does not change during the sleep, thread will quit and size will change.
- //TODO: should i force a resize after a definite delay occured, so it does not stay zoomed too long ?
- }
-
- try {
- EventQueue.invokeAndWait(new ResizeSwingRunnable(
- canvas, width, height));
- } catch (InterruptedException ie) {
- } catch (InvocationTargetException ite) {
- }
- }
- } catch (InterruptedException ie) {
- //if i get interrupted, this is not important, i'll quit method.
- }
- }
-
- /**
- * sets height. this has the effect of resetting the timeout.
- *
- * @param height the new height.
- *
- * @throws RuntimeException DOCUMENT ME!
- */
- public void setHeight(int height) {
- if (isAlive()) {
- this.height = height;
- sizeChanged = true;
- } else {
- throw new RuntimeException(
- "Resizing order arrived to a dead resizing thread. Spawn a new one.");
- }
- }
-
- /**
- * Sets width. This has the effect of resetting the timeout.
- *
- * @param width the new width.
- *
- * @throws RuntimeException DOCUMENT ME!
- */
- public void setWidth(int width) {
- if (isAlive()) {
- this.width = width;
- sizeChanged = true;
- } else {
- throw new RuntimeException(
- "Resizing order arrived to a dead resizing thread. Spawn a new one.");
- }
- }
- }
-}
diff --git a/src/classes/share/com/sun/j3d/exp/swing/impl/AutoOffScreenCanvas3D.java b/src/classes/share/com/sun/j3d/exp/swing/impl/AutoOffScreenCanvas3D.java
deleted file mode 100644
index 140de33..0000000
--- a/src/classes/share/com/sun/j3d/exp/swing/impl/AutoOffScreenCanvas3D.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.exp.swing.impl;
-
-/**
- * Tagging interface for Java 3D off-screen Canvas3D objects that are
- * automatically rendered. This is used internally by the JCanvas3D
- * implementation.
- * dst.length
- * bytes from
- * the buffer to the destination array and increments the
- * buffer's position by dst.length
.
- */
- public ByteBufferWrapper get(byte[] dst) {
- buffer.get(dst);
- return this;
- }
-
- /**
- * Bulk get method. Transfers length bytes
- * from the buffer starting at position offset into
- * the destination array.
- */
- public ByteBufferWrapper get(byte[] dst, int offset, int length) {
- buffer.get(dst, offset, length);
- return this;
- }
-
- /**
- * Returns the byte order of this buffer.
- */
- public ByteOrder order() {
- return buffer.order();
- }
-
- /**
- * Modifies this buffer's byte order.
- */
- public ByteBufferWrapper order(ByteOrder bo)
- {
- buffer.order( bo );
- return this;
- }
-
- /**
- * Creates a view of this ByteBufferWrapper as a
- * FloatBufferWrapper. Uses the correct
- */
- public FloatBufferWrapper asFloatBuffer() {
- return new FloatBufferWrapper( buffer.asFloatBuffer() );
- }
-
- /**
- * Creates a view of this ByteBufferWrapper as a
- * DoubleBufferWrapper.
- */
- public DoubleBufferWrapper asDoubleBuffer() {
- return new DoubleBufferWrapper( buffer.asDoubleBuffer() );
- }
-
- /**
- * Bulk put method. Transfers src.length
- * bytes into the buffer at the current position.
- */
- public ByteBufferWrapper put(byte[] src) {
- buffer.put(src);
- return this;
- }
-
- /**
- * Creates and returns a J3DBuffer object containing the
- * buffer in this ByteBufferWrapper object.
- */
- public J3DBuffer getJ3DBuffer() {
- return new J3DBuffer( buffer );
- }
-}
diff --git a/src/classes/share/com/sun/j3d/internal/Distance.java b/src/classes/share/com/sun/j3d/internal/Distance.java
deleted file mode 100644
index bb60d31..0000000
--- a/src/classes/share/com/sun/j3d/internal/Distance.java
+++ /dev/null
@@ -1,1092 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// --------------------------------------------------
-//
-// Distance routines, ported from:
-//
-// Magic Software, Inc.
-// http://www.magic-software.com
-// http://www.wild-magic.com
-// Copyright (c) 2004. All Rights Reserved
-//
-// The Wild Magic Library (WML) source code is supplied under the terms of
-// the license agreement http://www.magic-software.com/License/WildMagic.pdf
-// and may not be copied or disclosed except in accordance with the terms of
-// that agreement.
-//
-// --------------------------------------------------
-
-package com.sun.j3d.internal;
-
-import javax.vecmath.Point3d;
-import javax.vecmath.Vector3d;
-
-/**
- * Utility class used to calculate distance. Contains static methods
- * used by picking method to determine intersections.
- */
-
-public class Distance {
- /* Threshold factor to determine if two lines are parallel */
- static final double FUZZ = 1E-5;
-
- /* Utility method, for easy switch between distance and squared distance */
- private static final double DIST (double in) {
- // return Math.sqrt (Math.abs (in));
- return Math.abs (in);
- }
-
- /**
- * Minimum ray to segment distance.
- *
- * @param rayorig Origin of the ray
- * @param raydir Direction of the ray
- * @param segstart Segment start point
- * @param segend Segment end point
- * @return the square of the minimum distance from the ray to the segment
- */
- static public double rayToSegment (Point3d rayorig,
- Vector3d raydir,
- Point3d segstart,
- Point3d segend) {
- return rayToSegment (rayorig, raydir, segstart, segend, null, null, null);
- }
-
- /**
- * Minimum ray to segment distance. Returns the square of the distance.
- *
- * @param rayorig Origin of the ray
- *
- * @param raydir Direction of the ray
- *
- * @param segstart Segment start point
- *
- * @param segend Segment end point
- *
- * @param rayint If non-null, will be filled with the coordinates of
- * the point corresponding to the minimum distance on the ray.
- *
- * @param segint If non-null, will be filled with the coordinates of
- * the point corresponding to the minimum distance on the segment.
- *
- * @param param An array of two doubles, will be filled with the
- * parametric factors used to find the point of shortest distance on
- * each primitive (ray = O +sD, with O=origin and
- * D=direction). param[0] will contain the parameter for the ray,
- * and param[1] the parameter for the segment.
- *
- * @return the square of the minimum distance from the ray to the
- * segment
- */
- static public double rayToSegment (Point3d rayorig,
- Vector3d raydir,
- Point3d segstart,
- Point3d segend,
- Point3d rayint,
- Point3d segint,
- double[] param) {
- double s, t;
-
- Vector3d diff = new Vector3d();
- diff.sub (rayorig,segstart);
- Vector3d segdir = new Vector3d();
- segdir.sub (segend, segstart);
- /*
- System.out.println (rayorig + "\n" + raydir + "\n" + segstart + "\n" +
- segdir);
- */
- double A = raydir.dot (raydir);//Dot(ray.m,ray.m);
- double B = -raydir.dot (segdir);//-Dot(ray.m,seg.m);
- double C = segdir.dot (segdir);//Dot(seg.m,seg.m);
- double D = raydir.dot (diff);//Dot(ray.m,diff);
- double E; // -Dot(seg.m,diff), defer until needed
- double F = diff.dot (diff);//Dot(diff,diff);
- double det = Math.abs(A*C-B*B); // A*C-B*B = |Cross(M0,M1)|^2 >= 0
-
- double tmp;
-
- if (det >= FUZZ) {
- // ray and segment are not parallel
- E = -segdir.dot (diff);//-Dot(seg.m,diff);
- s = B*E-C*D;
- t = B*D-A*E;
-
- if (s >= 0) {
- if (t >= 0) {
- if (t <= det) { // region 0
- // minimum at interior points of ray and segment
- double invDet = 1.0f/det;
- s *= invDet;
- t *= invDet;
- if (rayint!=null) rayint.scaleAdd (s, raydir, rayorig);
- if (segint!=null) segint.scaleAdd (t, segdir, segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(s*(A*s+B*t+2*D)+t*(B*s+C*t+2*E)+F);
- }
- else { // region 1
-
- t = 1;
- if (D >= 0) {
- s = 0;
- if (rayint!=null) rayint.set (rayorig);
- if (segint!=null) segint.set (segend);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(C+2*E+F);
- }
- else {
- s = -D/A;
- if (rayint!=null) rayint.scaleAdd (s, raydir, rayorig);
- if (segint!=null) segint.set (segend);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST((D+2*B)*s+C+2*E+F);
- }
- }
- }
- else { // region 5
- t = 0;
- if (D >= 0) {
- s = 0;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.set (segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else {
- s = -D/A;
- if (rayint != null) rayint.scaleAdd (s, raydir, rayorig);
- if (segint != null) segint.set (segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- }
- }
- else {
- if (t <= 0) { // region 4
- if (D < 0) {
- s = -D/A;
- t = 0;
- if (rayint != null) rayint.scaleAdd (s, raydir, rayorig);
- if (segint != null) segint.set (segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- else {
- s = 0;
- if (E >= 0) {
- t = 0;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.set (segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else if (-E >= C) {
- t = 1;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.set (segend);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(C+2*E+F);
- }
- else {
- t = -E/C;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.scaleAdd (t, segdir, segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(E*t+F);
- }
- }
- }
- else if (t <= det) { // region 3
- s = 0;
- if (E >= 0) {
- t = 0;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.set (segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else if (-E >= C) {
- t = 1;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.set (segend);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(C+2*E+F);
- }
- else {
- t = -E/C;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.scaleAdd (t, segdir, segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(E*t+F);
- }
- }
- else { // region 2
- tmp = B+D;
- if (tmp < 0) {
- s = -tmp/A;
- t = 1;
- if (rayint != null) rayint.scaleAdd (s, raydir, rayorig);
- if (segint != null) segint.set (segend);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(tmp*s+C+2*E+F);
- }
- else {
- s = 0;
- if (E >= 0) {
- t = 0;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.set (segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else if (-E >= C) {
- t = 1;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.set (segend);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(C+2*E+F);
- }
- else {
- t = -E/C;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.scaleAdd (t, segdir, segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(E*t+F);
- }
- }
- }
- }
- }
- else {
- // ray and segment are parallel
- if (B > 0) {
- // opposite direction vectors
- t = 0;
- if (D >= 0) {
- s = 0;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.set (segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else {
- s = -D/A;
- if (rayint != null) rayint.scaleAdd (s, raydir, rayorig);
- if (segint != null) segint.set (segstart);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- }
- else {
- // same direction vectors
- E = segdir.dot (diff);//-Dot(seg.m,diff);
- t = 1;
- tmp = B+D;
- if (tmp >= 0) {
- s = 0;
- if (rayint != null) rayint.set (rayorig);
- if (segint != null) segint.set (segend);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(C+2*E+F);
- }
- else {
- s = -tmp/A;
- if (rayint != null) rayint.scaleAdd (s, raydir, rayorig);
- if (segint != null) segint.set (segend);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(tmp*s+C+2*E+F);
- }
- }
- }
- }
-
- /**
- * Minimum ray to ray distance. Returns the square of the distance.
- *
- * @param ray0orig Origin of ray 0
- * @param ray0dir Direction of ray 0
- * @param ray1orig Origin of ray 1
- * @param ray1dir Direction of ray 1
- * @return the square of the minimum distance from the ray to the segment
- */
- static public double rayToRay (Point3d ray0orig,
- Vector3d ray0dir,
- Point3d ray1orig,
- Vector3d ray1dir) {
- return rayToRay (ray0orig, ray0dir, ray1orig, ray1dir, null, null, null);
- }
-
- /**
- * Minimum ray to ray distance. Returns the square of the distance.
- *
- * @param ray0orig Origin of ray 0
- *
- * @param ray0dir Direction of ray 0
- *
- * @param ray1orig Origin of ray 1
- *
- * @param ray1dir Direction of ray 1
- *
- * @param ray0int If non-null, will be filled with the coordinates
- * of the point corresponding to the minimum distance on ray 0.
- *
- * @param ray1int If non-null, will be filled with the coordinates
- * of the point corresponding to the minimum distance on ray 1.
- *
- * @param param An array of two doubles, will be filled with the
- * parametric factors used to find the point of shortest distance on
- * each primitive (ray = O +sD, with O=origin and
- * D=direction). param[0] will contain the parameter for ray0, and
- * param[1] the parameter for ray1.
- *
- * @return the square of the minimum distance from the ray to the segment
- */
- static public double rayToRay (Point3d ray0orig,
- Vector3d ray0dir,
- Point3d ray1orig,
- Vector3d ray1dir,
- Point3d ray0int,
- Point3d ray1int,
- double[] param) {
-
- double s, t;
-
- Vector3d diff = new Vector3d();
- diff.sub (ray0orig, ray1orig);
-
- double A = ray0dir.dot (ray0dir); //Dot(ray0.m,ray0.m);
- double B = -ray0dir.dot (ray1dir); //-Dot(ray0.m,ray1.m);
- double C = ray1dir.dot (ray1dir); //Dot(ray1.m,ray1.m);
- double D = ray0dir.dot (diff); //Dot(ray0.m,diff);
- double E; // -Dot(ray1.m,diff), defer until needed
- double F = diff.dot (diff); //Dot(diff,diff);
- double det = Math.abs(A*C-B*B); // A*C-B*B = |Cross(M0,M1)|^2 >= 0
- /*
- System.out.println (ray0orig + "\n" + ray0dir + "\n" +
- ray1orig + "\n" + ray1dir);
- System.out.println (A + " " + B + " " + C + " " + D + " " + F + " " + det);
- */
- if (det >= FUZZ) {
- // rays are not parallel
- E = -ray1dir.dot (diff); //-Dot(ray1.m,diff);
- s = B*E-C*D;
- t = B*D-A*E;
-
- if (s >= 0) {
- if (t >= 0) { // region 0 (interior)
- // minimum at two interior points of rays
- double invDet = 1.0f/det;
- s *= invDet;
- t *= invDet;
- if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig);
- if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(s*(A*s+B*t+2*D)+t*(B*s+C*t+2*E)+F);
- }
- else { // region 3 (side)
- t = 0;
- if (D >= 0) {
- s = 0;
- if (ray0int != null) ray0int.set (ray0orig);
- if (ray1int != null) ray1int.set (ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else {
- s = -D/A;
- if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig);
- if (ray1int != null) ray1int.set (ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- }
- }
- else {
- if (t >= 0) { // region 1 (side)
- s = 0;
- if (E >= 0) {
- t = 0;
- if (ray0int != null) ray0int.set (ray0orig);
- if (ray1int != null) ray1int.set (ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else {
- t = -E/C;
- if (ray0int != null) ray0int.set (ray0orig);
- if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(E*t+F);
- }
- }
- else { // region 2 (corner)
- if (D < 0) {
- s = -D/A;
- t = 0;
- if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig);
- if (ray1int != null) ray1int.set (ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- else {
- s = 0;
- if (E >= 0) {
- t = 0;
- if (ray0int != null) ray0int.set (ray0orig);
- if (ray1int != null) ray1int.set (ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else {
- t = -E/C;
- if (ray0int != null) ray0int.set (ray0orig);
- if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(E*t+F);
- }
- }
- }
- }
- }
- else {
- // rays are parallel
- if (B > 0) {
- // opposite direction vectors
- t = 0;
- if (D >= 0) {
- s = 0;
- if (ray0int != null) ray0int.set (ray0orig);
- if (ray1int != null) ray1int.set (ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else {
- s = -D/A;
- if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig);
- if (ray1int != null) ray1int.set (ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- }
- else {
- // same direction vectors
- if (D >= 0) {
- E = ray1dir.dot (diff); //-Dot(ray1.m,diff);
- s = 0;
- t = -E/C;
- if (ray0int != null) ray0int.set (ray0orig);
- if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(E*t+F);
- }
- else {
- s = -D/A;
- t = 0;
- if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig);
- if (ray1int != null) ray1int.set (ray1orig);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- }
- }
- }
-
- /**
- * Minimum pt to ray distance. Returns the square of the distance.
- * @param pt The point
- * @param rayorig Origin of the ray
- * @param raydir Direction of the ray
- * @return the square of the minimum distance between the point and the ray
- */
- static public double pointToRay (Point3d pt,
- Point3d rayorig,
- Vector3d raydir) {
- return pointToRay (pt, rayorig, raydir, null, null);
- }
-
- /**
- * Minimum pt to ray distance. Returns the square of the distance.
- *
- * @param pt The point
- *
- * @param rayorig Origin of the ray
- *
- * @param raydir Direction of the ray
- *
- * @param rayint If non-null, will be filled with the coordinates of
- * the point corresponding to the minimum distance on the ray.
- *
- * @param param An array of one double, will be filled with the
- * parametric factors used to find the point of shortest distance on
- * the ray (ray = O +sD, with O=origin and D=direction). param[0]
- * will contain the parameter for the ray.
- *
- * @return the square of the minimum distance between the point and the ray
- */
- static public double pointToRay (Point3d pt,
- Point3d rayorig,
- Vector3d raydir,
- Point3d rayint,
- double[] param) {
-
- double t;
-
- Vector3d diff = new Vector3d();
- diff.sub (pt, rayorig);
- t = raydir.dot (diff); //Dot(ray.m,diff);
-
- if (t <= 0.0) {
- t = 0.0; // behind start of ray
- if (rayint != null) rayint.set (rayorig);
- if (param != null) { param[0] = t; }
- } else {
- t /= raydir.dot (raydir); //Dot(ray.m,ray.m);
- diff.scaleAdd (-t, raydir, diff); // diff = diff - t*ray.m;
- if (rayint != null) rayint.scaleAdd (t, raydir, rayorig);
- if (param != null) { param[0] = t; }
- }
- return diff.dot(diff);
- }
-
- /**
- * Minimum pt to segment distance. Returns the square of the distance.
- */
- static public double pointToSegment (Point3d pt,
- Point3d segstart,
- Point3d segend) {
- return pointToSegment (pt, segstart, segend, null, null);
- }
-
- /**
- * Minimum pt to segment distance. Returns the square of the distance.
- */
- static public double pointToSegment (Point3d pt,
- Point3d segstart,
- Point3d segend,
- Point3d segint,
- double[] param) {
-
- double t;
- Vector3d segdir = new Vector3d ();
- segdir.sub (segend, segstart);
- Vector3d diff = new Vector3d();
- diff.sub (pt,segstart);
- t = segdir.dot (diff); //Dot(seg.m,diff);
-
- if (t <= 0.0) {
- t = 0.0f;
- if (segint != null) segint.set (segstart);
- if (param != null) { param[0] = t; }
- }
- else {
- double mDotm = segdir.dot (segdir); //Dot(seg.m,seg.m);
- if (t >= mDotm) {
- t = 1.0f;
- diff.sub (segdir);
- if (segint != null) segint.set (segend);
- if (param != null) { param[0] = t; }
- }
- else {
- t /= mDotm;
- diff.scaleAdd (-t, segdir, diff); //diff = diff - t*seg.m;
- if (segint != null) segint.scaleAdd (t, segdir, segstart);
- if (param != null) { param[0] = t; }
- }
- }
- return diff.dot(diff); //DIST(diff);
- }
-
-
- /**
- * Minimum segment to segment distance. Returns the square of the distance.
- * @param seg0start the start of segment 0
- * @param seg0end the end of segment 0
- * @param seg1start the start of segment 1
- * @param seg1end the end of segment 1
- * @return the square of the minimum distance from segment to segment
- */
- static public double segmentToSegment (Point3d seg0start,
- Point3d seg0end,
- Point3d seg1start,
- Point3d seg1end) {
- return segmentToSegment (seg0start, seg0end, seg1start, seg1end,
- null, null, null);
- }
-
- /**
- * Minimum segment to segment distance. Returns the square of the distance.
- *
- * @param seg0start the start of segment 0
- *
- * @param seg0end the end of segment 0
- *
- * @param seg1start the start of segment 1
- *
- * @param seg1end the end of segment 1
- *
- * @param seg0int If non-null, will be filled with the coordinates
- * of the point corresponding to the minimum distance on segment 0.
- *
- * @param seg1int If non-null, will be filled with the coordinates
- * of the point corresponding to the minimum distance on segment 1.
- *
- * @param param An array of two doubles, will be filled with the
- * parametric factors used to find the point of shortest distance on
- * each primitive (segment = O +sD, with O=origin and
- * D=direction). param[0] will contain the parameter for segment 0,
- * and param[1] the parameter for segment 1.
- *
- * @return the square of the minimum distance from segment to segment
- */
- static public double segmentToSegment (Point3d seg0start,
- Point3d seg0end,
- Point3d seg1start,
- Point3d seg1end,
- Point3d seg0int,
- Point3d seg1int,
- double[] param) {
- double s,t;
-
- Vector3d diff = new Vector3d();
- diff.sub (seg0start,seg1start);
-
- Vector3d seg0dir = new Vector3d();
- seg0dir.sub (seg0end, seg0start);
- Vector3d seg1dir = new Vector3d();
- seg1dir.sub (seg1end, seg1start);
-
- double A = seg0dir.dot (seg0dir); //Dot(seg0dir,seg0dir);
- double B = -seg0dir.dot (seg1dir); //-Dot(seg0dir,seg1dir);
- double C = seg1dir.dot (seg1dir); //Dot(seg1dir,seg1dir);
- double D = seg0dir.dot (diff); //Dot(seg0dir,diff);
- double E; // -Dot(seg1dir,diff), defer until needed
- double F = diff.dot (diff); //Dot(diff,diff);
- double det = Math.abs(A*C-B*B); // A*C-B*B = |Cross(M0,M1)|^2 >= 0
-
- double tmp;
-
- if (det >= FUZZ) {
- // line segments are not parallel
- E = -seg1dir.dot (diff); //-Dot(seg1dir,diff);
- s = B*E-C*D;
- t = B*D-A*E;
-
- if (s >= 0) {
- if (s <= det) {
- if (t >= 0) {
- if (t <= det) { // region 0 (interior)
- // minimum at two interior points of 3D lines
- double invDet = 1.0f/det;
- s *= invDet;
- t *= invDet;
- if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
- if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(s*(A*s+B*t+2*D)+t*(B*s+C*t+2*E)+F);
- }
- else { // region 3 (side)
- t = 1;
- tmp = B+D;
- if (tmp >= 0) {
- s = 0;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(C+2*E+F);
- }
- else if (-tmp >= A) {
- s = 1;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+C+F+2*(E+tmp));
- }
- else {
- s = -tmp/A;
- if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(tmp*s+C+2*E+F);
- }
- }
- }
- else { // region 7 (side)
- t = 0;
- if (D >= 0) {
- s = 0;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else if (-D >= A) {
- s = 1;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+2*D+F);
- }
- else {
- s = -D/A;
- if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- }
- }
- else {
- if (t >= 0) {
- if (t <= det) { // region 1 (side)
- s = 1;
- tmp = B+E;
- if (tmp >= 0) {
- t = 0;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+2*D+F);
- }
- else if (-tmp >= C) {
- t = 1;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+C+F+2*(D+tmp));
- }
- else {
- t = -tmp/C;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(tmp*t+A+2*D+F);
- }
- }
- else { // region 2 (corner)
- tmp = B+D;
- if (-tmp <= A) {
- t = 1;
- if (tmp >= 0) {
- s = 0;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(C+2*E+F);
- }
- else {
- s = -tmp/A;
- if (seg0int!=null) seg0int.scaleAdd (s, seg0dir, seg0start);
- if (seg1int!=null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(tmp*s+C+2*E+F);
- }
- }
- else {
- s = 1;
- tmp = B+E;
- if (tmp >= 0) {
- t = 0;
- if (seg0int!=null) seg0int.set (seg0end);
- if (seg1int!=null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+2*D+F);
- }
- else if (-tmp >= C) {
- t = 1;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+C+F+2*(D+tmp));
- }
- else {
- t = -tmp/C;
- if (seg0int!=null) seg0int.set (seg0end);
- if (seg1int!=null) seg1int.scaleAdd (t, seg1dir, seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(tmp*t+A+2*D+F);
- }
- }
- }
- }
- else { // region 8 (corner)
- if (-D < A) {
- t = 0;
- if (D >= 0) {
- s = 0;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else {
- s = -D/A;
- if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- }
- else {
- s = 1;
- tmp = B+E;
- if (tmp >= 0) {
- t = 0;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+2*D+F);
- }
- else if (-tmp >= C) {
- t = 1;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+C+F+2*(D+tmp));
- }
- else {
- t = -tmp/C;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(tmp*t+A+2*D+F);
- }
- }
- }
- }
- }
- else {
- if (t >= 0) {
- if (t <= det) { // region 5 (side)
- s = 0;
- if (E >= 0) {
- t = 0;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else if (-E >= C) {
- t = 1;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(C+2*E+F);
- }
- else {
- t = -E/C;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(E*t+F);
- }
- }
- else { // region 4 (corner)
- tmp = B+D;
- if (tmp < 0) {
- t = 1;
- if (-tmp >= A) {
- s = 1;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+C+F+2*(E+tmp));
- }
- else {
- s = -tmp/A;
- if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(tmp*s+C+2*E+F);
- }
- }
- else {
- s = 0;
- if (E >= 0) {
- t = 0;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else if (-E >= C) {
- t = 1;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(C+2*E+F);
- }
- else {
- t = -E/C;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(E*t+F);
- }
- }
- }
- }
- else { // region 6 (corner)
- if (D < 0) {
- t = 0;
- if (-D >= A) {
- s = 1;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+2*D+F);
- }
- else {
- s = -D/A;
- if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- }
- else {
- s = 0;
- if (E >= 0) {
- t = 0;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else if (-E >= C) {
- t = 1;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(C+2*E+F);
- }
- else {
- t = -E/C;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(E*t+F);
- }
- }
- }
- }
- }
- else {
- // line segments are parallel
- if (B > 0) {
- // direction vectors form an obtuse angle
- if (D >= 0) {
- s = 0;
- t = 0;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F);
- }
- else if (-D <= A) {
- s = -D/A;
- t = 0;
- if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- else {
- E = -seg1dir.dot (diff); //-Dot(seg1dir,diff);
- s = 1;
- tmp = A+D;
- if (-tmp >= B) {
- t = 1;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+C+F+2*(B+D+E));
- }
- else {
- t = -tmp/B;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+2*D+F+t*(C*t+2*(B+E)));
- }
- }
- }
- else {
- // direction vectors form an acute angle
- if (-D >= A) {
- s = 1;
- t = 0;
- if (seg0int != null) seg0int.set (seg0end);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(A+2*D+F);
- }
- else if (D <= 0) {
- s = -D/A;
- t = 0;
- if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
- if (seg1int != null) seg1int.set (seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(D*s+F);
- }
- else {
- E = -seg1dir.dot (diff); //-Dot(seg1dir,diff);
- s = 0;
- if (D >= -B) {
- t = 1;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.set (seg1end);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(C+2*E+F);
- }
- else {
- t = -D/B;
- if (seg0int != null) seg0int.set (seg0start);
- if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
- if (param != null) { param[0] = s; param[1] = t; }
- return DIST(F+t*(2*E+C*t));
- }
- }
- }
- }
- }
-}
-
-
-
-
diff --git a/src/classes/share/com/sun/j3d/internal/DoubleBufferWrapper.java b/src/classes/share/com/sun/j3d/internal/DoubleBufferWrapper.java
deleted file mode 100644
index 0ef14f0..0000000
--- a/src/classes/share/com/sun/j3d/internal/DoubleBufferWrapper.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.internal;
-
-import java.nio.DoubleBuffer;
-
-import javax.media.j3d.J3DBuffer;
-
-/**
- * NIO Buffers are new in Java 1.4 but we need to run on 1.3
- * as well, so this class was created to hide the NIO classes
- * from non-1.4 Java 3D users.
- *
- * dst.length
- * doubles from
- * the buffer to the destination array and increments the
- * buffer's position by dst.length
.
- */
- public DoubleBufferWrapper get(double[] dst) {
- buffer.get(dst);
- return this;
- }
-
- /**
- * Bulk get method. Transfers length doubles
- * from the buffer starting at position offset into
- * the destination array.
- */
- public DoubleBufferWrapper get(double[] dst, int offset, int length){
- buffer.get(dst, offset, length);
- return this;
- }
-
- /**
- * Bulk put method. Transfers src.length
- * doubles into the buffer at the current position.
- */
- public DoubleBufferWrapper put(double[] src) {
- buffer.put(src);
- return this;
- }
-
- /**
- * Creates and returns a J3DBuffer object containing the
- * buffer in this DoubleBufferWrapper object.
- */
- public J3DBuffer getJ3DBuffer() {
- return new J3DBuffer( buffer );
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/internal/FastVector.java b/src/classes/share/com/sun/j3d/internal/FastVector.java
deleted file mode 100644
index a9d168f..0000000
--- a/src/classes/share/com/sun/j3d/internal/FastVector.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.internal;
-
-/**
- * The FastVector object is a growable array of ints. It's much faster
- * than the Java Vector class because it isn't synchronized. This class
- * was created because it is needed in several places by graphics
- * utilities.
- */
-public class FastVector {
-
- private int data[];
- private int capacity;
- private int increment;
- private int size;
-
- /**
- * Add an element to the end of the array.
- */
- public void addElement(int element)
- {
- if (size >= capacity) {
- capacity += (increment == 0) ? capacity : increment;
- int newData[] = new int[capacity];
- System.arraycopy(data, 0, newData, 0, size);
- data = newData;
- }
- data[size++] = element;
- } // End of addElement
-
-
-
- /**
- * Get number of ints currently stored in the array;
- */
- public int getSize()
- {
- return size;
- } // End of getSize
-
-
-
- /**
- * Get access to array data
- */
- public int[] getData()
- {
- return data;
- } // End of getData
-
-
-
- /**
- * Constructor.
- * @param initialCapacity Number of ints the object can hold
- * without reallocating the array.
- * @param capacityIncrement Once the array has grown beyond
- * its capacity, how much larger the reallocated array should be.
- */
- public FastVector(int initialCapacity, int capacityIncrement)
- {
- data = new int[initialCapacity];
- capacity = initialCapacity;
- increment = capacityIncrement;
- size = 0;
- } // End of FastVector(int, int)
-
-
-
- /**
- * Constructor.
- * When the array runs out of space, its size is doubled.
- * @param initialCapacity Number of ints the object can hold
- * without reallocating the array.
- */
- public FastVector(int initialCapacity)
- {
- data = new int[initialCapacity];
- capacity = initialCapacity;
- increment = 0;
- size = 0;
- } // End of FastVector(int)
-
-
-
- /**
- * Constructor.
- * The array is constructed with initial capacity of one integer.
- * When the array runs out of space, its size is doubled.
- */
- public FastVector()
- {
- data = new int[1];
- capacity = 1;
- increment = 0;
- size = 0;
- } // End of FastVector()
-} // End of class FastVector
-
-// End of file FastVector.java
diff --git a/src/classes/share/com/sun/j3d/internal/FloatBufferWrapper.java b/src/classes/share/com/sun/j3d/internal/FloatBufferWrapper.java
deleted file mode 100644
index 6c7badf..0000000
--- a/src/classes/share/com/sun/j3d/internal/FloatBufferWrapper.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.internal;
-
-import java.nio.FloatBuffer;
-
-import javax.media.j3d.J3DBuffer;
-
-/**
- * NIO Buffers are new in Java 1.4 but we need to run on 1.3
- * as well, so this class was created to hide the NIO classes
- * from non-1.4 Java 3D users.
- *
- * dst.length
- * floats from
- * the buffer to the destination array and increments the
- * buffer's position by dst.length
.
- */
- public FloatBufferWrapper get(float[] dst) {
- buffer.get(dst);
- return this;
- }
-
- /**
- * Bulk get method. Transfers length floats
- * from the buffer starting at position offset into
- * the destination array.
- */
- public FloatBufferWrapper get(float[] dst, int offset, int length){
- buffer.get(dst, offset, length);
- return this;
- }
-
- /**
- * Bulk put method. Transfers src.length
- * floats into the buffer at the current position.
- */
- public FloatBufferWrapper put(float[] src) {
- buffer.put(src);
- return this;
- }
-
- /**
- * Creates and returns a J3DBuffer object containing the
- * buffer in this FloatBufferWrapper object.
- */
- public J3DBuffer getJ3DBuffer() {
- return new J3DBuffer( buffer );
- }
-}
diff --git a/src/classes/share/com/sun/j3d/internal/HashCodeUtil.java b/src/classes/share/com/sun/j3d/internal/HashCodeUtil.java
deleted file mode 100644
index bb59aae..0000000
--- a/src/classes/share/com/sun/j3d/internal/HashCodeUtil.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.internal;
-
-/**
- * Utility class used when computing the hash code for
- * objects containing float or double values. This fixes Issue 36.
- */
-public class HashCodeUtil {
- /**
- * Returns the representation of the specified floating-point
- * value according to the IEEE 754 floating-point "single format"
- * bit layout, after first mapping -0.0 to 0.0. This method is
- * identical to Float.floatToIntBits(float) except that an integer
- * value of 0 is returned for a floating-point value of
- * -0.0f. This is done for the purpose of computing a hash code
- * that satisfies the contract of hashCode() and equals(). The
- * equals() method in some Java 3D classes does a pair-wise
- * "==" test on each floating-point field in the class. Since
- * 0.0f == -0.0f returns true, we must also return the
- * same hash code for two objects, one of which has a field with a
- * value of -0.0f and the other of which has a cooresponding field
- * with a value of 0.0f.
- *
- * @param f an input floating-point number
- * @return the integer bits representing that floating-point
- * number, after first mapping -0.0f to 0.0f
- */
- public static int floatToIntBits(float f) {
- // Check for +0 or -0
- if (f == 0.0f) {
- return 0;
- }
- else {
- return Float.floatToIntBits(f);
- }
- }
-
- /**
- * Returns the representation of the specified floating-point
- * value according to the IEEE 754 floating-point "double format"
- * bit layout, after first mapping -0.0 to 0.0. This method is
- * identical to Double.doubleToLongBits(double) except that an
- * integer value of 0L is returned for a floating-point value of
- * -0.0. This is done for the purpose of computing a hash code
- * that satisfies the contract of hashCode() and equals(). The
- * equals() method in some Java 3D classes does a pair-wise
- * "==" test on each floating-point field in the class. Since
- * 0.0 == -0.0 returns true, we must also return the
- * same hash code for two objects, one of which has a field with a
- * value of -0.0 and the other of which has a cooresponding field
- * with a value of 0.0.
- *
- * @param d an input double precision floating-point number
- * @return the integer bits representing that floating-point
- * number, after first mapping -0.0f to 0.0f
- */
- public static long doubleToLongBits(double d) {
- // Check for +0 or -0
- if (d == 0.0) {
- return 0L;
- }
- else {
- return Double.doubleToLongBits(d);
- }
- }
-
-
- /**
- * Do not construct an instance of this class.
- */
- private HashCodeUtil() {
- }
-}
diff --git a/src/classes/share/com/sun/j3d/internal/J3dUtilsI18N.java b/src/classes/share/com/sun/j3d/internal/J3dUtilsI18N.java
deleted file mode 100644
index 32c052b..0000000
--- a/src/classes/share/com/sun/j3d/internal/J3dUtilsI18N.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.internal;
-
-import java.util.MissingResourceException;
-import java.util.ResourceBundle;
-
-
-public class J3dUtilsI18N {
- static public String getString(String key) {
- String s;
- try {
- s = ResourceBundle.getBundle("com.sun.j3d.ExceptionStrings").getString(key);
- }
- catch (MissingResourceException e) {
- System.err.println("J3dUtilsI18N: Error looking up: " + key);
- s = key;
- }
- return s;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/IncorrectFormatException.java b/src/classes/share/com/sun/j3d/loaders/IncorrectFormatException.java
deleted file mode 100644
index 6926e86..0000000
--- a/src/classes/share/com/sun/j3d/loaders/IncorrectFormatException.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders;
-
-
-/**
- * Exception used to indicate that a file of the incorrect
- * type was passed to a loader.
- */
-public class IncorrectFormatException extends RuntimeException {
-
- public IncorrectFormatException() {
- super();
- }
-
- public IncorrectFormatException(String s) {
- super(s);
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/loaders/Loader.java b/src/classes/share/com/sun/j3d/loaders/Loader.java
deleted file mode 100644
index a2634c7..0000000
--- a/src/classes/share/com/sun/j3d/loaders/Loader.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders;
-
-import java.io.FileNotFoundException;
-import java.io.Reader;
-import java.net.URL;
-
-/**
- * The Loader interface is used to specify the location
- * and elements of a file format to load.
- * The interface is used to give loaders of various
- * file formats a common public interface. Ideally
- * the Scene interface will be implemented to give
- * the user a consistent interface to extract the
- * data.
- *
- * @see com.sun.j3d.loaders.Scene
- */
-public interface Loader {
-
- // These are the values to be used in constructing the
- // load flags for the loader. Users should OR the selected
- // values together to construct an aggregate flag integer
- // (see the setFlags() method). Users wishing to load all
- // data in a file should use the LOAD_ALL specifier.
-
- /** This flag enables the loading of light objects into the scene.*/
- public static final int LOAD_LIGHT_NODES = 1;
-
- /** This flag enables the loading of fog objects into the scene.*/
- public static final int LOAD_FOG_NODES = 2;
-
- /** This flag enables the loading of background objects into the scene.*/
- public static final int LOAD_BACKGROUND_NODES = 4;
-
- /** This flag enables the loading of behaviors into the scene.*/
- public static final int LOAD_BEHAVIOR_NODES = 8;
-
- /** This flag enables the loading of view (camera) objects into
- * the scene.*/
- public static final int LOAD_VIEW_GROUPS = 16;
-
- /** This flag enables the loading of sound objects into the scene.*/
- public static final int LOAD_SOUND_NODES = 32;
-
- /** This flag enables the loading of all objects into the scene.*/
- public static final int LOAD_ALL = 0xffffffff;
-
-
- // Loading methods
-
- /**
- * This method loads the named file and returns the Scene
- * containing the scene. Any data files referenced by this
- * file should be located in the same place as the named file;
- * otherwise users should specify an alternate base path with
- * the setBasePath(String) method.
- */
- public Scene load(String fileName) throws FileNotFoundException,
- IncorrectFormatException, ParsingErrorException;
-
- /**
- * This method loads the named file and returns the Scene
- * containing the scene. Any data files referenced by the Reader
- * should be located in the same place as the named file; otherwise,
- * users should specify an alternate base path with the setBaseUrl(URL)
- * method.
- */
- public Scene load(URL url) throws FileNotFoundException,
- IncorrectFormatException, ParsingErrorException;
-
- /**
- * This method loads the Reader and returns the Scene
- * containing the scene. Any data files referenced by the Reader should
- * be located in the user's current working directory.
- */
- public Scene load(Reader reader)
- throws FileNotFoundException, IncorrectFormatException,
- ParsingErrorException;
-
-
- // Variable get/set methods
-
- /**
- * This method sets the base URL name for data files associated with
- * the file passed into the load(URL) method.
- * The basePath should be null by default, which is an indicator
- * to the loader that it should look for any associated files starting
- * from the same directory as the file passed into the load(URL) method.
- */
- public void setBaseUrl(URL url);
-
- /**
- * This method sets the base path name for data files associated with
- * the file passed into the load(String) method.
- * The basePath should be null by default, which is an indicator
- * to the loader that it should look for any associated files starting
- * from the same directory as the file passed into the load(String)
- * method.
- */
- public void setBasePath(String pathName);
-
- /**
- * Returns the current base URL setting. By default this is null,
- * implying the loader should look for associated files starting
- * from the same directory as the file passed into the load(URL) method.
- */
- public URL getBaseUrl();
-
- /**
- * Returns the current base path setting. By default this is null,
- * implying the loader should look for associated files starting
- * from the same directory as the file passed into the load(String)
- * method.
- */
- public String getBasePath();
-
- /**
- * This method sets the load flags for the file. The flags should
- * equal 0 by default (which tells the loader to only load geometry).
- * To enable the loading of any particular scene elements, pass
- * in a logical OR of the LOAD values specified above.
- */
- public void setFlags(int flags);
-
- /**
- * Returns the current loading flags setting.
- */
- public int getFlags();
-}
-
-
-
diff --git a/src/classes/share/com/sun/j3d/loaders/LoaderBase.java b/src/classes/share/com/sun/j3d/loaders/LoaderBase.java
deleted file mode 100644
index ec12cb4..0000000
--- a/src/classes/share/com/sun/j3d/loaders/LoaderBase.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders;
-
-import java.net.URL;
-
-/**
- * This class implements the Loader interface. To use
- * a file loader would extend this class.
- */
-public abstract class LoaderBase implements Loader {
-
- /** Stores the types of objects that the user wishes to load.*/
- protected int loadFlags = 0;
-
- /** Stores the baseUrl for data files associated with the URL
- * passed into load(URL).*/
- protected URL baseUrl = null;
-
- /** Stores the basePath for data files associated with the file
- * passed into load(String).*/
- protected String basePath = null;
-
- // Constructors
-
- /**
- * Constructs a Loader with default values for all variables.
- */
- public LoaderBase() {
- }
-
- /**
- * Constructs a Loader with the specified flags word.
- */
- public LoaderBase(int flags) {
- loadFlags = flags;
- }
-
-
- // Variable get/set methods
-
- /**
- * This method sets the base URL name for data files associated with
- * the file. The baseUrl should be null by default, which is an indicator
- * to the loader that it should look for any associated files starting
- * from the same place as the URL passed into the load(URL) method.
- * Note: Users of setBaseUrl() would then use load(URL)
- * as opposed to load(String).
- */
- @Override
- public void setBaseUrl(URL url) {
- baseUrl = url;
- }
-
- /**
- * This method sets the base path name for data files associated with
- * the file. The basePath should be null by default, which is an indicator
- * to the loader that it should look for any associated files starting
- * from the same directory as the file passed into the load(String)
- * method.
- * Note: Users of setBasePath() would then use load(String)
- * as opposed to load(URL).
- */
- @Override
- public void setBasePath(String pathName) {
- basePath = pathName;
- }
-
- /**
- * Returns the current base URL setting.
- */
- @Override
- public URL getBaseUrl() {
- return baseUrl;
- }
-
- /**
- * Returns the current base path setting.
- */
- @Override
- public String getBasePath() {
- return basePath;
- }
-
- /**
- * This method sets the load flags for the file. The flags should
- * equal 0 by default (which tells the loader to only load geometry).
- */
- @Override
- public void setFlags(int flags) {
- loadFlags = flags;
- }
-
- /**
- * Returns the current loading flags setting.
- */
- @Override
- public int getFlags() {
- return loadFlags;
- }
-
-}
-
-
-
-
-
-
-
-
diff --git a/src/classes/share/com/sun/j3d/loaders/ParsingErrorException.java b/src/classes/share/com/sun/j3d/loaders/ParsingErrorException.java
deleted file mode 100644
index f046b58..0000000
--- a/src/classes/share/com/sun/j3d/loaders/ParsingErrorException.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders;
-
-
-/**
- * Exception used to indicate that the loader encountered
- * a problem parsing the specified file.
- */
-public class ParsingErrorException extends RuntimeException {
-
- public ParsingErrorException() {
- super();
- }
-
- public ParsingErrorException(String s) {
- super(s);
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/loaders/Scene.java b/src/classes/share/com/sun/j3d/loaders/Scene.java
deleted file mode 100644
index 901a9ca..0000000
--- a/src/classes/share/com/sun/j3d/loaders/Scene.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders;
-
-import java.util.Hashtable;
-
-import javax.media.j3d.Background;
-import javax.media.j3d.Behavior;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Fog;
-import javax.media.j3d.Light;
-import javax.media.j3d.Sound;
-import javax.media.j3d.TransformGroup;
-
-
-/**
- * The Scene interface is a set of methods used to extract
- * Java 3D scene graph information from a file loader utility.
- * The interface is used to give loaders of various
- * file formats a common public interface.
- */
-public interface Scene {
-
-
- /**
- * This method returns the BranchGroup containing the overall
- * scene loaded by the loader. All enabled items will be loaded
- * into this scene except for Behaviors (the Behavior group must be
- * retrieved separately so that users can choose whether and when
- * to activate behaviors).
- */
- public BranchGroup getSceneGroup();
-
- /**
- * This method returns an array of all View Groups defined in the file.
- * Each View Group is a TransformGroup that is already placed within
- * the scene that is returned in the getSceneGroup() call. This
- * TransformGroup holds the position/orientation of the view
- * as defined by the file. A user might request these references to
- * the groups in order to look at the data stored there or
- * to place ViewPlatforms within these groups and allow the
- * View to activate these ViewPlatforms so that the user would
- * see the scene from the viewpoints defined in the file.
- */
- public TransformGroup[] getViewGroups();
-
- /**
- * This method returns an array of floats with the horizontal field
- * of view. The entries in the array will correspond to those in the
- * array returned by the method getViewGroups. The entries from these
- * two arrays together provide all the information needed to recreate
- * the viewing parameters associated with a scene graph.
- */
- public float[] getHorizontalFOVs();
-
- /**
- * This method returns an array of all Lights defined in the file.
- * If no lights are defined, null is returned.
- */
- public Light[] getLightNodes();
-
- /**
- * This method returns a Hashtable which contains a list of all named
- * objects in the file and their associated scene graph objects. The
- * naming scheme for file objects is file-type dependent, but may include
- * such names as the DEF names of Vrml or filenames of objects (as
- * in Lightwave 3D). If no named objects are defined, null is returned.
- */
- public Hashtable getNamedObjects();
-
- /**
- * This method returns an array of all Background nodes defined in the
- * file. IF no Background nodes are defined, null is returned.
- */
- public Background[] getBackgroundNodes();
-
- /**
- * This method returns an array of all Fog nodes defined in the
- * file. If no fog nodes are defined, null is returned.
- */
- public Fog[] getFogNodes();
-
- /**
- * This method returns an array of all the behavior nodes
- * in the scene. If no Behavior nodes are defined, null is returned.
- */
- public Behavior[] getBehaviorNodes();
-
- /**
- * This method returns an array of all of the Sound nodes defined
- * in the file. If no Sound nodes are defined, null is returned.
- */
- public Sound[] getSoundNodes();
-
- /**
- * This method returns the text description of the file. If no
- * such description exists, this method should return null.
- */
- public String getDescription();
-
-}
-
-
-
-
-
diff --git a/src/classes/share/com/sun/j3d/loaders/SceneBase.java b/src/classes/share/com/sun/j3d/loaders/SceneBase.java
deleted file mode 100644
index bb3794d..0000000
--- a/src/classes/share/com/sun/j3d/loaders/SceneBase.java
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders;
-
-import java.util.Hashtable;
-import java.util.Vector;
-
-import javax.media.j3d.Background;
-import javax.media.j3d.Behavior;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Fog;
-import javax.media.j3d.Light;
-import javax.media.j3d.Sound;
-import javax.media.j3d.TransformGroup;
-
-
-/**
- * This class implements the Scene interface and extends it to incorporate
- * utilities that could be used by loaders. There should be little need
- * for future loaders to subclass this, or to implement Scene directly,
- * as the functionality of a SceneBase is fairly straightforward. This
- * class is responsible for both the storage and retrieval of data from
- * the Scene. The storage methods (used only by Loader writers) are all
- * of the add* routines. The retrieval methods (used primarily by Loader
- * users) are all of the get* routines.
- */
-public class SceneBase implements Scene {
-
- BranchGroup sceneGroup = null;
- BranchGroup behaviorGroup = null;
- Hashtable namedObjects = new Hashtable();
- String description = null;
-
- Vector viewVector = new Vector();
- Vector hfovVector = new Vector();
- Vector behaviorVector = new Vector();
- Vector lightVector = new Vector();
- Vector fogVector = new Vector();
- Vector backgroundVector = new Vector();
- Vector soundVector = new Vector();
-
- // Add methods
-
- /**
- * Sets the sceneGroup to be the group that is passed in.
- */
- public void setSceneGroup(BranchGroup scene) {
- sceneGroup = scene;
- }
-
- /**
- * Adds the given group to the list of view groups.
- */
- public void addViewGroup(TransformGroup tg) {
- viewVector.addElement(tg);
- }
-
- /**
- * Adds the given field of view value to the list of field of view values.
- */
- public void addHorizontalFOV(float hfov) {
- hfovVector.addElement(new Float(hfov));
- }
-
- /**
- * Adds the given behavior to a list of behaviors
- */
- public void addBehaviorNode(Behavior b) {
- behaviorVector.addElement(b);
- }
-
- /**
- * Adds the given Light node to the list of lights.
- */
- public void addLightNode(Light light) {
- lightVector.addElement(light);
- }
-
- /**
- * Adds the given Background node to the list of backgrounds.
- */
- public void addBackgroundNode(Background background) {
- backgroundVector.addElement(background);
- }
-
- /**
- * Adds the given Sound node to the list of sounds.
- */
- public void addSoundNode(Sound sound) {
- soundVector.addElement(sound);
- }
-
- /**
- * Adds the given Fog node to the list of fog nodes.
- */
- public void addFogNode(Fog fog) {
- fogVector.addElement(fog);
- }
-
- /**
- * Sets the text description of the scene to the passed in String.
- */
- public void addDescription(String descriptionString) {
- description = descriptionString;
- }
-
- /**
- * Adds the given String/Object pair to the table of named objects.
- */
- public void addNamedObject(String name, Object object) {
- if (namedObjects.get(name) == null)
- namedObjects.put(name, object);
- else {
- // key already exists - append a unique integer to end of name
- int nameIndex = 1;
- boolean done = false;
- while (!done) {
- // Iterate starting from "[1]" until we find a unique key
- String tempName = name + "[" + nameIndex + "]";
- if (namedObjects.get(tempName) == null) {
- namedObjects.put(tempName, object);
- done = true;
- }
- nameIndex++;
- }
- }
- }
-
- /**
- * This method returns the BranchGroup containing the overall
- * scene loaded by the loader.
- */
- @Override
- public BranchGroup getSceneGroup() {
- return sceneGroup;
- }
-
-
- /**
- * This method returns an array of all View Groups defined in the file.
- * A View Group is defined as a TransformGroup which contains a
- * ViewPlatform. The TransformGroup holds the position/orientation
- * information for the given ViewPlatform and the ViewPlatform
- * holds an view-specific information, such as Field of View.
- */
- @Override
- public TransformGroup[] getViewGroups() {
- if (viewVector.isEmpty())
- return null;
- TransformGroup[] viewGroups = new TransformGroup[viewVector.size()];
- viewVector.copyInto(viewGroups);
- return viewGroups;
- }
-
- /**
- * This method returns an array of floats that contains the horizontal
- * field of view values for each corresponding entry in the array of
- * view groups returned by the method getViewGroups.
- */
- @Override
- public float[] getHorizontalFOVs() {
- if (hfovVector.isEmpty())
- return null;
-
- int arraySize = hfovVector.size();
- float[] hfovs = new float[arraySize];
- Float[] tmpFovs = new Float[hfovVector.size()];
- hfovVector.copyInto(tmpFovs);
-
- // copy to array of floats and delete Floats
- for (int i=0; i
- * Rather than describe in detail how the file is parsed for each method,
- * I advise the user of this code to understand the lw3d file format
- * specs, which are pretty clear.
- */
-
-class LwoParser extends ParserObject {
-
- LWOBFileReader theReader;
- int currLength;
- float coordsArray[];
- float normalCoordsArray[];
- int facetIndicesArray[];
- int facetSizesArray[];
- int normalIndicesArray[];
- int red = 255, green = 255, blue = 255;
- float diffuse = 0.0f, specular = 0.0f, transparency = 0.0f, luminosity = 0.0f;
- int gloss = 128;
- Vector surfNameList = null;
- Vector surfaceList = new Vector(200);
- Vector shapeList = new Vector(200);
-
- /**
- * Constructor: Creates file reader and calls parseFile() to actually
- * read the file and grab the data
- */
- LwoParser(String fileName, int debugVals)
- throws FileNotFoundException {
-
- super(debugVals);
- debugOutputLn(TRACE, "parser()");
- long start = System.currentTimeMillis();
- theReader = new LWOBFileReader(fileName);
- debugOutputLn(TIME, " file opened in " +
- (System.currentTimeMillis() - start));
- parseFile();
- }
-
- LwoParser(URL url, int debugVals)
- throws FileNotFoundException {
- super(debugVals);
- debugOutputLn(TRACE, "parser()");
- try {
- long start = System.currentTimeMillis();
- theReader = new LWOBFileReader(url);
- debugOutputLn(TIME, " file opened in " +
- (System.currentTimeMillis() - start));
- }
- catch (IOException ex) {
- throw new FileNotFoundException(url.toString());
- }
- parseFile();
- }
-
-
- /**
- * Detail polygons are currently not implemented by this loader. Their
- * structure in geometry files is a bit complex, so there's this separate
- * method for simply parsing through and ignoring the data for detail
- * polygons
- */
- int skipDetailPolygons(int numPolys) throws ParsingErrorException {
- debugOutputLn(TRACE, "skipDetailPolygons(), numPolys = " + numPolys);
- int lengthRead = 0;
- int vert;
-
- try {
- for (int polyNum = 0; polyNum < numPolys; ++polyNum) {
- debugOutputLn(VALUES, "polyNum = " + polyNum);
- int numVerts = theReader.getShortInt();
- theReader.skip(numVerts * 2 + 2); // skip indices plus surf
- lengthRead += (numVerts * 2) + 4; // increment counter
- }
- }
- catch (IOException e) {
- debugOutputLn(EXCEPTION, "Exception in reading detail polys: " + e);
- throw new ParsingErrorException(e.getMessage());
- }
- return lengthRead;
- }
-
- /**
- * Returns already-existing ShapeHolder if one exists with the same
- * surface and the same geometry type (point, line, or poly)
- */
- ShapeHolder getAppropriateShape(int numSurf, int numVerts) {
- for (Enumeration e = shapeList.elements();
- e.hasMoreElements() ;) {
- ShapeHolder shape = (ShapeHolder)e.nextElement();
- if (shape.numSurf == numSurf)
- if (shape.numVerts == numVerts ||
- (shape.numVerts > 3 &&
- numVerts > 3))
- return shape;
- }
- return null;
- }
-
-
- /**
- * Parse the file for all the data for a POLS object (polygon
- * description)
- */
- void getPols(int length) {
- debugOutputLn(TRACE, "getPols(len), len = " + length);
- int vert;
- int lengthRead = 0;
- int prevNumVerts = -1;
- int prevNumSurf = 0;
- Vector facetSizesList;
- int facetIndicesArray[];
- facetSizesList =
- new Vector(length/6); // worst case size (every poly one vert)
- // Note that our array sizes are hardcoded because we don't
- // know until we're done how large they will be
- facetIndicesArray = new int[length/2];
- ShapeHolder shape = new ShapeHolder(debugPrinter.getValidOutput());
- debugOutputLn(VALUES, "new shape = " + shape);
- shape.coordsArray = coordsArray;
- shape.facetSizesList = facetSizesList;
- //shape.facetIndicesList = facetIndicesList;
- shape.facetIndicesArray = facetIndicesArray;
- shapeList.addElement(shape);
-
- //long startTime = (new Date()).getTime();
- boolean firstTime = true;
- while (lengthRead < length) {
- int numVerts = theReader.getShortInt();
- lengthRead += 2;
- int intArray[] = new int[numVerts];
- for (int i = 0; i < numVerts; ++i) {
- intArray[i] = theReader.getShortInt();
- lengthRead += 2;
- }
-
- int numSurf = theReader.getShortInt();
- lengthRead += 2;
- long startTimeBuff = 0, startTimeList = 0;
- if (!firstTime &&
- (numSurf != prevNumSurf ||
- ((numVerts != prevNumVerts) &&
- ((prevNumVerts < 3) ||
- (numVerts < 3))))) {
- // If above true, then start new shape
- shape = getAppropriateShape(numSurf, numVerts);
- if (shape == null) {
- //debugOutputLn(LINE_TRACE, "Starting new shape");
- facetSizesList = new Vector(length/6);
- facetIndicesArray = new int[length/2];
- shape = new ShapeHolder(debugPrinter.getValidOutput());
- shape.coordsArray = coordsArray;
- shape.facetSizesList = facetSizesList;
- //shape.facetIndicesList = facetIndicesList;
- shape.facetIndicesArray = facetIndicesArray;
- shape.numSurf = numSurf;
- shape.numVerts = numVerts;
- shapeList.addElement(shape);
- }
- else {
- facetSizesList = shape.facetSizesList;
- facetIndicesArray = shape.facetIndicesArray;
- }
- }
- else {
- shape.numSurf = numSurf;
- shape.numVerts = numVerts;
- }
- prevNumVerts = numVerts;
- prevNumSurf = numSurf;
- facetSizesList.addElement(new Integer(numVerts));
-
- int currPtr = 0;
- System.arraycopy(intArray, 0,
- facetIndicesArray, shape.currentNumIndices,
- numVerts);
- shape.currentNumIndices += numVerts;
- if (numSurf < 0) { // neg number means detail poly
- int numPolys = theReader.getShortInt();
- lengthRead += skipDetailPolygons(numPolys);
- shape.numSurf = ~shape.numSurf & 0xffff;
- if (shape.numSurf == 0)
- shape.numSurf = 1; // Can't have surface = 0
- }
- firstTime = false;
- }
- }
-
- /**
- * Parses file to get the names of all surfaces. Each polygon will
- * be associated with a particular surface number, which is the index
- * number of these names
- */
- void getSrfs(int length) {
- String surfName = new String();
- surfNameList = new Vector(length/2); // worst case size (each name 2 chars long)
- int lengthRead = 0;
- int stopMarker = theReader.getMarker() + length;
-
- int surfIndex = 0;
- while (theReader.getMarker() < stopMarker) {
- debugOutputLn(VALUES, "marker, stop = " +
- theReader.getMarker() + ", " + stopMarker);
- debugOutputLn(LINE_TRACE, "About to call getString");
- surfName = theReader.getString();
- debugOutputLn(VALUES, "Surfname = " + surfName);
- surfNameList.addElement(surfName);
- }
- }
-
- /**
- * Parses file to get all vertices
- */
- void getPnts(int length) throws ParsingErrorException {
- int numVerts = length / 12;
- float x, y, z;
-
- coordsArray = new float[numVerts*3];
- theReader.getVerts(coordsArray, numVerts);
- }
-
- /**
- * Creates new LwoSurface object that parses file and gets all
- * surface parameters for a particular surface
- */
- void getSurf(int length) throws FileNotFoundException {
- debugOutputLn(TRACE, "getSurf()");
-
- // Create LwoSurface object to read and hold each surface, then
- // store that surface in a vector of all surfaces.
-
- LwoSurface surf = new LwoSurface(theReader, length,
- debugPrinter.getValidOutput());
- surfaceList.addElement(surf);
- }
-
-
- /**
- * parses entire file.
- * return -1 on error or 0 on completion
- */
- int parseFile() throws FileNotFoundException, IncorrectFormatException {
- debugOutputLn(TRACE, "parseFile()");
- int length = 0;
- int lengthRead = 0;
- int fileLength = 100000;
-
- long loopStartTime = System.currentTimeMillis();
- // Every parsing unit begins with a four character string
- String tokenString = theReader.getToken();
-
- while (!(tokenString == null) &&
- lengthRead < fileLength) {
- long startTime = System.currentTimeMillis();
- // Based on value of tokenString, go to correct parsing method
- length = theReader.getInt();
-
- lengthRead += 4;
- //debugOutputLn(VALUES, "length, lengthRead, fileLength = " +
- // length + ", " + lengthRead + ", " + fileLength);
- //debugOutputLn(VALUES, "LWOB marker is at: " + theReader.getMarker());
-
- if (tokenString.equals("FORM")) {
- //debugOutputLn(LINE_TRACE, "got a form");
- fileLength = length + 4;
- length = 0;
- tokenString = theReader.getToken();
- lengthRead += 4;
- if (!tokenString.equals("LWOB"))
- throw new IncorrectFormatException(
- "File not of FORM-length-LWOB format");
- }
- else if (tokenString.equals("PNTS")) {
- //debugOutputLn(LINE_TRACE, "PNTS");
- getPnts(length);
- debugOutputLn(TIME, "done with " + tokenString + " in " +
- (System.currentTimeMillis() - startTime));
- }
- else if (tokenString.equals("POLS")) {
- //debugOutputLn(LINE_TRACE, "POLS");
- getPols(length);
- debugOutputLn(TIME, "done with " + tokenString + " in " +
- (System.currentTimeMillis() - startTime));
- }
- else if (tokenString.equals("SRFS")) {
- //debugOutputLn(LINE_TRACE, "SRFS");
- getSrfs(length);
- debugOutputLn(TIME, "done with " + tokenString + " in " +
- (System.currentTimeMillis() - startTime));
- }
- else if (tokenString.equals("CRVS")) {
- //debugOutputLn(LINE_TRACE, "CRVS");
- theReader.skipLength(length);
- //debugOutputLn(TIME, "done with " + tokenString + " in " +
- // (System.currentTimeMillis() - startTime));
- }
- else if (tokenString.equals("PCHS")) {
- //debugOutputLn(LINE_TRACE, "PCHS");
- theReader.skipLength(length);
- //debugOutputLn(TIME, "done with " + tokenString + " in " +
- // (System.currentTimeMillis() - startTime));
- }
- else if (tokenString.equals("SURF")) {
- //debugOutputLn(LINE_TRACE, "SURF");
- getSurf(length);
- //debugOutputLn(VALUES, "Done with SURF, marker = " + theReader.getMarker());
- debugOutputLn(TIME, "done with " + tokenString + " in " +
- (System.currentTimeMillis() - startTime));
- }
- else if (tokenString.equals("LWOB")) {
- //debugOutputLn(LINE_TRACE, "LWOB");
- }
- else {
- //debugOutputLn(LINE_TRACE, "Unknown object = " + tokenString);
- theReader.skipLength(length);
- //debugOutputLn(TIME, "done with " + tokenString + " in " +
- // (System.currentTimeMillis() - startTime));
- }
- lengthRead += length;
- if (lengthRead < fileLength) {
- //debugOutputLn(VALUES, "end of parseFile, length, lengthRead = " +
- // length + ", " + lengthRead);
- tokenString = theReader.getToken();
- lengthRead += 4;
- //debugOutputLn(VALUES, "just got tokenString = " + tokenString);
- }
- }
- debugOutputLn(TIME, "done with parseFile in " +
- (System.currentTimeMillis() - loopStartTime));
- return 0;
- }
-
- /**
- * This method is used only for testing
- */
- static void main(String[] args) {
- String fileName;
- if (args.length == 0)
- fileName = "cube.obj";
- else
- fileName = args[0];
-
- try {
- LwoParser theParser = new LwoParser(fileName, 0);
- }
- catch (FileNotFoundException e) {
- System.err.println(e.getMessage());
- e.printStackTrace();
- System.exit(1);
- }
- }
-}
-
-
-
-
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwoSurface.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwoSurface.java
deleted file mode 100644
index fd23902..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwoSurface.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-import java.awt.Image;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Vector;
-
-import javax.vecmath.Color3f;
-import javax.vecmath.Vector3f;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-import com.sun.j3d.loaders.IncorrectFormatException;
-import com.sun.j3d.loaders.ParsingErrorException;
-
-
-/**
- * This class is responsible for retrieving the surface parameters for a
- * particular surface from a binary Object file and turning that data
- * into Java3D data. These surface parameters include
- * diffuse/specular/emissive properties, color, shininess, transparency,
- * and textures. For textures, this class instantiates a LwoTexture object
- * to parse that data and turn it into Java3D texture data.
- */
-
-class LwoSurface extends ParserObject {
-
- LWOBFileReader theReader;
- int red = 255, green = 255, blue = 255;
- float diffuse = 0.0f, specular = 0.0f, transparency = 0.0f, luminosity = 0.0f;
- float creaseAngle = 0.0f;
- int gloss = 128;
- Color3f color, diffuseColor, specularColor, emissiveColor;
- float shininess;
- Image theImage = null;
- Vector3f textureCenter = null, textureSize = null;
- int textureAxis;
- String surfName;
- Vector textureList = new Vector();
-
- /**
- * Constructor that parses surface data from the binary file
- * and creates the necessary Java3d objects
- */
- LwoSurface(LWOBFileReader reader, int length, int debugVals)
- throws FileNotFoundException {
-
- super(debugVals);
- debugOutputLn(TRACE, "LwoSurface()");
- theReader = reader;
- getSurf(length);
- setJ3dColors();
- }
-
- /**
- * Creates Java3d color objects from the lw3d surface data
- */
- void setJ3dColors() {
- color = new Color3f((float)red/(float)255,
- (float)green/(float)255,
- (float)blue/(float)255);
- diffuseColor = new Color3f(diffuse*color.x,
- diffuse*color.y,
- diffuse*color.z);
- specularColor = new Color3f(specular*color.x,
- specular*color.y,
- specular*color.z);
- emissiveColor = new Color3f(luminosity*color.x,
- luminosity*color.y,
- luminosity*color.z);
- shininess = (float)(128.0 * ((float)gloss/1024.0));
- }
-
- Color3f getColor() {
- return color;
- }
-
- Color3f getDiffuseColor() {
- return diffuseColor;
- }
-
- Color3f getSpecularColor() {
- return specularColor;
- }
-
- Color3f getEmissiveColor() {
- return emissiveColor;
- }
-
- float getShininess() {
- return shininess;
- }
-
- float getCreaseAngle() {
- return creaseAngle;
- }
-
- /**
- * Returns the LwoTexture for the surface, if any is defined. Note that
- * lw3d allows users to define multiple textures for any surface, which
- * is not possible through Java3d. Therefore, we just grab the first
- * texture in any list of textures for a surface
- */
- LwoTexture getTexture() {
- debugOutputLn(TRACE, "getTexture()");
- try {
- if (textureList.isEmpty()) {
- return null;
- }
- else {
- return (LwoTexture)textureList.elementAt(0);
- }
- }
- catch (ArrayIndexOutOfBoundsException e) {
- debugOutputLn(EXCEPTION,
- "getTexture(), exception returning first element: " + e);
- return null;
- }
- }
-
- String getSurfName() {
- return surfName;
- }
-
- float getTransparency() {
- return transparency;
- }
-
- /**
- * Parses the binary file and gets all data for this surface
- */
- void getSurf(int length)
- throws FileNotFoundException, IncorrectFormatException,
- ParsingErrorException {
-
- debugOutputLn(TRACE, "getSurf()");
-
- // These "got*" booleans are to help use read the best version of
- // the data - the float values for these parameters should take
- // precedence over the other format
- boolean gotLuminosityFloat = false;
- boolean gotTransparencyFloat = false;
- boolean gotDiffuseFloat = false;
- boolean gotSpecularFloat = false;
- int surfStopMarker = theReader.getMarker() + length;
- surfName = theReader.getString();
- String tokenString = theReader.getToken();
- while (!(tokenString == null) &&
- theReader.getMarker() < surfStopMarker) {
- debugOutputLn(VALUES, " tokenString = " + tokenString);
- debugOutputLn(VALUES, " marker, stop = " +
- theReader.getMarker() + ", " + surfStopMarker);
- String textureToken = null;
- int fieldLength = theReader.getShortInt();
- debugOutputLn(VALUES, " fl = " + fieldLength);
-
- if (tokenString.equals("COLR")) {
- debugOutputLn(LINE_TRACE, " COLR");
- try {
- red = theReader.read();
- green = theReader.read();
- blue = theReader.read();
- theReader.read();
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- if (fieldLength != 4)
- throw new IncorrectFormatException(
- J3dUtilsI18N.getString("LwoSurface0"));
- }
- else if (tokenString.equals("FLAG")) {
- debugOutputLn(LINE_TRACE, " FLAG");
- theReader.skipLength(fieldLength);
- }
- else if (tokenString.equals("VLUM")) {
- debugOutputLn(LINE_TRACE, " VLUM");
- luminosity = theReader.getFloat();
- gotLuminosityFloat = true;
- }
- else if (tokenString.equals("LUMI")) {
- debugOutputLn(LINE_TRACE, " LUMI");
- if (gotLuminosityFloat)
- theReader.skipLength(fieldLength);
- else
- luminosity = (float)(theReader.getShortInt())/255;
- }
- else if (tokenString.equals("VDIF")) {
- debugOutputLn(LINE_TRACE, " VDIF");
- if (fieldLength != 4)
- throw new IncorrectFormatException("VDIF problem");
- diffuse = theReader.getFloat();
- gotDiffuseFloat = true;
- debugOutputLn(VALUES, "diff = " + diffuse);
- }
- else if (tokenString.equals("DIFF")) {
- debugOutputLn(LINE_TRACE, " DIFF");
- if (gotDiffuseFloat)
- theReader.skipLength(fieldLength);
- else
- diffuse = (float)theReader.getShortInt()/255;
- }
- else if (tokenString.equals("VTRN")) {
- debugOutputLn(LINE_TRACE, " VTRN");
- transparency = theReader.getFloat();
- gotTransparencyFloat = true;
- }
- else if (tokenString.equals("TRAN")) {
- debugOutputLn(LINE_TRACE, " TRAN");
- if (gotTransparencyFloat)
- theReader.skipLength(fieldLength);
- else
- transparency = (float)theReader.getShortInt()/255;
- }
- else if (tokenString.equals("VSPC")) {
- debugOutputLn(LINE_TRACE, " VSPC");
- specular = theReader.getFloat();
- gotSpecularFloat = true;
- debugOutputLn(VALUES, "spec = " + specular);
- }
- else if (tokenString.equals("SPEC")) {
- debugOutputLn(LINE_TRACE, " SPEC");
- if (gotSpecularFloat)
- theReader.skipLength(fieldLength);
- else {
- if (fieldLength == 4) // Bug in some LW versions
- specular = (float)theReader.getInt()/255;
- else
- specular = (float)theReader.getShortInt()/255;
- }
- }
- else if (tokenString.equals("GLOS")) {
- debugOutputLn(LINE_TRACE, " GLOS");
- if (fieldLength == 4)
- gloss = theReader.getInt();
- else
- gloss = theReader.getShortInt();
- }
- else if (tokenString.equals("SMAN")) {
- debugOutputLn(LINE_TRACE, " SMAN");
- creaseAngle = theReader.getFloat();
- }
- else if (tokenString.endsWith("TEX")) {
- // Textures are complex - hand off this bit to the
- // LwoTexture class
- LwoTexture texture =
- new LwoTexture(theReader,
- surfStopMarker - theReader.getMarker(),
- tokenString,
- debugPrinter.getValidOutput());
- textureToken = texture.getNextToken();
- if (texture.isHandled())
- textureList.addElement(texture);
- debugOutputLn(WARNING, "val = " + tokenString);
- }
- else {
- debugOutputLn(WARNING,
- "unrecognized token: " + tokenString);
- theReader.skipLength(fieldLength);
- }
- if (theReader.getMarker() < surfStopMarker) {
- if (textureToken == null)
- tokenString = theReader.getToken();
- else
- tokenString = textureToken;
- }
- }
- }
-
-}
-
-
-
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwoTexture.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwoTexture.java
deleted file mode 100644
index 9249b02..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwoTexture.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-import java.awt.Image;
-import java.awt.image.BufferedImage;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Hashtable;
-
-import javax.media.j3d.Texture;
-import javax.media.j3d.Texture2D;
-import javax.vecmath.Color3f;
-import javax.vecmath.Vector3f;
-
-import com.sun.j3d.loaders.ParsingErrorException;
-import com.sun.j3d.utils.image.TextureLoader;
-
-/**
- * This class is responsible for parsing the binary data in an Object file
- * that describes a texture for a particular surface and turning that data
- * into Java3D texture data. If the texture is coming from a file (which
- * is the only type of texture handled by the loader currently; other
- * types of texture definitions are ignored), then this class instantiates
- * a TargaReader object to read the data in that file. Once all of the
- * data has been read, the class creates a Java3D Texture object by first
- * scaling the image using the ImageScaler class (since all textures must
- * have width/height = power of 2; Note: this functionality is now built
- * into the TextureLoader class, so it could be removed from this loader)
- * and then creating a Texture with that image.
- */
-
-class LwoTexture extends ParserObject {
-
- LWOBFileReader theReader;
- int red = 255, green = 255, blue = 255;
- Color3f color, diffuseColor, specularColor, emissiveColor;
- Image theImage = null;
- String imageFile = null;
- Vector3f textureSize = new Vector3f(1f, 1f, 1f);;
- Vector3f textureCenter = new Vector3f(0f, 0f, 0f);
- int textureAxis;
- int flags = 0;
- String type;
- String mappingType;
- String nextToken = null;
- static Hashtable imageTable = new Hashtable();
- static Hashtable textureTable = new Hashtable();
-
- /**
- * Constructor: calls readTexture() to parse the file and retrieve
- * texture parameters
- */
- LwoTexture(LWOBFileReader reader, int length, String typename,
- int debugVals) throws FileNotFoundException {
- super(debugVals);
- debugOutputLn(TRACE, "Constructor");
- theReader = reader;
- type = typename;
- readTexture(length);
- }
-
- String getNextToken() {
- return nextToken;
- }
-
- /**
- * The loader currently only handles CTEX and DTEX texture types
- * (These either represent the surface color like a decal (CTEX)
- * or modify the diffuse color (DTEX)
- */
- boolean isHandled() {
- if ((type.equals("CTEX") ||
- type.equals("DTEX")) &&
- theImage != null)
- return true;
- debugOutputLn(LINE_TRACE, "failed isHandled(), type, theImage = " +
- type + ", " + theImage);
- return false;
- }
-
- /**
- * Return the actual Texture object associated with the current image.
- * If we've already created a texture for this image, return that;
- * otherwise create a new Texture
- */
- Texture getTexture() {
- debugOutputLn(TRACE, "getTexture()");
- if (theImage == null)
- return null;
- Texture2D t2d = (Texture2D)textureTable.get(theImage);
- if (t2d == null) {
- ImageScaler scaler = new ImageScaler((BufferedImage)theImage);
- BufferedImage scaledImage = (BufferedImage)scaler.getScaledImage();
- TextureLoader tl = new TextureLoader(scaledImage);
- t2d = (Texture2D)tl.getTexture();
- textureTable.put(theImage, t2d);
- }
-
- return t2d;
- }
-
- String getType() {
- return type;
- }
-
- Color3f getColor() {
- return color;
- }
-
- Image getImage() {
- return theImage;
- }
-
- Vector3f getTextureSize() {
- return textureSize;
- }
-
- int getTextureAxis() {
- return textureAxis;
- }
-
- Vector3f getTextureCenter() {
- return textureCenter;
- }
-
- String getMappingType() {
- return mappingType;
- }
-
- /**
- * Parse the binary file to retrieve all texture parameters for this
- * surface. If/when we encounter a TIMG parameter, which contains the
- * filename of an image, then create a new TargaReader object to
- * read that image file
- */
- void readTexture(int length)
- throws FileNotFoundException, ParsingErrorException {
-
- debugOutputLn(TRACE, "readTexture()");
-
- int surfStopMarker = theReader.getMarker() + length;
- mappingType = theReader.getString();
- debugOutputLn(VALUES, "mappingType = " + mappingType);
- String tokenString = theReader.getToken();
- while (!(tokenString == null) && theReader.getMarker() < surfStopMarker) {
-
- debugOutputLn(VALUES, " tokenString = " + tokenString);
- debugOutputLn(VALUES, " marker, stop = " + theReader.getMarker() + ", " + surfStopMarker);
-
- if (tokenString.endsWith("TEX") ||
- (!tokenString.startsWith("T") || tokenString.equals("TRAN"))) {
- nextToken = tokenString;
- return;
- }
-
- int fieldLength = theReader.getShortInt();
- debugOutputLn(VALUES, " fl = " + fieldLength);
-
- if (tokenString.equals("TFLG")) {
- debugOutputLn(WARNING, "Not yet handling: " + tokenString);
- flags = theReader.getShortInt();
- textureAxis = flags & 0x07;
- debugOutputLn(WARNING, "val = " + flags);
- }
- else if (tokenString.equals("TCLR")) {
- debugOutputLn(WARNING, "Not yet handling: " + tokenString);
- try {
- red = theReader.read();
- green = theReader.read();
- blue = theReader.read();
- theReader.read();
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- debugOutputLn(WARNING, "val = " + red + ", " + green +
- ", " + blue);
- }
- else if (tokenString.equals("TIMG")) {
- debugOutputLn(WARNING, "Not yet handling: " + tokenString);
- imageFile = theReader.getString();
- debugOutputLn(VALUES, "imageFile = " + imageFile);
- if (imageFile.indexOf("none") == -1) {
- if ((theImage =
- (Image)imageTable.get(imageFile)) == null) {
- try {
- TargaReader tr =
- new TargaReader(imageFile,
- debugPrinter.getValidOutput());
- theImage = tr.getImage();
- imageTable.put(imageFile, theImage);
- }
- catch (FileNotFoundException e) {
- // Ignore texture if can't find it
- debugOutputLn(WARNING, "Image File skipped: " +
- imageFile);
- }
- }
- }
- debugOutputLn(WARNING, "val = __" + imageFile + "__");
- }
- else if (tokenString.equals("TWRP")) {
- debugOutputLn(WARNING, "Not yet handling: " + tokenString);
- int widthWrap = theReader.getShortInt();
- int heightWrap = theReader.getShortInt();
- debugOutputLn(WARNING, "val = " + widthWrap + ", " +
- heightWrap);
- }
- else if (tokenString.equals("TCTR")) {
- debugOutputLn(WARNING, "Not yet handling: " + tokenString);
- textureCenter.x = theReader.getFloat();
- textureCenter.y = theReader.getFloat();
- textureCenter.z = theReader.getFloat();
- debugOutputLn(WARNING, "val = " + textureCenter);
- }
- else if (tokenString.equals("TSIZ")) {
- debugOutputLn(WARNING, "Not yet handling: " + tokenString);
- textureSize.x = theReader.getFloat();
- textureSize.y = theReader.getFloat();
- textureSize.z = theReader.getFloat();
- debugOutputLn(WARNING, "val = " + textureSize);
- }
- else {
- debugOutputLn(WARNING,
- "unrecognized token: " + tokenString);
- theReader.skipLength(fieldLength);
- }
- if (theReader.getMarker() < surfStopMarker) {
- tokenString = theReader.getToken();
- }
- }
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsBackground.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwsBackground.java
deleted file mode 100644
index cf548ea..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsBackground.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-
-
-import java.io.IOException;
-import java.io.StreamTokenizer;
-
-import javax.media.j3d.Background;
-import javax.media.j3d.BoundingSphere;
-import javax.vecmath.Color3f;
-import javax.vecmath.Point3d;
-
-import com.sun.j3d.loaders.ParsingErrorException;
-
-
-/**
- * This class creates a Background object (solid color only, no geometry)
- * according to some of the data stored in a Scene file. Note: Lightwave
- * defines much more complex backgrounds that the loader currently
- * handles. It should be possible to se Background Geometry to handle
- * most of these cases, if there's time and will to work on the problem.
- */
-
-class LwsBackground extends TextfileParser {
-
- // data from the file
- int solidBackdrop;
- Color3f color, zenithColor, skyColor, groundColor, nadirColor;
- Background backgroundObject = null;
-
-
- /**
- * Constructor: parses stream and retrieves all Background-related data
- */
- LwsBackground(StreamTokenizer st, int debugVals)
- throws ParsingErrorException {
-
- debugPrinter.setValidOutput(debugVals);
- debugOutput(TRACE, "LwsBackground()");
- color = new Color3f(0f, 0f, 0f);
- zenithColor = new Color3f(0f, 0f, 0f);
- skyColor = new Color3f(0f, 0f, 0f);
- groundColor = new Color3f(0f, 0f, 0f);
- nadirColor = new Color3f(0f, 0f, 0f);
-
- solidBackdrop = (int)getNumber(st);
- while (!isCurrentToken(st, "FogType")) {
- debugOutputLn(LINE_TRACE, "currentToken = " + st.sval);
-
- if (isCurrentToken(st, "BackdropColor")) {
- color.x = (float)getNumber(st)/255f;
- color.y = (float)getNumber(st)/255f;
- color.z = (float)getNumber(st)/255f;
- }
- else if (isCurrentToken(st, "NadirColor")) {
- nadirColor.x = (float)getNumber(st)/255f;
- nadirColor.y = (float)getNumber(st)/255f;
- nadirColor.z = (float)getNumber(st)/255f;
- }
- else if (isCurrentToken(st, "SkyColor")) {
- skyColor.x = (float)getNumber(st)/255f;
- skyColor.y = (float)getNumber(st)/255f;
- skyColor.z = (float)getNumber(st)/255f;
- }
- else if (isCurrentToken(st, "GroundColor")) {
- groundColor.x = (float)getNumber(st)/255f;
- groundColor.y = (float)getNumber(st)/255f;
- groundColor.z = (float)getNumber(st)/255f;
- }
- else if (isCurrentToken(st, "NadirColor")) {
- nadirColor.x = (float)getNumber(st)/255f;
- nadirColor.y = (float)getNumber(st)/255f;
- nadirColor.z = (float)getNumber(st)/255f;
- }
- try {
- st.nextToken();
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- }
- st.pushBack(); // push token back on stack
- }
-
- /**
- * Creates Java3d objects from the background data. Note that there
- * are plenty of lw3d background attributes that the loader currently
- * ignores. Some of these may best be handled by creating background
- * geometry rather than a solid background color
- */
- void createJava3dObject() {
- // TODO: there are various attributes of
- // backdrops that we're not currently handling. In
- // particular, if the file calls for a gradient background
- // (solidBackdrop == 0), we ignore the request and just
- // create a solid background from the sky color instead.
- // We should be able to do something with the
- // various colors specified, perhaps by creating
- // background geometry with the appropriate vertex
- // colors?
-
- if (solidBackdrop != 0) {
- backgroundObject = new Background(color);
- debugOutput(VALUES, "Background color = " + color);
- }
- else {
- backgroundObject = new Background(skyColor);
- debugOutput(VALUES, "Background color = " + skyColor);
- }
- BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100000.0);
- backgroundObject.setApplicationBounds(bounds);
- }
-
- Background getObjectNode() {
- return backgroundObject;
- }
-
- void printVals() {
- debugOutputLn(VALUES, " BACKGROUND vals: ");
- }
-
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsCamera.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwsCamera.java
deleted file mode 100644
index bef9f5d..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsCamera.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-
-
-import java.io.IOException;
-import java.io.StreamTokenizer;
-import java.util.Vector;
-
-import javax.media.j3d.Behavior;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-import javax.vecmath.Matrix4d;
-
-import com.sun.j3d.loaders.ParsingErrorException;
-
-/**
- * This class parses the data in a Scene file related to the camera and
- * creates Java3D TransformGroup that holds the data for positioning
- * and orienting the view according to the camera specifications.
- */
-
-class LwsCamera extends TextfileParser implements LwsPrimitive {
-
- // data from the file
- String fileName;
- String objName;
- LwsMotion motion;
- int parent;
- TransformGroup objectTransform;
- Vector objectBehavior;
-
- /**
- * Constructor: parses camera info and creates LwsMotion object for
- * keyframe data
- */
- LwsCamera(StreamTokenizer st, int firstFrame,
- int totalFrames, float totalTime,
- int debugVals) throws ParsingErrorException {
- debugPrinter.setValidOutput(debugVals);
- parent = -1;
- getNumber(st); // Skip ShowCamera parameters
- getNumber(st);
- getAndCheckString(st, "CameraMotion");
- motion = new LwsMotion(st, firstFrame, totalFrames, totalTime,
- debugPrinter.getValidOutput());
-
- // TODO: buggy way to stop processing the camera. Should actually
- // process required/optional fields in order and stop when there's
- // no more.
-
- while (!isCurrentToken(st, "DepthOfField")) {
- debugOutputLn(LINE_TRACE, "currentToken = " + st.sval);
-
- if (isCurrentToken(st, "ParentObject")) {
- parent = (int)getNumber(st);
- }
- try {
- st.nextToken();
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- }
- getNumber(st); // skip shadow type parameter
- }
-
- /**
- * Returns parent of the camera object
- */
- int getParent() {
- return parent;
- }
-
- /**
- * Creates Java3D items from the camera data. These objects consist
- * of: a TransformGroup to hold the view platform, and the behaviors
- * (if any) that act upon the view's TransformGroup.
- */
- void createJava3dObject(int loadBehaviors)
- {
- Matrix4d mat = new Matrix4d();
- mat.setIdentity();
- // Set the node's transform matrix according to the first frame
- // of the object's motion
- LwsFrame firstFrame = motion.getFirstFrame();
- firstFrame.setMatrix(mat);
- debugOutputLn(VALUES, " Camera Matrix = \n" + mat);
- Transform3D t1 = new Transform3D();
- Matrix4d m = new Matrix4d();
- double scale = .1;
- m.setColumn(0, scale, 0, 0, 0); // setScale not yet implemented
- m.setColumn(1, 0, scale, 0, 0);
- m.setColumn(2, 0, 0, scale, 0);
- m.setColumn(3, 0, 0, 0, 1);
- Transform3D scaleTrans = new Transform3D(m);
- TransformGroup scaleGroup = new TransformGroup(scaleTrans);
- scaleGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- scaleGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
- // mat.mul(m);
- t1.set(mat);
- objectTransform = new TransformGroup(t1);
- objectTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- objectBehavior = new Vector();;
- if (loadBehaviors != 0) {
- motion.createJava3dBehaviors(objectTransform);
- Behavior b = motion.getBehaviors();
- if (b != null)
- objectBehavior.addElement(b);
- }
- }
-
- /**
- * Returns TransformGroup of camera
- */
- @Override
- public TransformGroup getObjectNode()
- {
- return objectTransform;
- }
-
- /**
- * Returns animation behaviors for camera
- */
- @Override
- public Vector getObjectBehaviors()
- {
- debugOutputLn(TRACE, "getObjectBehaviors()");
- return objectBehavior;
- }
-
- /**
- * This is a debuggin utility, not currently activated. It prints
- * out the camera values
- */
- void printVals()
- {
- System.out.println(" objName = " + objName);
- motion.printVals();
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelope.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelope.java
deleted file mode 100644
index 1e9fb86..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelope.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-import java.io.IOException;
-import java.io.StreamTokenizer;
-
-import javax.media.j3d.Behavior;
-import javax.media.j3d.TransformGroup;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-import com.sun.j3d.loaders.IncorrectFormatException;
-import com.sun.j3d.loaders.ParsingErrorException;
-
-/**
- * This class is a superclass for any implementation of envelopes; the
- * only subclass currently is LwsEnvelopeLightIntensity. LwsEnvelope
- * parses the data in a Scene file and extracts the envelope data.
- */
-
-class LwsEnvelope extends TextfileParser {
-
- // data from the file
- String name;
- LwsEnvelopeFrame frames[];
- int numFrames;
- int numChannels;
- boolean loop;
- float totalTime;
- int totalFrames;
- Behavior behaviors;
-
- /**
- * Constructor: calls getEnvelope() to parse the stream for the
- * envelope data
- */
- LwsEnvelope(StreamTokenizer st, int frames, float time) {
- numFrames = 0;
- totalTime = time;
- totalFrames = frames;
- name = getName(st);
- getEnvelope(st);
- }
-
- /**
- * Parses the stream to retrieve all envelope data. Creates
- * LwsEnvelopeFrame objects for each keyframe of the envelope
- * (these frames differ slightly from LwsFrame objects because
- * envelopes contain slightly different data)
- */
- void getEnvelope(StreamTokenizer st)
- throws IncorrectFormatException, ParsingErrorException
- {
- debugOutputLn(TRACE, "getEnvelope()");
- numChannels = (int)getNumber(st);
- if (numChannels != 1) {
- throw new IncorrectFormatException(
- J3dUtilsI18N.getString("LwsEnvelope0"));
- }
- debugOutputLn(LINE_TRACE, "got channels");
-
- numFrames = (int)getNumber(st);
- frames = new LwsEnvelopeFrame[numFrames];
- debugOutputLn(VALUES, "got frames" + numFrames);
-
- for (int i = 0; i < numFrames; ++i) {
- frames[i] = new LwsEnvelopeFrame(st);
- }
- debugOutput(LINE_TRACE, "got all frames");
-
- try {
- st.nextToken();
- while (!isCurrentToken(st, "EndBehavior")) {
- // There is an undocumented "FrameOffset" in some files
- st.nextToken();
- }
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- int repeatVal = (int)getNumber(st);
- if (repeatVal == 1)
- loop = false;
- else
- loop = true;
- }
-
- /**
- * This superclass does nothing here - if the loader understands
- * how to deal with a particular type of envelope, it will use
- * a subclass of LwsEnvelope that will override this method
- */
- void createJava3dBehaviors(TransformGroup target) {
- behaviors = null;
- }
-
- Behavior getBehaviors() {
- return behaviors;
- }
-
-
- LwsEnvelopeFrame getFirstFrame() {
- if (numFrames > 0)
- return frames[0];
- else
- return null;
- }
-
-
- void printVals() {
- debugOutputLn(VALUES, " name = " + name);
- debugOutputLn(VALUES, " numChannels = " + numChannels);
- debugOutputLn(VALUES, " numFrames = " + numFrames);
- debugOutputLn(VALUES, " loop = " + loop);
- for (int i = 0; i < numFrames; ++i) {
- debugOutputLn(VALUES, " FRAME " + i);
- frames[i].printVals();
- }
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeFrame.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeFrame.java
deleted file mode 100644
index 0bd9145..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeFrame.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-
-
-import java.io.StreamTokenizer;
-
-/**
- * This class represents one keyframe in an envelope sequence.
- */
-
-class LwsEnvelopeFrame extends TextfileParser {
-
- // data from the file
- double value;
- double frameNumber;
- int linearValue;
- double tension, continuity, bias;
-
-
- /**
- * Constructor: parses stream and stores data for one keyframe of
- * an envelope sequence
- */
- LwsEnvelopeFrame(StreamTokenizer st) {
- value = getNumber(st);
- debugOutputLn(VALUES, "value = " + value);
- frameNumber = (int)getNumber(st);
- linearValue = (int)getNumber(st);
- debugOutputLn(VALUES, "framenum, linear " + frameNumber + " , " + linearValue);
- tension = getNumber(st);
- continuity = getNumber(st);
- bias = getNumber(st);
- debugOutputLn(VALUES, "tension, cont, bias = " + tension + ", " + continuity + ", " + bias);
- //System.out.println(" FRAME VALS");
- //printVals();
- }
-
-
- double getValue() {
- return value;
- }
-
-
- double getFrameNum() {
- return frameNumber;
- }
-
-
- void printVals() {
- debugOutputLn(VALUES, " value = " + value);
- debugOutputLn(VALUES, " frameNum = " + frameNumber);
- debugOutputLn(VALUES, " lin = " + linearValue);
- debugOutputLn(VALUES, " tension = " + tension);
- debugOutputLn(VALUES, " continuity = " + continuity);
- debugOutputLn(VALUES, " bias = " + bias);
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeLightIntensity.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeLightIntensity.java
deleted file mode 100644
index b8ff1b8..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsEnvelopeLightIntensity.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-
-
-import java.io.StreamTokenizer;
-
-import javax.media.j3d.Alpha;
-import javax.media.j3d.Behavior;
-import javax.media.j3d.BoundingSphere;
-import javax.media.j3d.TransformGroup;
-import javax.vecmath.Point3d;
-
-
-/**
- * This class creates a LightIntensityPathInterpolator object from the
- * keyframe-based envelope specified in a Scene file.
- */
-
-class LwsEnvelopeLightIntensity extends LwsEnvelope {
-
-
- /**
- * Constructor: Calls superclass, which will parse the stream
- * and store the envelope data
- */
- LwsEnvelopeLightIntensity(StreamTokenizer st,
- int frames, float time) {
- super(st, frames, time);
- }
-
- /**
- * Creates Java3d behaviors given the stored envelope data. The
- * Behavior created is a LightIntensityPathInterpolator
- */
- void createJava3dBehaviors(Object target) {
- if (numFrames <= 1)
- behaviors = null;
- else {
- long alphaAtOne = 0;
- int loopCount;
- if (loop)
- loopCount = -1;
- else
- loopCount = 1;
- // Note: hardcoded to always loop...
- loopCount = -1;
- debugOutputLn(VALUES, "totalTime = " + totalTime);
- debugOutputLn(VALUES, "loopCount = " + loopCount);
- float animTime = 1000.0f * totalTime *
- (float)(frames[numFrames-1].getFrameNum()/(float)totalFrames);
- debugOutputLn(VALUES, " anim time: " + animTime);
- debugOutputLn(VALUES, " totalFrames = " + totalFrames);
- debugOutputLn(VALUES, " lastFrame = " +
- frames[numFrames-1].getFrameNum());
- if (!loop)
- alphaAtOne = (long)(1000.0*totalTime - animTime);
- Alpha theAlpha =
- new Alpha(loopCount, Alpha.INCREASING_ENABLE,
- 0, 0, (long)animTime, 0,
- alphaAtOne, 0, 0, 0);
- float knots[] = new float[numFrames];
- float values[] = new float[numFrames];
- for (int i=0; i < numFrames; ++i) {
- values[i] = (float)frames[i].getValue();
- knots[i] = (float)(frames[i].getFrameNum())/
- (float)(frames[numFrames-1].getFrameNum());
- debugOutputLn(VALUES, "value, knot = " +
- values[i] + ", " + knots[i]);
- }
- LightIntensityPathInterpolator l = new
- LightIntensityPathInterpolator(theAlpha,
- knots,
- values,
- target);
- if (l != null) {
- behaviors = l;
- BoundingSphere bounds =
- new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0);
- behaviors.setSchedulingBounds(bounds);
- ((TransformGroup)target).setCapability
- (TransformGroup.ALLOW_TRANSFORM_WRITE);
- ((TransformGroup)target).addChild(behaviors);
- }
- }
- }
-
-
- @Override
- Behavior getBehaviors() {
- return behaviors;
- }
-
-
- @Override
- LwsEnvelopeFrame getFirstFrame() {
- if (numFrames > 0)
- return frames[0];
- else
- return null;
- }
-
-
- @Override
- void printVals() {
- debugOutputLn(VALUES, " name = " + name);
- debugOutputLn(VALUES, " numChannels = " + numChannels);
- debugOutputLn(VALUES, " numFrames = " + numFrames);
- debugOutputLn(VALUES, " loop = " + loop);
- for (int i = 0; i < numFrames; ++i) {
- debugOutputLn(VALUES, " FRAME " + i);
- frames[i].printVals();
- }
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFog.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFog.java
deleted file mode 100644
index 9c90ef5..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFog.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-
-
-import java.io.IOException;
-import java.io.StreamTokenizer;
-
-import javax.media.j3d.BoundingSphere;
-import javax.media.j3d.Fog;
-import javax.media.j3d.LinearFog;
-import javax.vecmath.Color3f;
-import javax.vecmath.Point3d;
-
-import com.sun.j3d.loaders.ParsingErrorException;
-
-
-/**
- * This class creates a Fog object from the data in a Scene file.
- */
-
-class LwsFog extends TextfileParser {
-
- // data from the file
- float minDist, maxDist, minAmount, maxAmount;
- int backdropFog;
- Color3f color;
- int type;
- Fog fogObject = null;
-
- /**
- * Constructor: parses stream and stores fog data
- */
- LwsFog(StreamTokenizer st, int debugVals) throws ParsingErrorException {
- debugPrinter.setValidOutput(debugVals);
- debugOutput(TRACE, "LwsFog()");
- color = new Color3f(0f, 0f, 0f);
-
- while (!isCurrentToken(st, "DitherIntensity")) {
- debugOutputLn(LINE_TRACE, "currentToken = " + st.sval);
-
- if (isCurrentToken(st, "FogMinDist")) {
- minDist = (float)getNumber(st);
- }
- else if (isCurrentToken(st, "FogMaxDist")) {
- maxDist = (float)getNumber(st);
- }
- else if (isCurrentToken(st, "FogMinAmount")) {
- minAmount = (float)getNumber(st);
- }
- else if (isCurrentToken(st, "FogMaxAmount")) {
- maxAmount = (float)getNumber(st);
- }
- else if (isCurrentToken(st, "BackdropFog")) {
- backdropFog = (int)getNumber(st);
- }
- else if (isCurrentToken(st, "FogColor")) {
- color.x = (float)getNumber(st)/255f;
- color.y = (float)getNumber(st)/255f;
- color.z = (float)getNumber(st)/255f;
- }
- try {
- st.nextToken();
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- }
- st.pushBack(); // push token back on stack
- }
-
- /**
- * Creates Java3d Fog object given the fog parameters in the file.
- * Note that various fog parameters in lw3d are not currently handled.
- */
- void createJava3dObject() {
- // TODO: there are various attributes of lw fog that
- // we're not currently handing, including non-linear fog
- // (need to understand the two different types - these may
- // map onto java3d's expontential fog node), non-solid
- // backdrop colors (how to handle this?), min/max amount
- // (j3d only handles 0 -> 1 case)
-
- fogObject = new LinearFog(color, minDist, maxDist);
- debugOutputLn(VALUES,
- "just set linearFog with color, minDist, maxDist = " +
- color + ", " +
- minDist + ", " +
- maxDist);
- BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100000.0);
- fogObject.setInfluencingBounds(bounds);
- }
-
- Fog getObjectNode()
- {
- return fogObject;
- }
-
- void printVals()
- {
- debugOutputLn(VALUES, " FOG vals: ");
- }
-
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFrame.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFrame.java
deleted file mode 100644
index 48ba728..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsFrame.java
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-
-
-import java.io.StreamTokenizer;
-
-import javax.vecmath.Matrix4d;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3d;
-
-/**
- * This class is responsible for parsing the data in a Scene file
- * associated with a single keyframe. This data includes the position,
- * orientation, and scaling information, in addition to the frame number
- * of that keyframe and some spline controls which are currently
- * ignored.
- */
-
-class LwsFrame extends TextfileParser {
-
- // data from the file
- double x, y, z;
- double heading, pitch, bank;
- double xScale, yScale, zScale;
- double frameNumber;
- int linearValue;
- double tension, continuity, bias;
-
- /**
- * Constructor: parses and stores all data associated with a particular
- * keyframe
- */
- LwsFrame(StreamTokenizer st) {
- x = getNumber(st);
- y = getNumber(st);
- z = -getNumber(st);
- debugOutputLn(VALUES, "x, y, z " + x + ", " + y + ", " + z);
- heading = getNumber(st);
- pitch = getNumber(st);
- bank = getNumber(st);
- debugOutputLn(VALUES, "(degrees) h, p, b = " + heading + ", " + pitch + ", " + bank);
- heading *= (Math.PI / 180.0); // Java3d works with radians
- pitch *= (Math.PI / 180.0);
- bank *= (Math.PI / 180.0);
- debugOutputLn(VALUES, "(radians) h, p, b = " + heading + ", " + pitch + ", " + bank);
- debugOutputLn(LINE_TRACE, "got pos and ori");
- xScale = getNumber(st);
- yScale = getNumber(st);
- zScale = getNumber(st);
- debugOutputLn(VALUES, "xs, ys, zs " + xScale +", " + yScale + ", " + zScale);
- frameNumber = (int)getNumber(st);
- // Note: The following spline controls are ignored
- linearValue = (int)getNumber(st);
- debugOutputLn(VALUES, "framenum, linear " + frameNumber + " , " + linearValue);
- tension = getNumber(st);
- continuity = getNumber(st);
- bias = getNumber(st);
- debugOutputLn(VALUES, "tension, cont, bias = " + tension + ", " + continuity + ", " + bias);
- }
-
-
-
- /**
- * Construct new frame that's in-between two given frames
- * Ratio gives the interpolation value for how far in-between
- * the new frame should be (0.5 is half-way, etc)
- */
- LwsFrame(LwsFrame prevFrame, LwsFrame nextFrame, double ratio) {
-
- x = prevFrame.x + (nextFrame.x - prevFrame.x) * ratio;
- y = prevFrame.y + (nextFrame.y - prevFrame.y) * ratio;
- z = prevFrame.z + (nextFrame.z - prevFrame.z) * ratio;
-
- heading = prevFrame.heading +
- (nextFrame.heading - prevFrame.heading) * ratio;
- pitch = prevFrame.pitch +
- (nextFrame.pitch - prevFrame.pitch) * ratio;
- bank = prevFrame.bank +
- (nextFrame.bank - prevFrame.bank) * ratio;
- xScale = prevFrame.xScale +
- (nextFrame.xScale - prevFrame.xScale) * ratio;
- yScale = prevFrame.yScale +
- (nextFrame.yScale - prevFrame.yScale) * ratio;
- zScale = prevFrame.zScale +
- (nextFrame.zScale - prevFrame.zScale) * ratio;
- frameNumber = prevFrame.frameNumber +
- (nextFrame.frameNumber - prevFrame.frameNumber) * ratio;
-
- // The following are not interpolated
- linearValue = prevFrame.linearValue;
- tension = prevFrame.tension;
- continuity = prevFrame.continuity;
- bias = prevFrame.bias;
- }
-
- /**
- * Using hermite interpolation construct a new frame that's
- * in-between two given frames. We also need to be given a
- * frame before the first frame and a frame after the second
- * frame. The calling function will make sure that we get the
- * four appropriate frames.
- *
- * Ratio gives the interpolation value for how far in-between
- * the new frame should be. (.5 is half-way, etc.)
- */
- LwsFrame(LwsFrame prevFrame, LwsFrame frame1,
- LwsFrame frame2, LwsFrame nextFrame, double u,
- double adj0, double adj1) {
-
- double h1, h2, h3, h4;
- double dd0a, dd0b, ds1a, ds1b;
-
- // pre-compute spline coefficients
- double u2, u3, z1;
- u2 = u * u;
- u3 = u2 *u;
- z1 = 3.0f *u2 - u3 - u3;
- h1 = 1.0f - z1;
- h2 = z1;
- h3 = u3 - u2 - u2 + u;
- h4 = u3 - u2;
-
- dd0a = (1.0f - frame1.tension) * (1.0f + frame1.continuity)
- * (1.0f + frame1.bias);
-
- dd0b = (1.0f - frame1.tension) * (1.0f - frame1.continuity)
- * (1.0f - frame1.bias);
-
- ds1a = (1.0f - frame2.tension) * (1.0f - frame2.continuity)
- * (1.0f + frame2.bias);
-
- ds1b = (1.0f - frame2.tension) * (1.0f + frame2.continuity)
- * (1.0f - frame2.bias);
-
- double[] v = new double[4];
-
- // interpolate x, y, z
- v[0] = prevFrame.x; v[1] = frame1.x;
- v[2] = frame2.x; v[3] = nextFrame.x;
- x = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
- adj0, adj1, h1, h2, h3, h4);
- v[0] = prevFrame.y; v[1] = frame1.y;
- v[2] = frame2.y; v[3] = nextFrame.y;
- y = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
- adj0, adj1, h1, h2, h3, h4);
- v[0] = prevFrame.z; v[1] = frame1.z;
- v[2] = frame2.z; v[3] = nextFrame.z;
- z = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
- adj0, adj1, h1, h2, h3, h4);
-
- // interpolate heading pitch and bank
- v[0] = prevFrame.heading; v[1] = frame1.heading;
- v[2] = frame2.heading ; v[3] = nextFrame.heading;
- heading = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
- adj0, adj1, h1, h2, h3, h4);
-
- v[0] = prevFrame.pitch; v[1] = frame1.pitch;
- v[2] = frame2.pitch; v[3] = nextFrame.pitch;
- pitch = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
- adj0, adj1, h1, h2, h3, h4);
-
- v[0] = prevFrame.bank; v[1] = frame1.bank;
- v[2] = frame2.bank; v[3] = nextFrame.bank;
- bank = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
- adj0, adj1, h1, h2, h3, h4);
-
- // interpolate scale - scale interpolation is assumed to be linear
- xScale = frame1.xScale + (frame2.xScale - frame1.xScale) * u;
- yScale = frame1.yScale + (frame2.yScale - frame1.yScale) * u;
- zScale = frame1.zScale + (frame2.zScale - frame1.zScale) * u;
-
- // interpolate frame number
- frameNumber = frame1.frameNumber +
- (frame2.frameNumber - frame1.frameNumber) * u;
-
- // The following are not interpolated
- linearValue = frame2.linearValue;
-
- // We need to keep the spline smooth between knot points
- tension = 0.0;
- continuity = 0.0;
- bias = 0.0;
- }
-
-
- double computeInterpolation(double[] value, double dd0a,
- double dd0b, double ds1a,
- double ds1b, double adj0,
- double adj1, double h1,
- double h2, double h3, double h4) {
-
- double dd0, ds1;
- double delta = value[2] - value[1] ;
- double result;
-
- // if adj != 0
- if (adj0 < -0.0001 || adj0 > 0.0001)
- dd0 = adj0 * (dd0a * (value[1] - value[0]) + dd0b * delta);
- else
- dd0 = 0.5f * (dd0a + dd0b) * delta;
-
- // if adj != 0
- if (adj1 < -0.0001 || adj1 > 0.0001)
- ds1 = adj1 * (ds1a * delta + ds1b * (value[3] - value[2]));
- else
- ds1 = 0.5f * (ds1a + ds1b) * delta;
-
- result = value[1] * h1 + value[2] * h2 + dd0 * h3 + ds1 * h4;
-
- return (result);
- }
-
- double getHeading() {
- return heading;
- }
-
- double getPitch() {
- return pitch;
- }
-
- double getBank() {
- return bank;
- }
-
- /**
- * Sets the given matrix to contain the position, orientation, and
- * scale values for the keyframe
- */
- void setMatrix(Matrix4d mat) {
- setRotationMatrix(mat);
- mat.setTranslation(new Vector3d(x, y, z));
- Matrix4d m = new Matrix4d();
- m.setColumn(0, xScale, 0, 0, 0); // setScale not yet implemented
- m.setColumn(1, 0, yScale, 0, 0);
- m.setColumn(2, 0, 0, zScale, 0);
- m.setColumn(3, 0, 0, 0, 1);
- mat.mul(m);
- }
-
- /**
- * Sets the given matrix to contain the orientation for this keyframe
- */
- void setRotationMatrix(Matrix4d mat)
- {
- debugOutputLn(TRACE, "setRotMat()");
- debugOutputLn(VALUES, " p, h, b = " +
- pitch + ", " +
- heading + ", " +
- bank);
- Matrix4d pitchMat = new Matrix4d();
- pitchMat.rotX(-pitch);
- Matrix4d bankMat = new Matrix4d();
- bankMat.rotZ(bank);
- mat.rotY(-heading);
- mat.mul(pitchMat);
- mat.mul(bankMat);
- debugOutputLn(VALUES, "setRotMat(), mat = " + mat);
- }
-
- Point3f getPosition() {
- return (new Point3f((float)x, (float)y, (float)z));
- }
-
- Point3f getScale() {
- // Make sure we don't have zero scale components
- if ((xScale < -0.0001 || xScale > 0.0001) &&
- (yScale < -0.0001 || yScale > 0.0001) &&
- (zScale < -0.0001 || zScale > 0.0001)) {
- return (new Point3f((float)xScale, (float)yScale, (float)zScale));
- } else {
- return (new Point3f(1.0f, 1.0f, 1.0f));
- }
- }
-
- double getFrameNum() {
- return frameNumber;
- }
-
- void printVals() {
- debugOutputLn(VALUES, " x = " + x);
- debugOutputLn(VALUES, " y = " + y);
- debugOutputLn(VALUES, " z = " + z);
- debugOutputLn(VALUES, " xScale = " + xScale);
- debugOutputLn(VALUES, " yScale = " + yScale);
- debugOutputLn(VALUES, " zScale = " + zScale);
- debugOutputLn(VALUES, " heading = " + heading);
- debugOutputLn(VALUES, " pitch = " + pitch);
- debugOutputLn(VALUES, " bank = " + bank);
- debugOutputLn(VALUES, " frameNum = " + frameNumber);
- debugOutputLn(VALUES, " lin = " + linearValue);
- debugOutputLn(VALUES, " tension = " + tension);
- debugOutputLn(VALUES, " continuity = " + continuity);
- debugOutputLn(VALUES, " bias = " + bias);
- }
-
-}
-
-
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsLight.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwsLight.java
deleted file mode 100644
index bd800dd..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsLight.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-
-
-import java.io.IOException;
-import java.io.StreamTokenizer;
-import java.util.Vector;
-
-import javax.media.j3d.Behavior;
-import javax.media.j3d.BoundingSphere;
-import javax.media.j3d.DirectionalLight;
-import javax.media.j3d.Light;
-import javax.media.j3d.PointLight;
-import javax.media.j3d.SpotLight;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-import javax.vecmath.Color3f;
-import javax.vecmath.Matrix4d;
-import javax.vecmath.Point3d;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3f;
-
-import com.sun.j3d.loaders.ParsingErrorException;
-
-/**
- * This class creates a light object from the data in a Scene file. It
- * instantiates an LwsMotion object to create any associated
- * animations.
- */
-
-class LwsLight extends TextfileParser implements LwsPrimitive {
-
- // data from the file
- String fileName;
- String objName;
- LwsMotion motion;
- int parent;
- TransformGroup objectTransform;
- Vector objectBehavior;
- Color3f color;
- int type;
- Point3f attenuation = new Point3f(1.0f, 0.0f, 0.0f);
- float spotConeAngle = (float)(Math.PI);
- // Meta object, used for holding light and
- LwLightObject lwLight;
- // light parameters
- LwsEnvelopeLightIntensity intensityEnvelope = null;
- Light light = null;
- final static int DIRECTIONAL = 0, POINT = 1, SPOT = 2;
-
- /**
- * Constructor: parses stream and creates data structures for all
- * light parameters currently handled by the loader
- */
- LwsLight(StreamTokenizer st, int totalFrames, float totalTime,
- int debugVals) throws ParsingErrorException {
-
- debugPrinter.setValidOutput(debugVals);
-
- debugOutput(TRACE, "LwsLight()");
- color = new Color3f(1f, 1f, 1f);
- lwLight = new LwLightObject(null, 0.0f, null);
-
- parent = -1;
- debugOutputLn(LINE_TRACE, "about to get LightName");
- getAndCheckString(st, "LightName");
- debugOutputLn(LINE_TRACE, "about to get LightName value");
- objName = getName(st);
- debugOutputLn(LINE_TRACE, "got LightName");
- skip(st, "ShowLight", 2);
- debugOutputLn(LINE_TRACE, "got ShowLight");
- getAndCheckString(st, "LightMotion");
- debugOutputLn(LINE_TRACE, "got LightMotion");
- motion = new LwsMotion(st, totalFrames, totalTime);
- debugOutputLn(LINE_TRACE, "got motions");
-
- // TODO: buggy way to stop processing the light. Should actually
- // process required/optional fields in order and stop when there's
- // no more. However, spec says "ShadowCasing" but the files say
- // "ShadowType".
-
- while (!isCurrentToken(st, "ShowCamera") &&
- !isCurrentToken(st, "AddLight")) {
- // TODO:
- // Things that we're not yet processing (and should):
- // - EdgeAngle: for spotlights, this is the angle which
- // contains the linear falloff toward the edge of the
- // ConeAngle. This doesn't directly map to J3d's
- // "concentration" value, so it's left out for now.
-
- debugOutputLn(LINE_TRACE, "currentToken = " + st.sval);
-
- if (isCurrentToken(st, "ParentObject")) {
- parent = (int)getNumber(st);
- }
- else if (isCurrentToken(st, "LightColor")) {
- color.x = (float)getNumber(st)/255f;
- color.y = (float)getNumber(st)/255f;
- color.z = (float)getNumber(st)/255f;
- lwLight.setColor(color);
- }
- else if (isCurrentToken(st, "LgtIntensity")) {
- // TODO: must be able to handle envelopes here
- String className = getClass().getName();
- int classIndex = className.lastIndexOf('.');
- String packageName;
- if (classIndex < 0)
- packageName = "";
- else
- packageName = className.substring(0, classIndex) + ".";
- EnvelopeHandler env =
- new EnvelopeHandler(st, totalFrames, totalTime,
- packageName + "LwsEnvelopeLightIntensity");
- if (env.hasValue) {
- float intensity = (float)env.theValue;
- color.x *= intensity;
- color.y *= intensity;
- color.z *= intensity;
- lwLight.setIntensity(intensity);
- }
- else {
- intensityEnvelope =
- (LwsEnvelopeLightIntensity)env.theEnvelope;
- }
- }
- else if (isCurrentToken(st, "LightType")) {
- type = (int)getNumber(st);
- }
- else if (isCurrentToken(st, "Falloff")) {
- float falloff = (float)getNumber(st);
- attenuation.y = 1.0f/(1.0f - falloff) - 1.0f;
- }
- else if (isCurrentToken(st, "ConeAngle")) {
- spotConeAngle = (float)getNumber(st) * (float)(Math.PI / 180.0);
- }
- try {
- st.nextToken();
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- }
- st.pushBack(); // push "ShowCamera" or "AddLight" back on stack
- }
-
- int getParent() {
- return parent;
- }
-
- /**
- * Create Java3D objects from the data we got from the file
- */
- void createJava3dObject(int loadBehaviors) {
- Matrix4d mat = new Matrix4d();
- mat.setIdentity();
- // Set the node's transform matrix according to the first frame
- // of the object's motion
- LwsFrame firstFrame = motion.getFirstFrame();
- firstFrame.setMatrix(mat);
- debugOutputLn(VALUES, "Light transform = " + mat);
- Transform3D t1 = new Transform3D();
- t1.set(mat);
- objectTransform = new TransformGroup(t1);
- objectTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- Vector3f defaultDir = new Vector3f(0f, 0f, -1f);
- Point3f defaultPos = new Point3f(0f, 0f, 0f);
-
- switch (type) {
- case DIRECTIONAL:
- light = new DirectionalLight(color, defaultDir);
- break;
- case POINT:
- light = new PointLight(color, defaultPos, attenuation);
- break;
- case SPOT:
- // Note: spotConeAngle in lw3d is half that of Java3d...
- light = new SpotLight(color, defaultPos, attenuation, defaultDir,
- 2 * spotConeAngle, 0.0f);
- break;
- default:
- // Shouldn't get here
- break;
- }
-
- light.setCapability(Light.ALLOW_COLOR_WRITE);
- if (light != null) {
- lwLight.setLight(light);
- BoundingSphere bounds =
- new BoundingSphere(new Point3d(0.0,0.0,0.0), 100000.0);
- light.setInfluencingBounds(bounds);
- objectTransform.addChild(light);
-
- // load behaviors if we have to
- objectBehavior = new Vector();
- if (loadBehaviors != 0) {
- Behavior b;
- b = null;
- motion.createJava3dBehaviors(objectTransform);
- b = motion.getBehaviors();
- if (b != null)
- objectBehavior.addElement(b);
-
- if (intensityEnvelope != null) {
- b = null;
- intensityEnvelope.createJava3dBehaviors(lwLight);
- b = intensityEnvelope.getBehaviors();
- if (b != null)
- objectBehavior.addElement(b);
- }
- }
- }
- }
-
- @Override
- public TransformGroup getObjectNode()
- {
- return objectTransform;
- }
-
- Light getLight() {
- return light;
- }
-
- @Override
- public Vector getObjectBehaviors()
- {
- debugOutputLn(TRACE, "getObjectBehaviors()");
- return objectBehavior;
- }
-
-
- void printVals()
- {
- debugOutputLn(VALUES, " LIGHT vals: ");
- debugOutputLn(VALUES, " objName = " + objName);
- motion.printVals();
- }
-
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsMotion.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwsMotion.java
deleted file mode 100644
index 0aa7304..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsMotion.java
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-import java.io.StreamTokenizer;
-import java.util.Enumeration;
-import java.util.Vector;
-
-import javax.media.j3d.Alpha;
-import javax.media.j3d.Behavior;
-import javax.media.j3d.BoundingSphere;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-import javax.vecmath.Matrix4d;
-import javax.vecmath.Point3d;
-import javax.vecmath.Point3f;
-import javax.vecmath.Quat4f;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-import com.sun.j3d.loaders.IncorrectFormatException;
-import com.sun.j3d.loaders.ParsingErrorException;
-import com.sun.j3d.utils.behaviors.interpolators.KBKeyFrame;
-import com.sun.j3d.utils.behaviors.interpolators.KBRotPosScaleSplinePathInterpolator;
-
-/**
- * This class is responsible for parsing the data in a Scene file related to
- * an object's animation and constructing the appropriate Java3D
- * Behavior objects. For each keyframe defined for the animation in the
- * Lightwave file, this class creates a LwsFrame object to parse that
- * keyframe data and create the appropriate data structures. Then for
- * each of those LwsFrame objects created, LwsMotion creates a knot
- * value for a PathInterpolator and fills in the appropriate field. Finally,
- * the class creates a RotPosScalePathInterpolator with all of the data
- * from the animation. There are also some utility functions in this
- * class for dealing with special cases of animations, such as animations
- * that begin after the first frame of the scene and animations that
- * define frames in a way that Java3D cannot easily interpret.
- */
-
-class LwsMotion extends TextfileParser {
-
- // data from the file
- String motionName;
- LwsFrame frames[];
- int numFrames;
- int numChannels;
- boolean loop;
- float totalTime;
- int firstFrame;
- int totalFrames;
- Behavior behaviors;
-
- /**
- * Constructor
- */
- LwsMotion(StreamTokenizer st, int frames, float time) {
- this(st, 0, frames, time, EXCEPTION);
-
- }
-
- /**
- * Constructor: takes tokenizer, 1st frame of this animation, total
- * number of frames, total time of animation, and the debug settings
- */
- LwsMotion(StreamTokenizer st, int firstFrame,
- int frames, float time, int debugVals)
- throws ParsingErrorException, IncorrectFormatException {
-
- debugPrinter.setValidOutput(debugVals);
- numFrames = 0;
- totalTime = time;
- this.firstFrame = firstFrame;
- totalFrames = frames;
- debugOutputLn(LINE_TRACE, "about to get motion name");
- motionName = getName(st);
- debugOutputLn(LINE_TRACE, "about to get motion");
- getMotion(st);
- }
-
- /**
- * This method parses the tokenizer and creates the data structures
- * that hold the data from that file. For each separate keyframe,
- * this method calls LwsFrame to parse and interpret that data.
- */
- void getMotion(StreamTokenizer st)
- throws ParsingErrorException, IncorrectFormatException
- {
- debugOutputLn(TRACE, "getMotion()");
- numChannels = (int)getNumber(st);
- if (numChannels != 9) {
- throw new IncorrectFormatException(
- J3dUtilsI18N.getString("LwsMotion0"));
- }
- debugOutputLn(LINE_TRACE, "got channels");
-
- numFrames = (int)getNumber(st);
- frames = new LwsFrame[numFrames];
- debugOutputLn(VALUES, "got frames" + numFrames);
-
- for (int i = 0; i < numFrames; ++i) {
- frames[i] = new LwsFrame(st);
- }
-
- debugOutput(LINE_TRACE, "got all frames");
-
- getAndCheckString(st, "EndBehavior");
- int repeatVal = (int)getNumber(st);
- if (repeatVal == 1)
- loop = false;
- else
- loop = true;
-
- // need to make sure frame info is in sycn with j3d
- // fixFrames();
- }
-
- /**
- * The previous version of this method looked for sucessive frames with
- * the same rotation value (mod 2PI). If it found such frames, it would
- * divide that interval into 4 separate frames.
- * This fix is not sufficient for various rotation cases, though. For
- * instance, if the rotation difference between two frames is more than
- * 2PI, the rotation will not case a flag to be fixed and the resulting
- * rotation will only be between the delta of the two rotations, mod 2PI.
- * The real fix should behave as follows:
- * - Iterate through all sucessive frames
- * - For any two frames that have rotation components that differ by more
- * than PI/2 (one quarter rotation - no reason for this, but let's pick a
- * small value to give our resulting path interpolations a better chance
- * of behaving correctly), figure out how many frames we need to create to
- * get increments of <= PI/2 between each frame.
- * - Create these new frames
- * - Set the odl frames pointer to the new frames structures.
- */
-
- void fixFrames() {
-
- boolean addedFrames = false;
- Vector newFramesList = new Vector();
- double halfPI = (float)(Math.PI/2);
- LwsFrame finalFrame = null;
-
- for (int i = 1 ; i < numFrames; ++i) {
- LwsFrame prevFrame;
- LwsFrame lastFrame = frames[i-1];
- LwsFrame thisFrame = frames[i];
- LwsFrame nextFrame;
-
- finalFrame = thisFrame;
- newFramesList.add(lastFrame);
-
- double largestAngleDifference = 0;
- double thisAngle = thisFrame.getHeading();
- double lastAngle = lastFrame.getHeading();
- double angleDifference = Math.abs(thisAngle - lastAngle);
- if (angleDifference > largestAngleDifference)
- largestAngleDifference = angleDifference;
-
- thisAngle = thisFrame.getPitch();
- lastAngle = lastFrame.getPitch();
- angleDifference = Math.abs(thisAngle - lastAngle);
- if (angleDifference > largestAngleDifference)
- largestAngleDifference = angleDifference;
-
- thisAngle = thisFrame.getBank();
- lastAngle = lastFrame.getBank();
- angleDifference = Math.abs(thisAngle - lastAngle);
- if (angleDifference > largestAngleDifference)
- largestAngleDifference = angleDifference;
-
- if (largestAngleDifference > halfPI) {
- // Angles too big - create new frames
- addedFrames = true;
- int numNewFrames = (int)(largestAngleDifference/halfPI);
- double increment = 1.0/(double)(numNewFrames+1);
- double currentRatio = increment;
-
- double totalf = frames[numFrames-1].getFrameNum();
- double tlength = (thisFrame.getFrameNum() -
- lastFrame.getFrameNum())/totalf;
- double adj0;
- double adj1;
-
- // get the previous and next frames
- if ((i-1) < 1) {
- prevFrame = frames[i-1];
- adj0 = 0.0;
- } else {
- prevFrame = frames[i-2];
- adj0 = tlength/((thisFrame.getFrameNum() -
- prevFrame.getFrameNum())/totalf);
- }
-
- if ((i+1) < numFrames) {
- nextFrame = frames[i+1];
- adj1 = tlength/((nextFrame.getFrameNum()-
- lastFrame.getFrameNum())/totalf);
- } else {
- nextFrame = frames[i];
- adj1 = 1.0;
- }
-
- for (int j = 0; j < numNewFrames; ++j) {
-
- LwsFrame newFrame;
-
- // if linear interpolation
- if (thisFrame.linearValue == 1) {
- newFrame = new LwsFrame(lastFrame,
- thisFrame, currentRatio);
-
- // if spline interpolation
- } else {
- newFrame = new LwsFrame(prevFrame, lastFrame,
- thisFrame, nextFrame,
- currentRatio, adj0, adj1);
- }
-
- currentRatio += increment;
- newFramesList.add(newFrame);
- }
- }
- }
-
- // Now add in final frame
- if (finalFrame != null)
- newFramesList.add(finalFrame);
- if (addedFrames) {
-
- // Recreate frames array from newFramesList
- LwsFrame newFrames[] = new LwsFrame[newFramesList.size()];
- Enumeration elements = newFramesList.elements();
- int index = 0;
- while (elements.hasMoreElements()) {
- newFrames[index++] = (LwsFrame)elements.nextElement();
- }
- frames = newFrames;
- numFrames = frames.length;
- for (int i = 0; i < numFrames; ++i) {
- debugOutputLn(VALUES, "frame " + i + " = " + frames[i]);
- frames[i].printVals();
- }
- }
- }
-
- /**
- * Utility for getting integer mod value
- */
- int intMod(int divisee, int divisor) {
- int tmpDiv = divisee;
- int tmpDivisor = divisor;
- if (tmpDiv < 0)
- tmpDiv = -tmpDiv;
- if (tmpDivisor < 0)
- tmpDivisor = -tmpDivisor;
- while (tmpDiv > tmpDivisor) {
- tmpDiv -= tmpDivisor;
- }
- return tmpDiv;
- }
-
- /**
- * Class that associates a particular frame with its effective frame
- * number (which accounts for animations that start after frame 1)
- */
- class FrameHolder {
- double frameNumber;
- LwsFrame frame;
-
- FrameHolder(LwsFrame theFrame, double number) {
- frame = theFrame;
- frameNumber = number;
- }
- }
-
-
- /**
- * This method was added to account for animations that start after
- * the first frame (e.g., Juggler.lws starts at frame 30). We need
- * to alter some of the information for the frames in this "frame subset"
- */
- void playWithFrameTimes(Vector framesVector) {
- debugOutputLn(TRACE, "playWithFrameTimes: firstFrame = " +
- firstFrame);
- if (firstFrame == 1) {
- return;
- }
- else if (frames[numFrames-1].getFrameNum() < totalFrames) {
- // First, create a vector that holds all LwsFrame's in frame
- // increasing order (where order is started at firstFrame Modulo
- // this motion's last frame
- int motionLastFrame =
- (int)(frames[numFrames-1].getFrameNum() + .4999999);
- int newFirstFrame = intMod(firstFrame, motionLastFrame);
- int newLastFrame = intMod(totalFrames, motionLastFrame);
- int index = 0;
- while (index < numFrames) {
- if (frames[index].getFrameNum() >= newFirstFrame)
- break;
- ++index;
- }
- int startIndex = index;
- if (frames[startIndex].getFrameNum() > firstFrame &&
- startIndex > 0)
- startIndex--; // Actually, should interpolate
- index = startIndex;
- if (newFirstFrame < newLastFrame) {
- while (index < numFrames &&
- frames[index].getFrameNum() <= newLastFrame) {
- FrameHolder frameHolder =
- new FrameHolder(frames[index],
- frames[index].getFrameNum() -
- newFirstFrame);
- framesVector.addElement(frameHolder);
- ++index;
- }
- }
- else {
- double currentNewFrameNumber = -1.0;
- while (index < numFrames) {
- currentNewFrameNumber = frames[index].getFrameNum() -
- newFirstFrame;
- FrameHolder frameHolder =
- new FrameHolder(frames[index],
- currentNewFrameNumber);
- framesVector.addElement(frameHolder);
- ++index;
- }
- index = 0;
- while (index <= startIndex &&
- frames[index].getFrameNum() <= newLastFrame) {
- if (index == 0) {
- LwsFrame newFrame =
- new LwsFrame(frames[index],
- frames[index+1],
- 1.0/(frames[index+1].getFrameNum() -
- frames[index].getFrameNum()));
- FrameHolder frameHolder =
- new FrameHolder(newFrame,
- newFrame.getFrameNum() +
- currentNewFrameNumber);
- framesVector.addElement(frameHolder);
- }
- else {
- FrameHolder frameHolder =
- new FrameHolder(frames[index],
- frames[index].getFrameNum() +
- currentNewFrameNumber);
- framesVector.addElement(frameHolder);
- }
- ++index;
- }
- }
- }
- else {
- int index = 0;
- while (index < numFrames) {
- if (frames[index].getFrameNum() >= firstFrame)
- break;
- ++index;
- }
- int startIndex = index;
- if (frames[startIndex].getFrameNum() > firstFrame &&
- startIndex > 0) {
- // Interpolate to first frame
- double ratio = (double)firstFrame /
- (frames[startIndex].getFrameNum() -
- frames[startIndex-1].getFrameNum());
- LwsFrame newFrame = new LwsFrame(frames[startIndex-1],
- frames[startIndex],
- ratio);
- FrameHolder frameHolder =
- new FrameHolder(newFrame, newFrame.getFrameNum() -
- firstFrame);
- framesVector.addElement(frameHolder);
- }
- index = startIndex;
- while (index < numFrames &&
- frames[index].getFrameNum() <= totalFrames) {
- FrameHolder frameHolder =
- new FrameHolder(frames[index],
- frames[index].getFrameNum() -
- firstFrame);
- framesVector.addElement(frameHolder);
- ++index;
- }
- if (frames[index-1].getFrameNum() < totalFrames) {
- // Interpolate to last frame
- double ratio = (double)(totalFrames -
- frames[index-1].getFrameNum()) /
- (frames[index].getFrameNum() -
- frames[index-1].getFrameNum());
- LwsFrame newFrame = new LwsFrame(frames[index-1],
- frames[index],
- ratio);
- FrameHolder frameHolder =
- new FrameHolder(newFrame, totalFrames - firstFrame);
- framesVector.addElement(frameHolder);
- }
- }
- }
-
- /**
- * Normally, we just create j3d behaviors from the frames. But if the
- * animation's first frame is after frame number one, then we have to
- * shuffle things around to account for playing/looping on this subset
- * of the total frames of the animation
- */
- void createJava3dBehaviorsForFramesSubset(TransformGroup target) {
-
- debugOutputLn(TRACE, "createJava3dBehaviorsForFramesSubset");
- Vector frameHolders = new Vector();
- playWithFrameTimes(frameHolders);
- long alphaAtOne = 0;
-
- // determine looping
- int loopCount;
- if (loop)
- loopCount = -1;
- else
- loopCount = 1;
- loopCount = -1;
-
- int numFrames = frameHolders.size();
-
- debugOutputLn(VALUES, "totalTime = " + totalTime);
- debugOutputLn(VALUES, "loopCount = " + loopCount);
-
- FrameHolder lastFrameHolder =
- (FrameHolder)frameHolders.elementAt(frameHolders.size() - 1);
- LwsFrame lastFrame = lastFrameHolder.frame;
- float animTime = 1000.0f * totalTime *
- (float)(lastFrameHolder.frameNumber/(float)(totalFrames -
- firstFrame));
- debugOutputLn(VALUES, " anim time: " + animTime);
- debugOutputLn(VALUES, " totalFrames = " + totalFrames);
-
- if (!loop)
- alphaAtOne = (long)(1000.0*totalTime - animTime);
- Alpha theAlpha =
- new Alpha(loopCount, Alpha.INCREASING_ENABLE,
- 0, 0, (long)animTime, 0,
- alphaAtOne, 0, 0, 0);
-
- float knots[] = new float[numFrames];
- Point3f[] positions = new Point3f[numFrames];
- Quat4f[] quats = new Quat4f[numFrames];
- Point3f[] scales = new Point3f[numFrames];
- Transform3D yAxis = new Transform3D();
- Matrix4d mat = new Matrix4d();
- KBKeyFrame[] keyFrames = new KBKeyFrame[numFrames];
-
- for (int i=0; i < numFrames; ++i) {
-
- FrameHolder frameHolder = (FrameHolder)frameHolders.elementAt(i);
- LwsFrame frame = frameHolder.frame;
-
- // copy position
- positions[i] = frame.getPosition();
-
- // copy scale
- // Used to hardcode no-scale: scales[i] = 1.0f, 1.0f, 1.0f;
- // Note that we can't do non-uniform scaling in the current Path
- // interpolators. The interpolator just uses the x scale.
- // getScale makes sure that we don't have any zero scale component
- scales[i] = frame.getScale();
-
- // copy rotation information
- frame.setRotationMatrix(mat);
- debugOutputLn(VALUES, "LwsMotion::createj3dbeh, mat = " + mat);
- quats[i] = new Quat4f();
- quats[i].set(mat);
- debugOutputLn(VALUES, " and quat = " + quats[i]);
-
- // calculate knot points from frame numbers
- if (i == 0)
- knots[i] = 0.0f;
- else
- knots[i] = (float)(frameHolder.frameNumber)/
- (float)(lastFrameHolder.frameNumber);
-
- // Create KB key frames
- keyFrames[i] = new KBKeyFrame(knots[i], frame.linearValue,
- positions[i],
- (float)frame.heading,
- (float)frame.pitch,
- (float)frame.bank,
- scales[i],
- (float)frame.tension,
- (float)frame.continuity,
- (float)frame.bias);
-
- debugOutputLn(VALUES, "pos, knots, quat = " +
- positions[i] + knots[i] + quats[i]);
- }
-
- // Pass the KeyFrames to the interpolator an let it do its thing
- KBRotPosScaleSplinePathInterpolator b = new
- KBRotPosScaleSplinePathInterpolator(theAlpha,
- target,
- yAxis,
- keyFrames);
- if (b != null) {
- behaviors = b;
- BoundingSphere bounds =
- new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0);
- b.setSchedulingBounds(bounds);
- target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- target.addChild(behaviors);
- }
- }
-
- /**
- * Create j3d behaviors for the data stored in this animation. This is
- * done by creating a RotPosScalePathInterpolator object that contains
- * all of the position, orientation, scale data for each keyframe.
- */
- void createJava3dBehaviors(TransformGroup target) {
-
- if (numFrames <= 1)
- behaviors = null;
- else {
- if (firstFrame > 1) {
- createJava3dBehaviorsForFramesSubset(target);
- return;
- }
-
- long alphaAtOne = 0;
-
- // determine looping
- int loopCount;
- if (loop)
- loopCount = -1;
- else
- loopCount = 1;
- loopCount = -1;
-
- debugOutputLn(VALUES, "totalTime = " + totalTime);
- debugOutputLn(VALUES, "loopCount = " + loopCount);
-
- float animTime = 1000.0f * totalTime *
- (float)(frames[numFrames-1].getFrameNum()/(float)totalFrames);
-
- debugOutputLn(VALUES, " anim time: " + animTime);
- debugOutputLn(VALUES, " totalFrames = " + totalFrames);
- debugOutputLn(VALUES, " lastFrame = " +
- frames[numFrames-1].getFrameNum());
-
- if (!loop)
- alphaAtOne = (long)(1000.0*totalTime - animTime);
- Alpha theAlpha =
- new Alpha(loopCount, Alpha.INCREASING_ENABLE,
- 0, 0, (long)animTime, 0,
- alphaAtOne, 0, 0, 0);
-
- float knots[] = new float[numFrames];
- Point3f[] positions = new Point3f[numFrames];
- Quat4f[] quats = new Quat4f[numFrames];
- Point3f[] scales = new Point3f[numFrames];
- Transform3D yAxis = new Transform3D();
- Matrix4d mat = new Matrix4d();
- KBKeyFrame[] keyFrames = new KBKeyFrame[numFrames];
-
- for (int i=0; i < numFrames; ++i) {
-
- // copy position
- positions[i] = frames[i].getPosition();
-
- // copy scale
- // Used to hardcode no-scale: scales[i] = 1.0f, 1.0f, 1.0f;
- // Note that we can't do non-uniform scaling in the current Path
- // interpolators. The interpolator just uses the x scale.
- // getScale makes sure that we don't have any 0 scale component
- scales[i] = frames[i].getScale();
-
- // copy rotation information
- frames[i].setRotationMatrix(mat);
- debugOutputLn(VALUES, "LwsMotion::createj3dbeh, mat = " + mat);
- quats[i] = new Quat4f();
- quats[i].set(mat);
- debugOutputLn(VALUES, " and quat = " + quats[i]);
-
- // calculate knot points from frame numbers
- if (i == 0)
- knots[i] = 0.0f;
- else
- knots[i] = (float)(frames[i].getFrameNum())/
- (float)(frames[numFrames-1].getFrameNum());
-
- // Create KB key frames
- keyFrames[i] = new KBKeyFrame(knots[i],frames[i].linearValue,
- positions[i],
- (float)frames[i].heading,
- (float)frames[i].pitch,
- (float)frames[i].bank,
- scales[i],
- (float)frames[i].tension,
- (float)frames[i].continuity,
- (float)frames[i].bias);
-
-
- debugOutputLn(VALUES, "pos, knots, quat = " +
- positions[i] + knots[i] + quats[i]);
- }
-
- // Pass the KeyFrames to the interpolator an let it do its thing
- KBRotPosScaleSplinePathInterpolator b = new
- KBRotPosScaleSplinePathInterpolator(theAlpha,
- target,
- yAxis,
- keyFrames);
- if (b != null) {
- behaviors = b;
- BoundingSphere bounds =
- new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0);
- b.setSchedulingBounds(bounds);
- target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- target.addChild(behaviors);
- }
- }
-
- }
-
- /**
- * Returns the Behavior object created for this animation
- */
- Behavior getBehaviors() {
- return behaviors;
- }
-
- /**
- * Returns the first LwsFrame object (which contains the initial
- * setup for a given object)
- */
- LwsFrame getFirstFrame() {
- if (numFrames > 0)
- return frames[0];
- else
- return null;
- }
-
- /**
- * Utility function for printing values
- */
- void printVals() {
- debugOutputLn(VALUES, " motionName = " + motionName);
- debugOutputLn(VALUES, " numChannels = " + numChannels);
- debugOutputLn(VALUES, " numFrames = " + numFrames);
- debugOutputLn(VALUES, " loop = " + loop);
- for (int i = 0; i < numFrames; ++i) {
- debugOutputLn(VALUES, " FRAME " + i);
- frames[i].printVals();
- }
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsObject.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwsObject.java
deleted file mode 100644
index 555655e..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsObject.java
+++ /dev/null
@@ -1,573 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.StreamTokenizer;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import javax.media.j3d.Behavior;
-import javax.media.j3d.Group;
-import javax.media.j3d.Shape3D;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-import javax.vecmath.Matrix4d;
-import javax.vecmath.Vector3f;
-
-import com.sun.j3d.loaders.IncorrectFormatException;
-import com.sun.j3d.loaders.ParsingErrorException;
-
-/**
- * An LwsObject is passed a handle to the text file that contains the scene
- * and is responsible for parsing a particular section of that file that
- * describes a single object. This section defines the type of object
- * (either a group or some geometry specified by an Object file) and
- * some keyframe data that describes the an animation of the
- * orientation/position/scale of the object. For geometry objects, this
- * class instantiates a J3dLwoParser object to parse the binary data file.
- * For the keyframe data, the class instantiates an LwsMotion object to
- * parse and store that data.
- */
-
-class LwsObject extends TextfileParser implements LwsPrimitive {
-
- // data from the file
- String fileName;
- String objName;
- LwsMotion motion;
- int parent;
- TransformGroup objectTransform;
- Vector objectBehavior;
- Vector shapeList = null;
- boolean hasPivot = false;
- TransformGroup pivotTransGroup = null;
-
- URL urlName;
- String protocol;
- int fileType;
-
- /**
- * Constructor: parses object section of this scene file and
- * creates all appropriate data structures to hold the information
- * @param st StreamTokenizer for scene file
- * @param loadObject boolean specifying that object is not a lw3d Null
- * object
- * @param firstFrame int holding the first frame of the scene's animation
- * @param totalFrames int holding the total number of frames in the scene
- * @param totalTime float holding the total time of the animation
- * @param loader Lw3dLoader loader object that was created by user
- * @param debugVals in holding current debug flags
- */
- LwsObject(StreamTokenizer st, boolean loadObject,
- int firstFrame, int totalFrames, float totalTime,
- Lw3dLoader loader, int debugVals)
- throws java.io.FileNotFoundException,
- ParsingErrorException {
- debugPrinter.setValidOutput(debugVals);
- parent = -1;
-
- fileType = loader.getFileType();
-
- try {
- if (loadObject) {
- // If this is true, then the object is actually described
- // in an external geometry file. Get that filename
- fileName = getString(st);
- String path = null;
- switch (loader.getFileType()) {
- case Lw3dLoader.FILE_TYPE_FILENAME:
- // No other case is current implemented in this loader
- path = loader.getBasePath();
- if (path == null)
- path = loader.getInternalBasePath();
- if (path != null) {
- // It's not sufficient to just use the base path.
- // Lightwave scene files tend to embed path names
- // to object files that are only correct if you
- // start from a certain directory. For example, a
- // scene file in data/ may point to an object in
- // data/Objects - but in this case
- // getInternalBasePath() would be data/, so you'd
- // look for the object in data/data/Objects...
- // To attempt to overcome this confusing state of
- // affairs, let's check path/filename
- // first, then iterate all the way up the path
- // until there are no more members of path. This
- // will ensure that we'll at least pick up data
- // files if they exist off of one of the parent
- // directories of wherever the scene file is
- // stored.
- // No, I don't really like this solution, but I don't
- // know of a better general approach for now...
-
- fileName = getQualifiedFilename(path, fileName);
- }
- break;
- case Lw3dLoader.FILE_TYPE_URL:
- path = "";
- URL pathUrl = loader.getBaseUrl();
- if (pathUrl != null) {
- path = pathUrl.toString();
- // store the protocol
- protocol = pathUrl.getProtocol();
- }
- else {
- path = loader.getInternalBaseUrl();
- // store the protocol
- protocol = (new URL(path)).getProtocol();
- }
-
- urlName = getQualifiedURL(path, fileName);
- break;
- }
- }
- else
- // else the object is a lw3d Null object; essentially a group
- // which contains other objects
- objName = getString(st);
- skip(st, "ShowObject", 2);
- debugOutputLn(LINE_TRACE,
- "skipped showobject, about to get objectmotion");
- getAndCheckString(st, "ObjectMotion");
- debugOutputLn(LINE_TRACE, "got string " + st.sval);
- // Create an LwsMotion object to parse the animation data
- motion = new LwsMotion(st, firstFrame, totalFrames,
- totalTime, debugVals);
- debugOutputLn(LINE_TRACE, "got motion");
- boolean hasParent = false; // keeps bones prim from reassigning par
-
- // TODO: This isn't the greatest way to stop parsing an object
- // (keying on the ShowOptions parameter), but it seems to be valid
- // for the current lw3d format
- while (!isCurrentToken(st, "ShadowOptions")) {
- if (!hasParent &&
- isCurrentToken(st, "ParentObject")) {
- parent = (int)getNumber(st);
- hasParent = true;
- }
- else if (isCurrentToken(st, "PivotPoint")) {
- // PivotPoint objects are tricky - they make the object
- // rotate about this new point instead of the default
- // So setup transform groups such that this happens
- // correctly.
- hasPivot = true;
- float x = (float)getNumber(st);
- float y = (float)getNumber(st);
- float z = (float)getNumber(st);
- Vector3f pivotPoint = new Vector3f(-x, -y, z);
- Transform3D pivotTransform = new Transform3D();
- pivotTransform.set(pivotPoint);
- pivotTransGroup = new TransformGroup(pivotTransform);
- pivotTransGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- }
-
- else if (isCurrentToken(st, "ObjDissolve")) {
- // Just handle it for now, don't care about value
- EnvelopeHandler env =
- new EnvelopeHandler(st, totalFrames, totalTime);
- }
- st.nextToken();
- }
- getNumber(st); // skip shadow options parameter
- debugOutputLn(LINE_TRACE, "done with LwsObject constructor");
- }
- catch (MalformedURLException e) {
- throw new FileNotFoundException(e.getMessage());
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- catch (NumberFormatException e) {
- throw new ParsingErrorException("Expected a number, got " +
- e.getMessage());
- }
- }
-
- /**
- * This method takes the given path and filename and checks whether
- * that file exists. If not, it chops off the last part of pathname
- * and recurse to try again. This has the effect of searching all the
- * way up a given pathname for the existence of the file anywhere
- * along that path. This is somewhat of a hack to get around the
- * constraining way that Lightwave uses to define its data object
- * locations in its scene files.
- *
- * If the filename is absolute, it will use the path information from
- * the filename first, then the path information from the lws file.
- * If the file can not be found in these locations, the local directory
- * will be searched.
- * In addition, it will look for filenames converted to lowercase to
- * make it easier to use between Windows and Unix.
- */
-
- String getQualifiedFilename(String pathname, String filename)
- throws java.io.FileNotFoundException {
-
- int index;
- String pathname2 = "";
-
- // System.out.println ("pathname:"+pathname+" filename:"+filename);
-
- // Do we have an absolute filename ?
- if (filename.indexOf (File.separator) == 0) {
- if ((index = filename.lastIndexOf (File.separator)) != -1) {
- pathname2 = filename.substring (0, index+1);
- filename = filename.substring (index+1);
- }
- else {
- return null; // something out of the ordinary happened
- }
- }
-
- // See if we can find the file
- // ---------------------------
-
- // Try pathname from absolute filename
- try {
- if (new File(pathname2 + filename).exists()) {
- return (pathname2 + filename);
- }
- }
- catch (NullPointerException ex) {
- ex.printStackTrace();
- }
- // Try lowercase filename
- if (new File(pathname2 + filename.toLowerCase()).exists()) {
- return (pathname2 + filename.toLowerCase());
- }
-
- // Try original pathname
- if (new File(pathname + filename).exists()) {
- return (pathname + filename);
- }
- // Try lowercase filename
- if (new File(pathname + filename.toLowerCase()).exists()) {
- return (pathname + filename.toLowerCase());
- }
-
- // Finally, let's check the local directory
- if (new File(filename).exists()) {
- return (filename);
- }
- // Try lowercase filename
- if (new File(filename.toLowerCase()).exists()) {
- return (filename.toLowerCase());
- }
-
- // Conditions that determine when we give up on the recursive search
- if ((pathname.equals(File.separator)) ||
- (pathname == null) ||
- (pathname.equals(""))) {
-
- throw new java.io.FileNotFoundException(filename);
- }
-
- // Try to find the file in the upper directories
- // Chop off the last directory from pathname and recurse
- StringBuffer newPathName = new StringBuffer(128);
- StringTokenizer st = new StringTokenizer(pathname, File.separator);
- int tokenCount = st.countTokens() - 1;
- if (pathname.startsWith(java.io.File.separator))
- newPathName.append(File.separator);
- for (int i = 0; i < tokenCount; ++i) {
- String directory = st.nextToken();
- newPathName.append(directory);
- newPathName.append(File.separator);
- }
-
- String newPath = newPathName.toString();
- return getQualifiedFilename(newPath, filename);
- }
-
- URL getQualifiedURL(String path, String file)
- throws MalformedURLException {
-
- URL url = null;
-
- // try the path and the file -- this is the lightwave spec
- try {
- // create url
- url = new URL(path + file);
- // see if file exists
- url.getContent();
- // return url if no exception is thrown
- return url;
- }
- catch (IOException e) {
- // Ignore - try something different
- }
-
- // try a couple other options, but trying to open connections is slow,
- // so don't try as many options as getQualifiedFilename
-
- // try absolute path
- try {
- url = new URL(file);
- url.getContent();
- }
- catch (IOException ex) {
- // Ignore - try something different
- }
-
- // try the absolute path with the protocol
- try {
- url = new URL(protocol + ":" + file);
- url.getContent();
- return url;
- }
- catch (IOException ex) {
- // Nothing else to try so give up
- throw new MalformedURLException(path + file);
- }
- }
-
- /**
- * Returns parent object
- */
- int getParent() {
- return parent;
- }
-
- /**
- * Adds the given child to the transform of this node (its parent).
- */
- void addChild(LwsPrimitive child) {
- debugOutputLn(TRACE, "addChild()");
- if (objectTransform != null) {
- debugOutputLn(LINE_TRACE, "objectTransform = " + objectTransform);
- if (child.getObjectNode() != null) {
- debugOutputLn(LINE_TRACE, "child has object node");
- if (hasPivot)
- pivotTransGroup.addChild(child.getObjectNode());
- else
- objectTransform.addChild(child.getObjectNode());
- }
-/*
- if (child.getObjectBehaviors() != null) {
- debugOutputLn(LINE_TRACE, "child has behaviors");
- Group bg = child.getObjectBehaviors();
- debugOutputLn(VALUES, " child behaviors = " + bg);
- // TODO: should remove intermediate group nodes
- objectBehavior.addChild(bg);
- }
-*/
- }
- }
-
- /**
- * Creates Java3d objects from the data stored for this object.
- * The objects created consist of: A TransformGroup that holds the
- * transform specified by the first keyframe, a Behavior that acts
- * on the TransformGroup if there are more than 1 keyframes, and
- * some geometry (created by J3dLwoParser) from an external geometry
- * file (if the object wasn't an lw3d Null object (group)).
- */
- void createJava3dObject(LwsObject cloneObject, int loadBehaviors)
- throws IncorrectFormatException, ParsingErrorException,
- FileNotFoundException
- {
- String seqToken = new String("_sequence_");
- Matrix4d mat = new Matrix4d();
- mat.setIdentity();
- // Set the node's transform matrix according to the first frame
- // of the object's motion
- LwsFrame firstFrame = motion.getFirstFrame();
- firstFrame.setMatrix(mat);
- Transform3D t1 = new Transform3D();
- t1.set(mat);
- objectTransform = new TransformGroup(t1);
- objectTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
-
- // This following bit is a hack and should probably be removed.
- // It was put in here in order to handle the "Tloop" functionality
- // of holosketch, which was needed for the 1998 Javaone conference
- // (the HighNoon demo, in particular). Having the code here, or
- // using it, means that some object file names are tagged as special
- // because they contain the phrase "_sequence_", which tells this
- // object file reader that that object file is, in fact, a
- // sequence file. It then creates a SequenceReader object to
- // read that file and create an animation from the objects defined
- // in that file.
- // See SequenceReader.java for more information on this.
- // By the way, a better/fuller implementation of this functionality
- // would involve investigating a standard Plug-In for Lightwave
- // that allows the writing out of sequence files from Bones data.
- // i think it would be better to base any Tloop stuff on that
- // standard than on some proprietary hack of our own.
-
- if (fileName != null && fileName.indexOf(seqToken) != -1) { // Tloop
-
- int index = fileName.indexOf(seqToken);
- index += seqToken.length();
- String seqFilename = fileName.substring(index);
- int endIndex = seqFilename.indexOf(".lwo");
- if (endIndex != -1)
- seqFilename = seqFilename.substring(0, endIndex);
- if ((new File(seqFilename)).exists()) {
- SequenceReader sr =
- new SequenceReader(seqFilename,
- motion.totalTime,
- (int)motion.totalFrames);
- sr.printLines();
- sr.createJava3dObjects(debugPrinter.getValidOutput(),
- loadBehaviors);
- Group g = sr.getObjectNode();
- if (g != null)
- objectTransform.addChild(g);
-
- // Sequence reader's getObjectBehaviors creates new Vector
- objectBehavior = sr.getObjectBehaviors();
-
- return;
- }
- }
-
- // Okay, now that that hack is out of the way, let's get on with
- // "normal" Lightwave object files.
- if (fileName != null || urlName != null) {
- // If this object refers to an obj file, load it and create
- // geometry from it.
- if (cloneObject == null) {
- debugOutputLn(VALUES,
- "About to load binary file for " + fileName);
- // Create a J3dLwoParser object to parse the geometry file
- // and create the appropriate geometry
- J3dLwoParser objParser = null;
- switch (fileType) {
- case Lw3dLoader.FILE_TYPE_FILENAME:
- objParser =
- new J3dLwoParser(fileName,
- debugPrinter.getValidOutput());
- break;
- case Lw3dLoader.FILE_TYPE_URL:
- objParser = new J3dLwoParser(urlName,
- debugPrinter.getValidOutput());
- break;
- }
- objParser.createJava3dGeometry();
- // pivot points change the parent transform
- if (hasPivot) {
- objectTransform.addChild(pivotTransGroup);
- }
- if (objParser.getJava3dShapeList() != null) {
- shapeList = objParser.getJava3dShapeList();
- for (Enumeration e = shapeList.elements() ;
- e.hasMoreElements() ;) {
- if (!hasPivot || pivotTransGroup == null)
- objectTransform.addChild((Shape3D)e.nextElement());
- else
- pivotTransGroup.addChild((Shape3D)e.nextElement());
- }
- }
- }
- else {
- // Already read that file: Clone original object
- debugOutputLn(LINE_TRACE, "Cloning shapes");
- Vector cloneShapeList = cloneObject.getShapeList();
- for (Enumeration e = cloneShapeList.elements() ;
- e.hasMoreElements() ;) {
- debugOutputLn(LINE_TRACE, " shape clone");
- Shape3D shape = (Shape3D)e.nextElement();
- Shape3D cloneShape = (Shape3D)shape.cloneTree();
- objectTransform.addChild(cloneShape);
- }
- }
- }
-
- // Create j3d behaviors for the object's animation
- objectBehavior = new Vector();
- if (loadBehaviors != 0) {
- motion.createJava3dBehaviors(objectTransform);
- Behavior b = motion.getBehaviors();
- if (b != null)
- objectBehavior.addElement(b);
- }
- }
-
- /**
- * Return list of Shape3D objects for this object file. This is used
- * when cloning objects (if the scene file requests the same object file
- * more than once, that object will be cloned instead of recreated each
- * time).
- */
- Vector getShapeList() {
- return shapeList;
- }
-
- /**
- * Return the TransformGroup that holds this object file
- */
- @Override
- public TransformGroup getObjectNode() {
- return objectTransform;
- }
-
- /**
- * Return the Group that holds this object's behaviors. The behaviors
- * are grouped separately from the geometry so that they can be handled
- * differently by the parent application.
- */
- @Override
- public Vector getObjectBehaviors()
- {
- debugOutputLn(TRACE, "getObjectBehaviors()");
- return objectBehavior;
- }
-
-
- /**
- * Utiliy function to print some of the object values. Used in
- * debugging.
- */
- void printVals()
- {
- debugOutputLn(VALUES, " OBJECT vals: ");
- debugOutputLn(VALUES, " fileName = " + fileName);
- debugOutputLn(VALUES, " objName = " + objName);
- motion.printVals();
- }
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsPrimitive.java b/src/classes/share/com/sun/j3d/loaders/lw3d/LwsPrimitive.java
deleted file mode 100644
index f80d795..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/LwsPrimitive.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-
-
-import java.util.Vector;
-
-import javax.media.j3d.TransformGroup;
-
-/**
- * This is an interface which is implemented by LwsObject,
- * LwsFog, LwsBackground, LwsLight, etc. It provides a generic method
- * for objects to access some of the common data in these classes.
- */
-
-interface LwsPrimitive {
-
- // interface from which other Lws types (Object, Camera, etc.)
- // inherit methods
-
- public Vector getObjectBehaviors();
-
- public TransformGroup getObjectNode();
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/ParserObject.java b/src/classes/share/com/sun/j3d/loaders/lw3d/ParserObject.java
deleted file mode 100644
index 95e1453..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/ParserObject.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-/**
- * This class is a superclass of the binary parsing classes. It provides
- * some basic debugging utilities.
- */
-
-class ParserObject {
-
-
- final static int TRACE = DebugOutput.TRACE, VALUES = DebugOutput.VALUES;
- final static int MISC = DebugOutput.MISC, LINE_TRACE = DebugOutput.LINE_TRACE;
- final static int NONE = DebugOutput.NONE, EXCEPTION = DebugOutput.EXCEPTION;
- final static int TIME = DebugOutput.TIME, WARNING = DebugOutput.WARNING;
-
- protected DebugOutput debugPrinter;
-
-
- ParserObject() {
- debugPrinter = new DebugOutput(EXCEPTION);
- }
-
- ParserObject(int debugVals) {
- this();
- debugPrinter.setValidOutput(debugVals);
- }
-
-
- protected void debugOutputLn(int outputType, String theOutput) {
- if (theOutput.equals(""))
- debugPrinter.println(outputType, theOutput);
- else
- debugPrinter.println(outputType,
- getClass().getName() + "::" + theOutput);
- }
-
- protected void debugOutput(int outputType, String theOutput) {
- debugPrinter.print(outputType, theOutput);
- }
-
-
-
-}
-
-
-
-
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceLine.java b/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceLine.java
deleted file mode 100644
index 8629c7e..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceLine.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.StreamTokenizer;
-import java.util.Enumeration;
-import java.util.Hashtable;
-
-import javax.media.j3d.Alpha;
-import javax.media.j3d.Behavior;
-import javax.media.j3d.BoundingSphere;
-import javax.media.j3d.Group;
-import javax.media.j3d.Link;
-import javax.media.j3d.Shape3D;
-import javax.media.j3d.SharedGroup;
-import javax.media.j3d.Switch;
-import javax.media.j3d.SwitchValueInterpolator;
-import javax.media.j3d.TransformGroup;
-import javax.vecmath.Point3d;
-
-import com.sun.j3d.loaders.IncorrectFormatException;
-import com.sun.j3d.loaders.ParsingErrorException;
-
-/**
- * This class was created to handle "sequence files", which allow
- * holosketch-type Tloop sequences to be loaded through the lw3d loader.
- * The class reads a sequence file line by line and uses SequenceLine to
- * load the file specified in each line.
- * Idea behind the Tloop process:
- * Artist creates "tloops" (animations with each keyframe's
- * geometry saved out explicitly) where the geometries are spaced
- * one frame apart. Then I can automatically create a SwitchValueInterpolator
- * based on this spacing. If the number of frames in the sequence is
- * greater than the number of frames in the tloop, then it will automatically
- * loop until the end of the sequence.
- * Process:
- * 1) Artist creates an animation of a null group that has a child with some
- * special name, such as "bucket_sequence_bucketsequence.txt.lwo", which tells
- * the lw3d loader that it should look for a sequence file by the name of
- * bucketsequence.txt. What happens to this object is irrelevant (as far as
- * the loader is concerned); all animation information is taken from its
- * parent instead.
- * 2) Artist saves out the geometry of the bucket at whatever frames she wants
- * to. If she's saving a tloop (a sequence of frames), she should save them
- * under the names
- * 3) Artist creates the sequence file, which lists all saved geometry files
- * (except sequences - these can be referred to simply by the first file
- * (...000.lwo)), along with their associated start/end frames. She also lists
- * the number of files in the sequence, although this parameter is implied
- * anyway, through the existence of the sequence files and their naming
- * convention. Maybe we should trash this guy.
- * 4) In the lw3d loader, when LwsObject encounters an object with the
- * filename "..._sequence_
- * 5) Each SequenceLine creates a Java3D group containing its objects. This
- * is either a plain-old-Group (if there is only one object) or a Switch group
- * with a SwitchValueInterpolator.
- * 6) SequenceReader constructs a Switch group and adds all SequenceLine groups
- * to this new group. It also creates a SwitchPathInterpolator (child of
- * PathInterolator) that contsructs an Alpha based on the startFrame values of
- * each SequenceLine. It creates a group and adds the SwitchPathInterpolator
- * plus any SequenceLine SwitchValueInterpolators to this group.
- * 7) LwsObject adds the SequenceReader Switch group to its objectTransform.
- * It does a getBehaviors() from SequenceReader and adds the result (the
- * SwitchPathInterpolator group) to its objectBehaviors group.
- * 8) Done.
- */
-
-class SequenceLine {
-
- int startFrame;
- int endFrame;
- String fileName;
-
- Group geometryGroup = null;
- Behavior behaviors;
- int numFrames;
- float totalTime;
- int totalFrames;
-
- // storedRefList keeps references to already loaded objects
- static Hashtable storedRefList = new Hashtable();
-
- SequenceLine(StreamTokenizer st, float time, int frames)
- throws ParsingErrorException {
- try {
- totalTime = time;
- totalFrames = frames;
- startFrame = (int)st.nval;
- st.nextToken();
- endFrame = (int)st.nval;
- st.nextToken();
- fileName = st.sval;
- numFrames = endFrame - startFrame + 1;
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- }
-
- /**
- * Creates a SwitchValueInterpolator which is used to switch between
- * the objects specified for the sequence. This is done for files
- * that end in "000", meaning that there are a sequence of files
- * with that same base name that should specify every frame of a
- * sequence for an object. The Switch node is used to hold all of the
- * files and the Switch Behavior node is used to activate switching
- * at the right time and to the right object.
- */
- private void createSwitchBehavior(Switch target) {
-
- int loopCount = -1;
- float animTime = 1000.0f * totalTime *
- (float)(target.numChildren())/(float)totalFrames;
- float startTime = 1000f * totalTime *
- (float)startFrame/(float)totalFrames;
- Alpha theAlpha =
- new Alpha(-1, (long)startTime, 0, (long)animTime, 0, 0);
-
- SwitchValueInterpolator b=new SwitchValueInterpolator(theAlpha,target);
- behaviors = b;
- BoundingSphere bounds =
- new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0);
- b.setSchedulingBounds(bounds);
- target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- target.addChild(behaviors);
-
- }
-
- /**
- * Create Java3d objects from the data in the sequence line. This
- * means that for a tloop file (ends in "000"), we're going to create
- * the appropriate geometry for each file, put them all in a Switch
- * node, then create a SwitchValueInterpolator to swap between the
- * frames of the tloop. If it's not a tloop, then we're just going to
- * create the geometry for that file.
- */
- void createJava3dObjects(int debugVals, int loadBehaviors)
- throws IncorrectFormatException, FileNotFoundException {
- if (fileName.indexOf("000") != -1) { // Tloop
- int index = fileName.indexOf("000");
- String fileNameBase = fileName.substring(0, index);
- Switch s = new Switch();
- s.setCapability(Switch.ALLOW_SWITCH_READ);
- s.setCapability(Switch.ALLOW_SWITCH_WRITE);
- String tempFileName = fileName;
- int fileNum = 0;
- while ((new File(tempFileName)).exists()) {
- if (storedRefList.get(tempFileName) != null) {
- // System.out.println("retrieve stored version of " +
- // tempFileName);
- SharedGroup storedGroup =
- (SharedGroup)storedRefList.get(tempFileName);
- Link newLink = new Link(storedGroup);
- s.addChild(newLink);
- }
- else {
- // System.out.println("reading " + tempFileName);
- J3dLwoParser objParser = new J3dLwoParser(tempFileName,
- debugVals);
- objParser.createJava3dGeometry();
- TransformGroup t = new TransformGroup();
- SharedGroup newSharedGroup = new SharedGroup();
- storedRefList.put(tempFileName, newSharedGroup);
- newSharedGroup.addChild(t);
- Link newLink = new Link(newSharedGroup);
- s.addChild(newLink);
- if (objParser.getJava3dShapeList() != null) {
- for (Enumeration e =
- objParser.getJava3dShapeList().elements() ;
- e.hasMoreElements() ;) {
- t.addChild((Shape3D)e.nextElement());
- }
- }
- }
- ++fileNum;
- String fileNumString = String.valueOf(fileNum);
- if (fileNum < 10)
- fileNumString = "00" + fileNumString;
- else if (fileNum < 100)
- fileNumString = "0" + fileNumString;
- tempFileName = fileNameBase + fileNumString + ".lwo";
- }
- behaviors = null;
- if (loadBehaviors != 0) {
- createSwitchBehavior(s);
- }
- geometryGroup = (Group)s;
- }
- else {// Not a tloop, just a file
- geometryGroup = new Group();
- if (storedRefList.get(fileName) != null) {
- // System.out.println("getting old ref to " + fileName);
- SharedGroup storedGroup =
- (SharedGroup)storedRefList.get(fileName);
- Link newLink = new Link(storedGroup);
- geometryGroup.addChild(newLink);
- }
- else {
- // System.out.println("reading " + fileName);
- J3dLwoParser objParser = new J3dLwoParser(fileName,
- debugVals);
- objParser.createJava3dGeometry();
- TransformGroup t = new TransformGroup();
- if (objParser.getJava3dShapeList() != null) {
- for (Enumeration e = objParser.getJava3dShapeList().elements() ;
- e.hasMoreElements() ;) {
- t.addChild((Shape3D)e.nextElement());
- }
- }
- SharedGroup newSharedGroup = new SharedGroup();
- newSharedGroup.addChild(t);
- Link newLink = new Link(newSharedGroup);
- geometryGroup.addChild(newLink);
- storedRefList.put(fileName, newSharedGroup);
- }
- }
- }
-
- Group getGeometry() {
- return geometryGroup;
- }
-
- Behavior getBehavior() {
- return behaviors;
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceReader.java b/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceReader.java
deleted file mode 100644
index ac79dff..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/SequenceReader.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-import java.io.BufferedReader;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.StreamTokenizer;
-import java.util.Enumeration;
-import java.util.Vector;
-
-import javax.media.j3d.Alpha;
-import javax.media.j3d.BoundingSphere;
-import javax.media.j3d.Switch;
-import javax.media.j3d.TransformGroup;
-import javax.vecmath.Point3d;
-
-import com.sun.j3d.loaders.ParsingErrorException;
-
-/**
- * This class was created to read a special file format devised for
- * JavaOne '98 that allowed Tloop functionality inside of Lightwave. It
- * would be best to find a more standard solution, including using some
- * plug-in for lw3d that I've heard of that allows artists to automatically
- * save out the geometry for a file at every frame.
- */
-
-class SequenceReader {
-
-
- Vector sequenceLines;
- float totalTime;
- int totalFrames;
-
- TransformGroup objectTransform;
- Vector behaviorVector;
-
- /**
- * Constructor: parses a sequence file and creates a new SequenceLine
- * object to read in every line of the file
- */
- SequenceReader(String filename, float time, int frames)
- throws ParsingErrorException {
- totalTime = time;
- totalFrames = frames;
- sequenceLines = new Vector();
- try {
- // System.out.println("reading sequence from " + filename);
- StreamTokenizer st = new StreamTokenizer(new BufferedReader(
- new FileReader(filename)));
- st.wordChars('_', '_');
- st.wordChars('/', '/');
- int type = st.nextToken();
- while (st.ttype != StreamTokenizer.TT_EOF) {
- sequenceLines.addElement(new SequenceLine(st,
- totalTime,
- totalFrames));
- st.nextToken();
- }
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- }
-
- /**
- * Creates Java3D objects from the data defined in the sequence
- * file. Calls each sequenceLine object to create its own
- * j3d objects, then puts all of those objects in a single Switch
- * node. Finally, it creates a SwitchPathInterpolator object which
- * handles switching between each object/s defined by each line
- */
- void createJava3dObjects(int debugVals, int loadBehaviors)
- throws FileNotFoundException {
-
- objectTransform = new TransformGroup();
- behaviorVector = new Vector();
- Enumeration e = sequenceLines.elements();
- Switch switchNode = new Switch();
- switchNode.setCapability(Switch.ALLOW_SWITCH_READ);
- switchNode.setCapability(Switch.ALLOW_SWITCH_WRITE);
- objectTransform.addChild(switchNode);
- while (e.hasMoreElements()) {
- SequenceLine line = (SequenceLine)e.nextElement();
- line.createJava3dObjects(debugVals, loadBehaviors);
- if (line.getGeometry() != null)
- switchNode.addChild(line.getGeometry());
- //objectTransform.addChild(line.getGeometry());
- if (line.getBehavior() != null) {
- behaviorVector.addElement(line.getBehavior());
- }
- }
- float knots[] = new float[sequenceLines.size() + 1];
- for (int i = 0; i < knots.length-1; ++i) {
- SequenceLine sl = (SequenceLine)sequenceLines.elementAt(i);
- knots[i] = (float)sl.startFrame/(float)totalFrames;
- }
- knots[knots.length-1] = 1.0f;
- Alpha theAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE,
- 0, 0, (long)(1000f * totalTime), 0,
- 0, 0, 0, 0);
-
- SwitchPathInterpolator switchPath =
- new SwitchPathInterpolator(theAlpha,
- knots,
- switchNode);
- BoundingSphere bounds =
- new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0);
- switchPath.setSchedulingBounds(bounds);
- switchNode.addChild(switchPath);
- behaviorVector.addElement(switchPath);
- }
-
- TransformGroup getObjectNode() {
- return objectTransform;
- }
-
- Vector getObjectBehaviors() {
- return behaviorVector;
- }
-
- void printLines() {
- Enumeration e = sequenceLines.elements();
- while (e.hasMoreElements()) {
- SequenceLine line = (SequenceLine)e.nextElement();
- }
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/ShapeHolder.java b/src/classes/share/com/sun/j3d/loaders/lw3d/ShapeHolder.java
deleted file mode 100644
index 70d2d5f..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/ShapeHolder.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-import java.util.Vector;
-
-import javax.vecmath.Vector3f;
-
-
-/**
- * This class holds all of the vertex/facet/normal/surface-reference
- * data for a particular object. It has utilities to calculate facet normals,
- * but this is no longer in use since using the new GeomInfo utilities.
- */
-
-class ShapeHolder extends ParserObject {
-
-
- Vector facetSizesList;
- Vector facetIndicesList;
- int facetIndicesArray[];
- int currentNumIndices = 0;
- int numSurf;
- int numVerts;
- int facetIndices[];
- int facetSizes[];
- int normalIndices[];
- float normalCoords[];
- float coordsArray[];
-
- ShapeHolder() {
- }
-
- ShapeHolder(int debugVals) {
- super(debugVals);
- }
-
-
- /**
- * Print out (to stdout) the geometry data (coords, indices,
- * and facet sizes). This is a debugging utility.
- */
- void printGeometryData(LwoSurface surface) {
- int i, j;
- int indicesIndex = 0;
- System.out.println("\nPolygon Data:");
- System.out.println(" Surface color = " + surface.color);
- System.out.println(" Surface diffuse = " + surface.diffuseColor);
- for (i = 0; i < facetSizes.length; ++i) {
- int polySize = facetSizes[i];
- System.out.println("Facet of size " + polySize);
- for (j = 0; j < polySize; ++j) {
- int coordIndex = 3 * facetIndices[indicesIndex++];
- System.out.println("x, y, z = " +
- coordsArray[coordIndex] + ", " +
- coordsArray[coordIndex+1] + ", " +
- coordsArray[coordIndex+2]);
- }
- }
- }
-
- /**
- * Constructs geometry arrays given a winding rule (it turns out that
- * lw3d winding is opposite of j3d winding, so this is always set to
- * true in J3dLwoParser)
- */
- void createArrays(boolean reverseWinding) {
- debugOutputLn(TRACE, "createArrays()");
- // debugOutputLn(VALUES, "facetIndices, faceSizesList = " +
- // facetIndicesList + facetSizesList);
- //debugOutputLn(VALUES, "ind and sizes size " +
- // facetIndicesList.size() + ", " +
- // facetSizesList.size());
- //facetIndices =
- // new int[facetIndicesList.size()];
- facetIndices = new int[currentNumIndices];
- if (reverseWinding) {
- int facetBeginIndex = 0;
- for (int facetIndex = 0;
- facetIndex < facetSizesList.size();
- ++facetIndex) {
- int currFaceSize =
- ((Integer)facetSizesList.elementAt(facetIndex)).intValue();
- int tempFace[] = new int[currFaceSize];
- for (int j = 0; j < currFaceSize; ++j) {
- facetIndices[facetBeginIndex + j] =
- facetIndicesArray[facetBeginIndex +
- currFaceSize - j - 1];
- }
- facetBeginIndex += currFaceSize;
- }
-
- }
- else {
- for (int i = 0; i < facetIndices.length; ++i) {
- facetIndices[i] = facetIndicesArray[i];
- }
- }
-
- debugOutputLn(LINE_TRACE, "facetIndices.len and coordsArray.len = " +
- facetIndices.length + ", " + coordsArray.length);
- if (((Integer)facetSizesList.elementAt(0)).intValue() < 3) {
- // if we're dealing with point/line primitives, then let's abandon
- // the indexed route and simply construct a new coordsArray
- // that holds the direct values we need for a GeometryArray
- // object
- debugOutputLn(LINE_TRACE, "Using direct geometry because " +
- "facetIndices is of size " +
- facetIndices.length +
- " and coordsArray is of length "+
- coordsArray.length);
- float newCoordsArray[] = new float[facetIndices.length * 3];
- int newCoordsIndex = 0;
- for (int i = 0; i < facetIndices.length; ++i) {
- newCoordsArray[newCoordsIndex++] =
- coordsArray[facetIndices[i]*3];
- newCoordsArray[newCoordsIndex++] =
- coordsArray[facetIndices[i]*3+1];
- newCoordsArray[newCoordsIndex++] =
- coordsArray[facetIndices[i]*3+2];
- }
- coordsArray = newCoordsArray;
- facetIndices = null;
- }
-
- facetSizes =
- new int[facetSizesList.size()];
- for (int i = 0; i < facetSizes.length; ++i) {
- facetSizes[i] =
- ((Integer)facetSizesList.elementAt(i)).intValue();
- }
-
- facetSizesList = null; // Force garbage collection on Vectors
- facetIndicesList = null;
- facetIndicesArray = null;
- }
-
- /**
- * Force gc on all array objects
- */
- void nullify() {
- facetSizesList = null; // Force garbage collection on everything
- facetIndicesList = null;
- facetIndicesArray = null;
- facetSizes = null;
- facetIndices = null;
- normalCoords = null;
- normalIndices = null;
- }
-
- /**
- * This method calculates facet normals for the geometry. It is no
- * longer used, as we're now using the GeometryInfo utility to calculate
- * smooth normals
- */
- void calcNormals() {
- debugOutputLn(TRACE, "calcNormals()");
- debugOutputLn(LINE_TRACE, "coordsLength, facetsizes.len = " +
- coordsArray.length + ", " + facetSizes.length);
- if (facetSizes[0] > 2) {
- // points and lines don't need normals, polys do
- if (facetIndices != null) {
- normalIndices = new int[facetIndices.length];
- normalCoords = new float[facetIndices.length * 3];
- }
- else {
- normalCoords = new float[coordsArray.length];
- }
- debugOutputLn(LINE_TRACE, "normalCoords, incides len = " +
- normalCoords.length + ", " +
- ((facetIndices == null) ? 0 : normalIndices.length));
- int facetIndex = 0;
- int tempIndex = -1;
- for (int i = 0; i < facetSizes.length; i += 1) {
- Vector3f norm;
- int currFacetSize = facetSizes[i];
- //debugOutputLn(LINE_TRACE, " i, facetIndex, currSize = " +
- // i + ", " + facetIndex + ", " + currFacetSize);
- if (currFacetSize < 3) {
- // This shouldn't occur
- norm = new Vector3f(0f, 0f, 1f);
- }
- else {
- Vector3f v1, v2;
- int index1, index2, index3;
- if (facetIndices != null) {
- index1 = facetIndices[facetIndex];
- index2 = facetIndices[facetIndex+1];
- index3 = facetIndices[facetIndex+2];
- //debugOutputLn(VALUES, " index123 = " +
- // index1 + ", " + index2 + ", " + index3);
- }
- else {
- index1 = facetIndex;
- index2 = facetIndex+1;
- index3 = facetIndex+2;
- }
- v1 = new
- Vector3f(coordsArray[index2*3] - coordsArray[index1*3],
- coordsArray[index2*3+1] - coordsArray[index1*3+1],
- coordsArray[index2*3+2] - coordsArray[index1*3+2]);
- v2 = new
- Vector3f(coordsArray[index3*3] - coordsArray[index1*3],
- coordsArray[index3*3+1] - coordsArray[index1*3+1],
- coordsArray[index3*3+2] - coordsArray[index1*3+2]);
- //debugOutputLn(VALUES, "v1, v2 = " + v1 + v2);
- norm = new Vector3f();
- norm.cross(v1, v2);
- norm.normalize(norm);
- }
-
- for (int j = 0; j < currFacetSize; ++j) {
- int normIndex = facetIndex + j;
- normalCoords[normIndex*3] = norm.x;
- normalCoords[normIndex*3+1] = norm.y;
- normalCoords[normIndex*3+2] = norm.z;
- if (facetIndices != null)
- normalIndices[normIndex] = normIndex;
- }
- facetIndex += currFacetSize;
- }
- }
- debugOutputLn(TRACE, "done with calcNormals()");
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/SwitchPathInterpolator.java b/src/classes/share/com/sun/j3d/loaders/lw3d/SwitchPathInterpolator.java
deleted file mode 100644
index b52e1bf..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/SwitchPathInterpolator.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
- package com.sun.j3d.loaders.lw3d;
-
-
-import java.util.Enumeration;
-
-import javax.media.j3d.Alpha;
-import javax.media.j3d.Switch;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-/**
- * This class was used in conjunction with SequenceReader to create
- * Tloop functionality inside of Lightwave files. This behavior handles
- * the switching between objects defined in separate lines of a
- * sequence file. That is, each line in a sequence file has the name
- * of an object (or an object sequence, if the name ends in "000")
- * and details the start and end frames that that object should be active.
- * This class determines which object/s defined in the file should be active
- * at any given time during the animation.
- */
-
-class SwitchPathInterpolator extends FloatValueInterpolator {
-
- Switch target;
- int firstSwitchIndex;
- int lastSwitchIndex;
- int currentChild;
- int childCount;
-
- /**
- * Constructs a new SwitchPathInterpolator object.
- * @param alpha the alpha object for this interpolator
- * @param knots an array of knot values that specify a spline
- */
- SwitchPathInterpolator(Alpha alpha, float knots[], Switch target) {
-
- super(alpha, knots, new float[knots.length]);
-
- if (knots.length != (target.numChildren() + 1))
- throw new IllegalArgumentException(J3dUtilsI18N.getString("SwitchPathInterpolator0"));
-
- this.target = target;
- firstSwitchIndex = 0;
- lastSwitchIndex = target.numChildren() - 1;
- childCount = lastSwitchIndex + 1;
- }
-
- /**
- * This method sets the correct child for the Switch node according
- * to alpha
- * @param criteria enumeration of criteria that have triggered this wakeup
- */
-
- @Override
- public void processStimulus(Enumeration criteria) {
-
- int child;
-
- // Handle stimulus
- if (this.getAlpha() != null) {
-
- // Let PathInterpolator calculate the correct
- // interpolated knot point
- computePathInterpolation();
-
- if (currentKnotIndex > 0)
- child = currentKnotIndex - 1;
- else
- child = 0;
-
- if (target.getWhichChild() != child) {
- target.setWhichChild(child);
- }
-
- if ((this.getAlpha()).finished())
- return;
- }
-
- wakeupOn(defaultWakeupCriterion);
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/TargaReader.java b/src/classes/share/com/sun/j3d/loaders/lw3d/TargaReader.java
deleted file mode 100644
index 617c710..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/TargaReader.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-import java.awt.Image;
-import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferInt;
-import java.io.BufferedInputStream;
-import java.io.DataInputStream;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-import com.sun.j3d.loaders.IncorrectFormatException;
-import com.sun.j3d.loaders.ParsingErrorException;
-
-/**
- * This class parses a standard Targa file and retrieves the image stored
- * therein, storing the pixel data in a BufferedImage.
- */
-
-class TargaReader extends ParserObject {
-
- BufferedInputStream bufferedReader;
- Image theImage = null;
-
- /**
- * Constructor: creates file reader and calls parseFile() to do the real
- * work
- */
- TargaReader(String fileName, int debugVals) throws FileNotFoundException {
- super(debugVals);
- debugOutputLn(TRACE, "constructor");
- bufferedReader = new BufferedInputStream(
- new DataInputStream(new FileInputStream(fileName)));
- if (bufferedReader != null)
- parseFile();
- }
-
- /**
- * Returns the image that was created from parsing the targa file (null
- * if the file reading failed)
- */
- Image getImage() {
- return theImage;
- }
-
- /**
- * This method parses the file and stores the pixel data in a
- * BufferedImage. The basic file format is:
- * Byte Description
- *
- * 0 Image ID Length
- * 1 Colormap type
- * 2 Image Type
- * 3-4 Colormap spec: 1st entry index
- * 5-6 Colormap spec: length
- * 7 Colormap spec: entry size
- * 8-9 X-origin of lower-left corner
- * 10-11 Y-origin of lower-left corner
- * 12-13 Image width
- * 14-15 Image height
- * 16 Pixel depth
- * 17 00(origin)(alpha)
- * first 2 bytes 0, next 2 starting corner,
- * last four number of overlay bits per pixel
- * 18- Image ID
- * ?? Colormap data
- * ?? Image Data
- * ?? Developer Area
- * ?? Extension Area
- * ?? File Footer
- *
- * We're going to make some assumptions about the format of files we're
- * asked to load. In particular, we're not going to do any colormpa-based
- * images: the images need to be either 24-bit or 32-bit true color.
- * We're also going to ignore vaiours parameters in the header block, since
- * they complicate life and don't appear to be used in Lightwave image
- * files. In particular, the following fields will be ignored:
- * Image ID, colormap info, xy origins, and alpha/overlay bits.
- */
-
- void parseFile()
- throws IncorrectFormatException, ParsingErrorException {
- try {
- int idLength = bufferedReader.read();
- int colormapPresent = bufferedReader.read();
- int imageType = bufferedReader.read();
- bufferedReader.skip(9); // skipping camp and xy origin data
- int width = bufferedReader.read() | bufferedReader.read() << 8;
- int height = bufferedReader.read() | bufferedReader.read() << 8;
- int depth = bufferedReader.read();
- int flags = bufferedReader.read();
- boolean bottomToTop = ((flags & 0x20) == 0);
- boolean leftToRight = ((flags & 0x10) == 0);
- bufferedReader.skip(idLength);
-
- // Check on the file parameters to see whether we should punt
- if ((colormapPresent == 1) ||
- imageType != 2 ||
- (depth != 24 &&
- depth != 32)) {
- // Punt
- throw new IncorrectFormatException(
- "This format is not readable by the Lightwave " +
- "loader. Only 24- or 32-bit true-color " +
- "uncompressed Targa images will work");
- }
-
- // Image format must be okay for us to read
- BufferedImage bImage =
- new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
- int[] imageBits =
- ((DataBufferInt)bImage.getRaster().getDataBuffer()).getData();
-
- int row;
- int column;
-
- for (int i = 0; i < height; ++i) {
- if (bottomToTop)
- row = (height - i - 1);
- else
- row = i;
- for (int j = 0; j < width; ++j) {
-
- if (leftToRight)
- column = j;
- else
- column = (width - j - 1);
-
- int blue = bufferedReader.read();
- int green = bufferedReader.read();
- int red = bufferedReader.read();
- int alpha = 0xff;
- if (depth == 32)
- alpha = bufferedReader.read();
- imageBits[row*width + column] = alpha << 24 |
- red << 16 |
- green << 8 |
- blue;
- }
- }
- theImage = bImage;
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- }
-
-}
-
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/TextfileParser.java b/src/classes/share/com/sun/j3d/loaders/lw3d/TextfileParser.java
deleted file mode 100644
index f0cc401..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/TextfileParser.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.loaders.lw3d;
-
-import java.io.IOException;
-import java.io.StreamTokenizer;
-
-import com.sun.j3d.loaders.ParsingErrorException;
-
-/**
- * This class is a superclass for most of the Lws* Scene-file parsing
- * classes. It provides some debugging utilities, as well as utilities for
- * reading the types of data common to this loader.
- */
-
-class TextfileParser {
-
- // class variables
- static int WORD = StreamTokenizer.TT_WORD;
- static int NUMBER = StreamTokenizer.TT_NUMBER;
- int currentLevel = 3;
- final static int TRACE = DebugOutput.TRACE, VALUES = DebugOutput.VALUES;
- final static int MISC = DebugOutput.MISC, LINE_TRACE = DebugOutput.LINE_TRACE;
- final static int NONE = DebugOutput.NONE, EXCEPTION = DebugOutput.EXCEPTION;
- final static int TIME = DebugOutput.TIME;
- protected DebugOutput debugPrinter;
- char lineSeparatorChar = 0;
-
- TextfileParser() {
- debugPrinter = new DebugOutput(EXCEPTION);
- String lineSeparator = System.getProperty("line.separator");
- lineSeparatorChar = lineSeparator.charAt(0);
- debugOutputLn(VALUES, "lineSeparatorChar = " + (int)lineSeparatorChar);
- }
-
-
- protected void debugOutputLn(int outputType, String theOutput) {
- if (theOutput.equals(""))
- debugPrinter.println(outputType, theOutput);
- else {
- debugPrinter.println(outputType,
- getClass().getName() + "::" + theOutput);
- }
- }
-
- protected void debugOutput(int outputType, String theOutput) {
- debugPrinter.print(outputType, theOutput);
- }
-
- /**
- * Utility method to advance the tokenizer until we see the given
- * string. This is used to skip by various parameters that we
- * currently ignore in the loader.
- */
- void skipUntilString(StreamTokenizer st, String theString)
- throws ParsingErrorException {
- boolean done = false;
- try {
- while (!done) {
- st.nextToken();
- if (st.ttype == WORD &&
- st.sval.equals(theString))
- done = true;
- }
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- }
-
-
- /**
- * Returns number from the tokenizer. Note that we don't recognize
- * numbers in the tokenizer automatically because numbers might be in
- * scientific notation, which isn't processed correctly by
- * StreamTokenizer
- */
- double getNumber(StreamTokenizer st)
- throws ParsingErrorException, NumberFormatException {
- try {
- int token = st.nextToken();
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- checkType(st, WORD);
- return ((Double.valueOf(st.sval)).doubleValue());
- }
-
- /**
- * Returns String from the tokenizer
- */
- String getString(StreamTokenizer st) throws ParsingErrorException {
- try {
- st.nextToken();
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- checkType(st, WORD);
- return (st.sval);
- }
-
- /**
- * Returns a "name" from the stream. This is different from simply a
- * String because the name could contain whitespace characters
- * (such as "object 1" or "objectname (sequence)") that would confuse
- * the string parser. So we just grab all characters until EOL and
- * concatenate them together to form the name
- */
- String getName(StreamTokenizer st) throws ParsingErrorException {
- String theName = "";
- st.ordinaryChar(lineSeparatorChar);
- st.ordinaryChar('\n');
- st.ordinaryChar('\r');
- try {
- st.nextToken();
- while (st.ttype != lineSeparatorChar &&
- st.ttype != '\r' &&
- st.ttype != '\n') {
- if (st.ttype != '(' &&
- st.ttype != ')')
- theName += st.sval;
- st.nextToken();
- }
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- st.whitespaceChars(lineSeparatorChar, lineSeparatorChar);
- st.whitespaceChars('\n', '\n');
- st.whitespaceChars('\r', '\r');
- debugOutputLn(VALUES, "name = " + theName);
- return theName;
- }
-
- /**
- * Gets the next token and ensures that it is the string we were
- * expecting to see
- */
- void getAndCheckString(StreamTokenizer st, String expectedValue)
- throws ParsingErrorException {
- try {
- st.nextToken();
- checkString(st, expectedValue);
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- }
-
- /**
- * Error checking routine - makes sure the current token is the string
- * we were expecting
- */
- void checkString(StreamTokenizer st, String theString) throws
- ParsingErrorException {
- if (!(st.ttype == StreamTokenizer.TT_WORD) ||
- !st.sval.equals(theString))
- throw new ParsingErrorException(
- "Bad String Token (wanted " + theString + ", got " + st.sval +
- ": " + st.toString());
- }
-
- /**
- * Error checking routine - makes sure the current token is of the right
- * type
- */
- void checkType(StreamTokenizer st, int theType)
- throws ParsingErrorException {
- if (!(st.ttype == theType))
- throw new ParsingErrorException(
- "Bad Type Token, Expected " + theType + " and received" +
- st.ttype);
- }
-
- /**
- * Utility routine - gets next token, checks it against our expectation,
- * then skips a given number of tokens. This can be used to parse
- * through (and ignore) certain parameter/value sets in the files
- */
- void skip(StreamTokenizer st, String tokenString, int skipVals)
- throws ParsingErrorException {
- try {
- st.nextToken();
- checkString(st, tokenString);
- for (int i = 0; i < skipVals; ++i) {
- st.nextToken();
- }
- }
- catch (IOException e) {
- throw new ParsingErrorException(e.getMessage());
- }
- }
-
- /**
- * Utility method- used to check whether the current token is equal
- * to the given string
- */
- boolean isCurrentToken(StreamTokenizer st, String tokenString) {
- if (st.ttype == WORD)
- return (st.sval.equals(tokenString));
- return false;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/loaders/lw3d/package.html b/src/classes/share/com/sun/j3d/loaders/lw3d/package.html
deleted file mode 100644
index e87c100..0000000
--- a/src/classes/share/com/sun/j3d/loaders/lw3d/package.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- v float float float
vn float float float
- * vt float float
- * f int int int . . .
- * f int/int int/int int/int . . .
- * f int/int/int int/int/int int/int/int . . .
- * g name
- * s int
- * s off
- * usemtl name
- * - * amber amber_trans aqua aqua_filter - * archwhite archwhite2 bflesh black - * blondhair blue_pure bluegrey bluetint - * blugrn blutan bluteal bone - * bone1 bone2 brass brnhair - * bronze brown brownlips brownskn - * brzskin chappie charcoal deepgreen - * default dkblue dkblue_pure dkbrown - * dkdkgrey dkgreen dkgrey dkorange - * dkpurple dkred dkteal emerald - * fgreen flaqua flblack flblonde - * flblue_pure flbrown fldkblue_pure fldkdkgrey - * fldkgreen fldkgreen2 fldkgrey fldkolivegreen - * fldkpurple fldkred flesh fleshtransparent - * flgrey fllime flltbrown flltgrey - * flltolivegreen flmintgreen flmustard florange - * flpinegreen flpurple flred fltan - * flwhite flwhite1 flyellow glass - * glassblutint glasstransparent gold green - * greenskn grey hair iris - * jetflame lavendar lcdgreen lighttan - * lighttan2 lighttan3 lighttannew lightyellow - * lime lips ltbrown ltgrey - * meh metal mintgrn muscle - * navy_blue offwhite.cool offwhite.warm olivegreen - * orange pale_green pale_pink pale_yellow - * peach periwinkle pink pinktan - * plasma purple red redbrick - * redbrown redorange redwood rubber - * ruby sand_stone sapphire shadow - * ship2 silver skin sky_blue - * smoked_glass tan taupe teeth - * violet white yellow yellow_green - * yellowbrt yelloworng - *- *
mtllib filename
- * newmtl name
- * Ka float float float
- * Kd float float float
- * Ks float float float
- * illum (0, 1, or 2)
- * Ns float
- * map_Kd filename
- * Provides a Java 3D loader for Wavefront .obj files.
- - diff --git a/src/classes/share/com/sun/j3d/loaders/package.html b/src/classes/share/com/sun/j3d/loaders/package.html deleted file mode 100644 index 6b38d00..0000000 --- a/src/classes/share/com/sun/j3d/loaders/package.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - -Provides interfaces and abstract classes for writing Java 3D loaders.
- - diff --git a/src/classes/share/com/sun/j3d/utils/applet/JMainFrame.java b/src/classes/share/com/sun/j3d/utils/applet/JMainFrame.java deleted file mode 100644 index 62541fd..0000000 --- a/src/classes/share/com/sun/j3d/utils/applet/JMainFrame.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -// JMainFrame - run an Applet as an application -// -// Copyright (C) 1996 by Jef Poskanzer-// Using this class you can add a trivial main program to any Applet -// and run it directly, as well as from a browser or the appletviewer. -// And unlike some versions of this concept, MainFrame implements both -// images and sound. -//
-// Sample main program: -//
-// The only methods you need to know about are the constructors. -//-// public static void main( String[] args ) -// { -// new Acme.MainFrame( new ThisApplet(), args, 400, 400 ); -// } -//
-// You can specify Applet parameters on the command line, as name=value. -// For instance, the equivalent of: -//
-// would just be: -//-// <PARAM NAME="pause" VALUE="200"> -//
-// You can also specify three special parameters: -//-// pause=200 -//
-//-// width=N Width of the Applet. -// height=N Height of the Applet. -// barebones=true Leave off the menu bar and status area. -//
-// Fetch the software.
-// Fetch the entire Acme package.
-
-public class MainFrame extends Frame implements
- Runnable, AppletStub, AppletContext
-{
-
- private String[] args = null;
- private static int instances = 0;
- private String name;
- private boolean barebones = true;
- private Applet applet;
- private Label label = null;
- private Dimension appletSize;
-
- private static final String PARAM_PROP_PREFIX = "parameter.";
-
- /// Constructor with everything specified.
- public MainFrame(Applet applet, String[] args,
- int width, int height) {
- build(applet, args, width, height);
- }
-
- /// Constructor with no default width/height.
- public MainFrame(Applet applet, String[] args ) {
- build(applet, args, -1, -1);
- }
-
- /// Constructor with no arg parsing.
- public MainFrame(Applet applet, int width, int height) {
- build( applet, null, width, height );
- }
-
- // Internal constructor routine.
- private void build( Applet applet, String[] args,
- int width, int height) {
- ++instances;
- this.applet = applet;
- this.args = args;
- applet.setStub( this );
- name = applet.getClass().getName();
- setTitle( name );
-
- // Set up properties.
- Properties props = System.getProperties();
- props.put( "browser", "Acme.MainFrame" );
- props.put( "browser.version", "11jul96" );
- props.put( "browser.vendor", "Acme Laboratories" );
- props.put( "browser.vendor.url", "http://www.acme.com/" );
-
- // Turn args into parameters by way of the properties list.
- if ( args != null )
- parseArgs( args, props );
-
- // If width and height are specified in the parameters, override
- // the compiled-in values.
- String widthStr = getParameter( "width" );
- if ( widthStr != null ) {
- width = Integer.parseInt( widthStr );
- }
-
- String heightStr = getParameter( "height" );
- if ( heightStr != null ) {
- height = Integer.parseInt( heightStr );
- }
-
- // Were width and height specified somewhere?
- if ((width == -1) || (height == -1)) {
- System.err.println( "Width and height must be specified." );
- return;
- }
-
- // Do we want to run bare-bones?
- String bonesStr = getParameter( "barebones" );
- if ((bonesStr != null) && bonesStr.equals( "true" )) {
- barebones = true;
- }
-
- // Lay out components.
- setLayout( new BorderLayout() );
- add( "Center", applet );
-
- // Set up size.
- pack();
- validate();
- appletSize = applet.getSize();
- applet.setSize( width, height );
- setVisible(true);
-
-
- /*
- Added WindowListener inner class to detect close events.
- */
- SecurityManager sm = System.getSecurityManager();
- boolean doExit = true;
-
- if (sm != null) {
- try {
- sm.checkExit(0);
- } catch (SecurityException e) {
- doExit = false;
- }
- }
-
- final boolean _doExit = doExit;
-
- addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosing(WindowEvent winEvent) {
- if (MainFrame.this.applet != null) {
- MainFrame.this.applet.destroy();
- }
- Window w = winEvent.getWindow();
- w.hide();
- try {
- w.dispose();
- } catch (IllegalStateException e) {}
-
- if (_doExit) {
- System.exit(0);
- }
- }
- });
-
- // Start a separate thread to call the applet's init() and start()
- // methods, in case they take a long time.
- (new Thread( this )).start();
- }
-
- // Turn command-line arguments into Applet parameters, by way of the
- // properties list.
- private static void parseArgs( String[] args, Properties props) {
- String arg;
-
- for (int i = 0; i < args.length; ++i) {
- arg = args[i];
- int ind = arg.indexOf( '=' );
- if ( ind == -1 ) {
- props.put(PARAM_PROP_PREFIX + arg.toLowerCase(), "" );
- } else {
- props.put(PARAM_PROP_PREFIX + arg.substring( 0, ind ).toLowerCase(),
- arg.substring( ind + 1 ) );
- }
- }
- }
-
- // Methods from Runnable.
-
- /// Separate thread to call the applet's init() and start() methods.
- @Override
- public void run() {
- showStatus( name + " initializing..." );
- applet.init();
- validate();
- showStatus( name + " starting..." );
- applet.start();
- validate();
- showStatus( name + " running..." );
- }
-
-
- // Methods from AppletStub.
- @Override
- public boolean isActive() {
- return true;
- }
-
- @Override
- public URL getDocumentBase() {
- // Returns the current directory.
- String dir = System.getProperty( "user.dir" );
- String urlDir = dir.replace( File.separatorChar, '/' );
- try {
- return new URL( "file:" + urlDir + "/");
- } catch ( MalformedURLException e ) {
- return null;
- }
- }
-
- @Override
- public URL getCodeBase() {
- // Hack: loop through each item in CLASSPATH, checking if
- // the appropriately named .class file exists there. But
- // this doesn't account for .zip files.
- String path = System.getProperty( "java.class.path" );
- Enumeration st = new StringTokenizer( path, ":" );
- while ( st.hasMoreElements() ) {
- String dir = (String) st.nextElement();
- String filename = dir + File.separatorChar + name + ".class";
- File file = new File( filename );
- if (file.exists()) {
- String urlDir = dir.replace( File.separatorChar, '/' );
- try {
- return new URL( "file:" + urlDir + "/" );
- } catch (MalformedURLException e) {
- return null;
- }
- }
- }
- return null;
- }
-
- @Override
- public String getParameter(String name) {
- // Return a parameter via the munged names in the properties list.
- return System.getProperty( PARAM_PROP_PREFIX + name.toLowerCase() );
- }
-
- @Override
- public void appletResize(int width, int height) {
- // Change the frame's size by the same amount that the applet's
- // size is changing.
- Dimension frameSize = getSize();
- frameSize.width += width - appletSize.width;
- frameSize.height += height - appletSize.height;
- setSize( frameSize );
- appletSize = applet.getSize();
- }
-
- @Override
- public AppletContext getAppletContext() {
- return this;
- }
-
-
- // Methods from AppletContext.
- @Override
- public AudioClip getAudioClip( URL url ) {
- // This is an internal undocumented routine. However, it
- // also provides needed functionality not otherwise available.
- // I suspect that in a future release, JavaSoft will add an
- // audio content handler which encapsulates this, and then
- // we can just do a getContent just like for images.
- return new sun.applet.AppletAudioClip( url );
- }
-
- @Override
- public Image getImage( URL url ) {
- Toolkit tk = Toolkit.getDefaultToolkit();
- try {
- ImageProducer prod = (ImageProducer) url.getContent();
- return tk.createImage( prod );
- } catch ( IOException e ) {
- return null;
- }
- }
-
- @Override
- public Applet getApplet(String name) {
- // Returns this Applet or nothing.
- if (name.equals( this.name )) {
- return applet;
- }
- return null;
- }
-
- @Override
- public Enumeration getApplets() {
- // Just yields this applet.
- Vector v = new Vector();
- v.addElement( applet );
- return v.elements();
- }
-
- @Override
- public void showDocument( URL url ) {
- // Ignore.
- }
-
- @Override
- public void showDocument( URL url, String target ) {
- // Ignore.
- }
-
- @Override
- public void showStatus( String status ) {
- if (label != null) {
- label.setText(status);
- }
- }
-
- @Override
- public void setStream( String key, java.io.InputStream stream ) {
- throw new RuntimeException("Not Implemented");
- // TODO implement setStream method
- }
-
- @Override
- public java.io.InputStream getStream( String key ) {
- throw new RuntimeException("Not Implemented");
- // TODO implement getStream method
- }
-
- @Override
- public java.util.Iterator getStreamKeys() {
- throw new RuntimeException("Not Implemented");
- // TODO implement getStreamKeys method
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/applet/package.html b/src/classes/share/com/sun/j3d/utils/applet/package.html
deleted file mode 100644
index 3e0334e..0000000
--- a/src/classes/share/com/sun/j3d/utils/applet/package.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
Provides utility classes for running applets as stand-alone -applications.
- - diff --git a/src/classes/share/com/sun/j3d/utils/audio/DistanceAttenuation.java b/src/classes/share/com/sun/j3d/utils/audio/DistanceAttenuation.java deleted file mode 100644 index 5572ea3..0000000 --- a/src/classes/share/com/sun/j3d/utils/audio/DistanceAttenuation.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - - /* - * Sound Distance Attenuation utilities - * - * Various methods to create PointSound and ConeSound distance attenuation - * arrays. - */ - -package com.sun.j3d.utils.audio; - -import javax.media.j3d.SoundException; -import javax.vecmath.Point2f; - -import com.sun.j3d.internal.J3dUtilsI18N; - -public class DistanceAttenuation -{ - // private fields - - // public fields - /** - * Equation types - */ - static final int DOUBLE_DISTANCE_HALF_GAIN = 1; - - // methods - /** - * Fill a Distance Attenuation array - * - * recommend that the distance attenuation Point2f array is defined to - * be allocated to be 10 for DOUBLE_DISTANCE_HALF_GAIN - since 1/(2^10) - * exceeds 1/1000 scale that is agreed to be affective zero gain - * - * First method assumes that: - * type is half gain for every double of distance - * inner radius is 0.0 but region between 0th and 1st elements is constant - * since gains for these two elements are the same - * min gain approches zero. - */ - public void fillDistanceAttenuation( - float unitDistance, float unitGain, - Point2f[] distanceAttenuation ) { - if (distanceAttenuation == null) - throw new SoundException(J3dUtilsI18N.getString("DistanceAttenuation0")); - - int length = distanceAttenuation.length; - distanceAttenuation[0].x = 0.0f; - distanceAttenuation[0].y = unitGain; - float nextDistance = unitDistance; - float nextGain = unitGain; - - for (int i=1; iProvides audio utility classes.
- - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineCurve.java b/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineCurve.java deleted file mode 100644 index efc1d6b..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineCurve.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.interpolators; - -import com.sun.j3d.internal.J3dUtilsI18N; - -/** - * CubicSplineCurve is a container class that holds a number of - * cubicSplineSegments - * - * @since Java3D 1.1 - */ - -public class CubicSplineCurve { - - private float totalCurveLength; - private CubicSplineSegment[] cubicSplineSegment; - public int numSegments; - - - /** - * Default constructor - */ - CubicSplineCurve () { - numSegments = 0; - totalCurveLength = 0f; - } - - /** - * This method takes a list of key frames and creates spline segments - * from it. It requires at least four key frames to be passed to it. - * Given n key frames, it creates n-3 CubicSplineSegments. - * @param keys the list of key frames that specify the motion path - */ - - CubicSplineCurve (TCBKeyFrame keys[]) { - - int keyLength = keys.length; - // Require at least 4 key frames for cubic spline curve - if (keyLength < 4) - throw new IllegalArgumentException(J3dUtilsI18N.getString("CubicSplineCurve0")); - - numSegments = keyLength - 3; - this.cubicSplineSegment = new CubicSplineSegment[numSegments]; - - // intialize and calculate coefficients for each segment - int k0 = 0; int k1 = 1; int k2 = 2; int k3 = 3; - for (; k0 < numSegments; k0++, k1++, k2++, k3++) { - this.cubicSplineSegment[k0] = new CubicSplineSegment - (keys[k0], keys[k1], keys[k2], keys[k3]); - } - - // compute total curve length - computeTotalCurveLength (); - } - - /** - * This method takes a list of spline segments creates the - * CubicSplineCurve. - * @param the list of segments that comprise the complete motion path - */ - - CubicSplineCurve (CubicSplineSegment s[]) { - - cubicSplineSegment = new CubicSplineSegment[s.length]; - numSegments = cubicSplineSegment.length; - for (int i = 0; i < numSegments; i++) { - this.cubicSplineSegment[i] = s[i]; - } - - // compute total curve length - computeTotalCurveLength (); - } - - /** - * This method takes a list of spline segments to replace the existing - * set of CubicSplineSegments that comprise the current CubicSplineCurve - * motion path. - * @param s the list of segments that comprise the complete motion path - */ - - public void setSegments (CubicSplineSegment s[]) { - - cubicSplineSegment = new CubicSplineSegment[s.length]; - numSegments = cubicSplineSegment.length; - for (int i = 0; i < numSegments; i++) { - this.cubicSplineSegment[i] = s[i]; - } - - // compute total curve length - computeTotalCurveLength (); - } - - /** - * This method returns the CubicSplineSegments pointed to by index - * @param index the index of the CubicSplineSegment required - * @return index the CubicSplineSegment pointed to by index - */ - public CubicSplineSegment getSegment (int index) { - - return this.cubicSplineSegment[index]; - - } - - - // computes the total length of the curve - private void computeTotalCurveLength () { - - totalCurveLength = 0f; - for (int i = 0; i < numSegments; i++) { - totalCurveLength += cubicSplineSegment[i].length; - } - - } - - /** - * This method returns the total length of the entire CubicSplineCurve - * motion path. - * - * @return the length of the CubicSplineCurve motion path - */ - - public float getTotalCurveLength () { - - return this.totalCurveLength; - - } - -} - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineSegment.java b/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineSegment.java deleted file mode 100644 index 63199af..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/CubicSplineSegment.java +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.interpolators; - -import javax.vecmath.Point3f; -import javax.vecmath.Quat4f; -import javax.vecmath.Vector3f; - - -/** - * The CubicSplineSegment class creates the representation of a - * TCB (Kochanek-Bartels Spline). This class takes 4 key frames as - * its input (using TCBKeyFrame). If interpolating between the ith - * and (i+1)th key frame then the four key frames that need to - * be specified are the (i-1)th, ith, (i+1)th - * and (i+2)th keyframes in order. The CubicSegmentClass - * then pre-computes the hermite interpolation basis coefficients if the - * (i+1)th frame has the linear flag set to zero. These are used to - * calculate the interpolated position, scale and quaternions when they - * requested by the user using the getInterpolated* methods. If the the - * (i+1)th frame's linear flag is set to 1 then the class uses - * linear interpolation to calculate the interpolated position, sccale and - * quaternions it returns through the getInterpolated* methods. - * - * @since Java3D 1.1 - */ - -public class CubicSplineSegment { - - // Legendre polynomial information for Gaussian quadrature of speed - // for the domain [0,u], 0 <= u <= 1. - - // Legendre roots mapped to (root+1)/2 - static final double modRoot[] = - { - 0.046910077, - 0.230765345, - 0.5, - 0.769234655, - 0.953089922 - }; - - // original coefficients divided by 2 - static final double modCoeff[] = - { - 0.118463442, - 0.239314335, - 0.284444444, - 0.239314335, - 0.118463442 - }; - - // Key Frames - TCBKeyFrame[] keyFrame = new TCBKeyFrame[4]; - - // H.C - Point3f c0, c1, c2, c3; // coefficients for position - Point3f e0, e1, e2, e3; // coefficients for scale - - // variables for destination derivative - float one_minus_t_in; - float one_minus_c_in; - float one_minus_b_in; - float one_plus_c_in; - float one_plus_b_in; - float ddb; - float dda; - - // variables for source derivative - float one_minus_t_out; - float one_minus_c_out; - float one_minus_b_out; - float one_plus_c_out; - float one_plus_b_out; - float dsb; - float dsa; - - // Length of the spline segment - float length; - - // interpolation type - int linear; - - /** - * Default constructor - */ - CubicSplineSegment () { - - length = 0; - - } - - /** - * Creates a cubic spline segment between two key frames using the - * key frames provided. If creating a spline between the ith frame and - * the (i+1)th frame then send down the (i - 1)th, - * ith , (i+1)th and the (i+2)th key - * frames. - * - * @param kf0 (i - 1)th Key Frame - * @param kf1 ith Key Frame - * @param kf2 (i + 1)th Key Frame - * @param kf3 (i + 2)th Key Frame - */ - - CubicSplineSegment (TCBKeyFrame kf0, TCBKeyFrame kf1, TCBKeyFrame kf2, - TCBKeyFrame kf3) { - - // Copy KeyFrame information - keyFrame[0] = new TCBKeyFrame(kf0); - keyFrame[1] = new TCBKeyFrame(kf1); - keyFrame[2] = new TCBKeyFrame(kf2); - keyFrame[3] = new TCBKeyFrame(kf3); - - // if linear interpolation is requested then just set linear flag - // if spline interpolation is needed then compute spline coefficients - if (kf2.linear == 1) { - this.linear = 1; - } else { - this.linear = 0; - computeCommonCoefficients (kf0, kf1, kf2, kf3); - computeHermiteCoefficients (kf0, kf1, kf2, kf3); - } - - length = computeLength (1.0f); - // System.out.println ("Segment length = " + length); - - } - - // compute the common coefficients - private void computeCommonCoefficients (TCBKeyFrame kf0, - TCBKeyFrame kf1, - TCBKeyFrame kf2, - TCBKeyFrame kf3) { - - // variables for destination derivative - float one_minus_t_in = 1.0f - kf1.tension; - float one_minus_c_in = 1.0f - kf1.continuity; - float one_minus_b_in = 1.0f - kf1.bias; - float one_plus_c_in = 1.0f + kf1.continuity; - float one_plus_b_in = 1.0f + kf1.bias; - - // coefficients for the incoming Tangent - ddb = one_minus_t_in * one_minus_c_in * one_minus_b_in; - dda = one_minus_t_in * one_plus_c_in * one_plus_b_in; - - // variables for source derivative - float one_minus_t_out = 1.0f - kf2.tension; - float one_minus_c_out = 1.0f - kf2.continuity; - float one_minus_b_out = 1.0f - kf2.bias; - float one_plus_c_out = 1.0f + kf2.continuity; - float one_plus_b_out = 1.0f + kf2.bias; - - // coefficients for the outgoing Tangent - dsb = one_minus_t_in * one_plus_c_in * one_minus_b_in; - dsa = one_minus_t_in * one_minus_c_in * one_plus_b_in; - } - - - // compute the hermite interpolation basis coefficients - private void computeHermiteCoefficients (TCBKeyFrame kf0, - TCBKeyFrame kf1, - TCBKeyFrame kf2, - TCBKeyFrame kf3) { - - - Point3f deltaP = new Point3f(); - Point3f deltaS = new Point3f(); - - // Find the difference in position and scale - deltaP.x = kf2.position.x - kf1.position.x; - deltaP.y = kf2.position.y - kf1.position.y; - deltaP.z = kf2.position.z - kf1.position.z; - - deltaS.x = kf2.scale.x - kf1.scale.x; - deltaS.y = kf2.scale.y - kf1.scale.y; - deltaS.z = kf2.scale.z - kf1.scale.z; - - // Incoming Tangent - Point3f dd_pos = new Point3f(); - Point3f dd_scale = new Point3f(); - - // If this is the first keyframe of the animation - if (kf0.knot == kf1.knot) { - - float ddab = 0.5f * (dda + ddb); - - // Position - dd_pos.x = ddab * deltaP.x; - dd_pos.y = ddab * deltaP.y; - dd_pos.z = ddab * deltaP.z; - - // Scale - dd_scale.x = ddab * deltaS.x; - dd_scale.y = ddab * deltaS.y; - dd_scale.z = ddab * deltaS.z; - - } else { - - float adj0 = (kf1.knot - kf0.knot)/(kf2.knot - kf0.knot); - - // Position - dd_pos.x = adj0 * - ((ddb * deltaP.x) + (dda * (kf1.position.x - kf0.position.x))); - dd_pos.y = adj0 * - ((ddb * deltaP.y) + (dda * (kf1.position.y - kf0.position.y))); - dd_pos.z = adj0 * - ((ddb * deltaP.z) + (dda * (kf1.position.z - kf0.position.z))); - - // Scale - dd_scale.x = adj0 * - ((ddb * deltaS.x) + (dda * (kf1.scale.x - kf0.scale.x))); - dd_scale.y = adj0 * - ((ddb * deltaS.y) + (dda * (kf1.scale.y - kf0.scale.y))); - dd_scale.z = adj0 * - ((ddb * deltaS.z) + (dda * (kf1.scale.z - kf0.scale.z))); - } - - // Outgoing Tangent - Point3f ds_pos = new Point3f(); - Point3f ds_scale = new Point3f(); - - // If this is the last keyframe of the animation - if (kf2.knot == kf3.knot) { - - float dsab = 0.5f * (dsa + dsb); - - // Position - ds_pos.x = dsab * deltaP.x; - ds_pos.y = dsab * deltaP.y; - ds_pos.z = dsab * deltaP.z; - - // Scale - ds_scale.x = dsab * deltaS.x; - ds_scale.y = dsab * deltaS.y; - ds_scale.z = dsab * deltaS.z; - - } else { - - float adj1 = (kf2.knot - kf1.knot)/(kf3.knot - kf1.knot); - - // Position - ds_pos.x = adj1 * - ((dsb * (kf3.position.x - kf2.position.x)) + (dsa * deltaP.x)); - ds_pos.y = adj1 * - ((dsb * (kf3.position.y - kf2.position.y)) + (dsa * deltaP.y)); - ds_pos.z = adj1 * - ((dsb * (kf3.position.z - kf2.position.z)) + (dsa * deltaP.z)); - - // Scale - ds_scale.x = adj1 * - ((dsb * (kf3.scale.x - kf2.scale.x)) + (dsa * deltaS.x)); - ds_scale.y = adj1 * - ((dsb * (kf3.scale.y - kf2.scale.y)) + (dsa * deltaS.y)); - ds_scale.z = adj1 * - ((dsb * (kf3.scale.z - kf2.scale.z)) + (dsa * deltaS.z)); - } - - // Calculate the coefficients of the polynomial for position - c0 = new Point3f(); - c0.x = kf1.position.x; - c0.y = kf1.position.y; - c0.z = kf1.position.z; - - c1 = new Point3f(); - c1.x = dd_pos.x; - c1.y = dd_pos.y; - c1.z = dd_pos.z; - - c2 = new Point3f(); - c2.x = 3*deltaP.x - 2*dd_pos.x - ds_pos.x; - c2.y = 3*deltaP.y - 2*dd_pos.y - ds_pos.y; - c2.z = 3*deltaP.z - 2*dd_pos.z - ds_pos.z; - - c3 = new Point3f(); - c3.x = -2*deltaP.x + dd_pos.x + ds_pos.x; - c3.y = -2*deltaP.y + dd_pos.y + ds_pos.y; - c3.z = -2*deltaP.z + dd_pos.z + ds_pos.z; - - // Calculate the coefficients of the polynomial for scale - e0 = new Point3f(); - e0.x = kf1.scale.x; - e0.y = kf1.scale.y; - e0.z = kf1.scale.z; - - e1 = new Point3f(); - e1.x = dd_scale.x; - e1.y = dd_scale.y; - e1.z = dd_scale.z; - - e2 = new Point3f(); - e2.x = 3*deltaS.x - 2*dd_scale.x - ds_scale.x; - e2.y = 3*deltaS.y - 2*dd_scale.y - ds_scale.y; - e2.z = 3*deltaS.z - 2*dd_scale.z - ds_scale.z; - - e3 = new Point3f(); - e3.x = -2*deltaS.x + dd_scale.x + ds_scale.x; - e3.y = -2*deltaS.y + dd_scale.y + ds_scale.y; - e3.z = -2*deltaS.z + dd_scale.z + ds_scale.z; - } - - - /** - * Computes the length of the curve at a given point between - * key frames. - * @param u specifies the point between keyframes where 0 <= u <= 1. - */ - - public float computeLength (float u) { - - float result = 0f; - - // if linear interpolation - if (linear == 1) { - result = u*keyFrame[2].position.distance(keyFrame[1].position); - } else { - // Need to transform domain [0,u] to [-1,1]. If 0 <= x <= u - // and -1 <= t <= 1, then x = u*(t+1)/2. - int degree = 5; - for (int i = 0; i < degree; i++) - result += (float)modCoeff[i]*computeSpeed(u*(float)modRoot[i]); - result *= u; - } - - return result; - } - - // Velocity along curve - private float computeSpeed (float u) { - Point3f v = new Point3f(); - - v.x = c1.x + u * (2 * c2.x + 3 * u * c3.x); - v.y = c1.y + u * (2 * c2.y + 3 * u * c3.y); - v.z = c1.z + u * (2 * c2.z + 3 * u * c3.z); - - return (float)(Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z)); - } - - - /** - * Computes the interpolated quaternion along the curve at - * a given point between key frames. This routine uses linear - * interpolation if the (i+1)th key frame's linear - * value is equal to 1. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @param newQuat returns the value of the interpolated quaternion - */ - - public void getInterpolatedQuaternion (float u, Quat4f newQuat) { - - // if linear interpolation - if (this.linear == 1) { - double quatDot; - - quatDot = keyFrame[1].quat.x * keyFrame[2].quat.x + - keyFrame[1].quat.y * keyFrame[2].quat.y + - keyFrame[1].quat.z * keyFrame[2].quat.z + - keyFrame[1].quat.w * keyFrame[2].quat.w; - - if (quatDot < 0) { - newQuat.x = keyFrame[1].quat.x + - (-keyFrame[2].quat.x - keyFrame[1].quat.x) * u; - newQuat.y = keyFrame[1].quat.y + - (-keyFrame[2].quat.y - keyFrame[1].quat.y) * u; - newQuat.z = keyFrame[1].quat.z + - (-keyFrame[2].quat.z - keyFrame[1].quat.z) * u; - newQuat.w = keyFrame[1].quat.w + - (-keyFrame[2].quat.w - keyFrame[1].quat.w) * u; - } else { - newQuat.x = keyFrame[1].quat.x + - (keyFrame[2].quat.x - keyFrame[1].quat.x) * u; - newQuat.y = keyFrame[1].quat.y + - (keyFrame[2].quat.y - keyFrame[1].quat.y) * u; - newQuat.z = keyFrame[1].quat.z + - (keyFrame[2].quat.z - keyFrame[1].quat.z) * u; - newQuat.w = keyFrame[1].quat.w + - (keyFrame[2].quat.w - keyFrame[1].quat.w) * u; - } - - } else { - - // TODO: - // Currently we just use the great circle spherical interpolation - // for quaternions irrespective of the linear flag. Eventually - // we might want to do cubic interpolation of quaternions - newQuat.interpolate (keyFrame[1].quat, keyFrame[2].quat, u); - } - - } - - - - /** - * Computes the interpolated scale along the curve at a given point - * between key frames and returns a Point3f with the interpolated - * x, y, and z scale components. This routine uses linear - * interpolation if the (i+1)th key frame's linear - * value is equal to 1. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @param newScale returns the interpolated x,y,z scale value in a Point3f - */ - - public void getInterpolatedScale (float u, Point3f newScale) { - - // if linear interpolation - if (this.linear == 1) { - - newScale.x = keyFrame[1].scale.x + - ((keyFrame[2].scale.x - keyFrame[1].scale.x) * u); - newScale.y = keyFrame[1].scale.y + - ((keyFrame[2].scale.y - keyFrame[1].scale.y) * u); - newScale.z = keyFrame[1].scale.z + - ((keyFrame[2].scale.z - keyFrame[1].scale.z) * u); - - } else { - - newScale.x = e0.x + u * (e1.x + u * (e2.x + u * e3.x)); - newScale.y = e0.y + u * (e1.y + u * (e2.y + u * e3.y)); - newScale.z = e0.z + u * (e1.z + u * (e2.z + u * e3.z)); - - } - } - - - /** - * Computes the interpolated position along the curve at a given point - * between key frames and returns a Point3f with the interpolated - * x, y, and z scale components. This routine uses linear - * interpolation if the (i+1)th key frame's linear - * value is equal to 1. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @param newPos returns the interpolated x,y,z position in a Point3f - */ - - public void getInterpolatedPosition (float u, Point3f newPos) { - - // if linear interpolation - if (this.linear == 1) { - newPos.x = keyFrame[1].position.x + - ((keyFrame[2].position.x - keyFrame[1].position.x) * u); - newPos.y = keyFrame[1].position.y + - ((keyFrame[2].position.y - keyFrame[1].position.y) * u); - newPos.z = keyFrame[1].position.z + - ((keyFrame[2].position.z - keyFrame[1].position.z) * u); - } else { - - newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); - newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); - newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); - - } - } - - - /** - * Computes the interpolated position along the curve at a given point - * between key frames and returns a Vector3f with the interpolated - * x, y, and z scale components. This routine uses linear - * interpolation if the (i+1)th key frame's linear - * value is equal to 1. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @param newPos returns the interpolated x,y,z position in a Vector3f. - */ - - public void getInterpolatedPositionVector (float u, Vector3f newPos) { - // if linear interpolation - if (this.linear == 1) { - newPos.x = keyFrame[1].position.x + - ((keyFrame[2].position.x - keyFrame[1].position.x) * u); - newPos.y = keyFrame[1].position.y + - ((keyFrame[2].position.y - keyFrame[1].position.y) * u); - newPos.z = keyFrame[1].position.z + - ((keyFrame[2].position.z - keyFrame[1].position.z) * u); - } else { - - newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); - newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); - newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); - - } - } - - /** - * Computes the ratio of the length of the spline from the ith - * key frame to the position specified by u to the length of the entire - * spline segment from the ith key frame to the (i+1) - * th key frame. When the (i+1)th key frame's linear - * value is equal to 1, this is meaninful otherwise it should return u. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @return the interpolated ratio - */ - - public float getInterpolatedValue (float u) { - return (computeLength(u)/this.length); - } -} diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineCurve.java b/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineCurve.java deleted file mode 100644 index 755dd78..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineCurve.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.interpolators; - -import com.sun.j3d.internal.J3dUtilsI18N; - -/** - * KBCubicSplineCurve is a container class that holds a number of - * KBCubicSplineSegments - * - * @since Java3D 1.2 - */ - -public class KBCubicSplineCurve { - - private float totalCurveLength; - private KBCubicSplineSegment[] cubicSplineSegment; - public int numSegments; - - - // default constructor - KBCubicSplineCurve () { - numSegments = 0; - totalCurveLength = 0f; - } - - /** - * This method takes a list of key frames and creates spline segments - * from it. It requires at least four key frames to be passed to it. - * Given n key frames, it creates n-3 KBCubicSplineSegments. - * @param the list of key frames that specify the motion path - */ - - KBCubicSplineCurve (KBKeyFrame keys[]) { - - int keyLength = keys.length; - // Require at least 4 key frames for cubic spline curve - if (keyLength < 4) - throw new - IllegalArgumentException(J3dUtilsI18N.getString("KBCubicSplineCurve0")); - - numSegments = keyLength - 3; - this.cubicSplineSegment = new KBCubicSplineSegment[numSegments]; - - // intialize and calculate coefficients for each segment - int k0 = 0; int k1 = 1; int k2 = 2; int k3 = 3; - for (; k0 < numSegments; k0++, k1++, k2++, k3++) { - this.cubicSplineSegment[k0] = new KBCubicSplineSegment - (keys[k0], keys[k1], keys[k2], keys[k3]); - } - - // compute total curve length - computeTotalCurveLength (); - } - - /** - * This method takes a list of spline segments creates the - * KBCubicSplineCurve. - * @param the list of segments that comprise the complete motion path - */ - - KBCubicSplineCurve (KBCubicSplineSegment s[]) { - - cubicSplineSegment = new KBCubicSplineSegment[s.length]; - numSegments = cubicSplineSegment.length; - for (int i = 0; i < numSegments; i++) { - this.cubicSplineSegment[i] = s[i]; - } - - // compute total curve length - computeTotalCurveLength (); - } - - /** - * This method takes a list of spline segments to replace the existing - * set of KBCubicSplineSegments that comprise the current - * KBCubicSplineCurve motion path. - * @param s the list of segments that comprise the complete motion path - */ - - public void setSegments (KBCubicSplineSegment s[]) { - - cubicSplineSegment = new KBCubicSplineSegment[s.length]; - numSegments = cubicSplineSegment.length; - for (int i = 0; i < numSegments; i++) { - this.cubicSplineSegment[i] = s[i]; - } - - // compute total curve length - computeTotalCurveLength (); - } - - /** - * This method returns the KBCubicSplineSegments pointed to by index - * @param index the index of the KBCubicSplineSegment required - * @return the KBCubicSplineSegment pointed to by index - */ - public KBCubicSplineSegment getSegment (int index) { - - return this.cubicSplineSegment[index]; - - } - - - // computes the total length of the curve - private void computeTotalCurveLength () { - - totalCurveLength = 0f; - for (int i = 0; i < numSegments; i++) { - totalCurveLength += cubicSplineSegment[i].length; - } - - } - - /** - * This method returns the total length of the entire KBCubicSplineCurve - * motion path. - * - * @return the length of the KBCubicSplineCurve motion path - */ - - public float getTotalCurveLength () { - - return this.totalCurveLength; - - } - -} - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineSegment.java b/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineSegment.java deleted file mode 100644 index 62471c5..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBCubicSplineSegment.java +++ /dev/null @@ -1,624 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.interpolators; - -import javax.vecmath.Point3f; -import javax.vecmath.Vector3f; - - -/** - * The KBCubicSplineSegment class creates the representation of a - * Kochanek-Bartel's (also known as the TCB or Tension-Continuity-Bias - * Spline. This class takes 4 key frames as its input (using KBKeyFrame). - * If interpolating between the ith and (i+1)th key - * frame then the four key frames that need to be specified are the - * (i-1)th, ith, (i+1)th - * and (i+2)th keyframes in order. The KBCubicSegmentClass - * then pre-computes the hermite interpolation basis coefficients if the - * (i+1)th frame has the linear flag set to zero. These are used to - * calculate the interpolated position, scale and quaternions when they - * requested by the user using the getInterpolated* methods. If the the - * (i+1)th frame's linear flag is set to 1 then the class uses - * linear interpolation to calculate the interpolated position, scale, heading - * pitch and bank it returns through the getInterpolated* methods. - * - * @since Java3D 1.2 - */ -public class KBCubicSplineSegment { - - // Legendre polynomial information for Gaussian quadrature of speed - // for the domain [0,u], 0 <= u <= 1. - - // Legendre roots mapped to (root+1)/2 - static final double modRoot[] = - { - 0.046910077, - 0.230765345, - 0.5, - 0.769234655, - 0.953089922 - }; - - // original coefficients divided by 2 - static final double modCoeff[] = - { - 0.118463442, - 0.239314335, - 0.284444444, - 0.239314335, - 0.118463442 - }; - - // Key Frames - KBKeyFrame[] keyFrame = new KBKeyFrame[4]; - - // H.C - Point3f c0, c1, c2, c3; // coefficients for position - Point3f e0, e1, e2, e3; // coefficients for scale - float h0, h1, h2, h3; // coefficients for heading - float p0, p1, p2, p3; // coefficients for pitch - float b0, b1, b2, b3; // coefficients for bank - - // variables for destination derivative - float one_minus_t_in; - float one_minus_c_in; - float one_minus_b_in; - float one_plus_c_in; - float one_plus_b_in; - float ddb; - float dda; - - // variables for source derivative - float one_minus_t_out; - float one_minus_c_out; - float one_minus_b_out; - float one_plus_c_out; - float one_plus_b_out; - float dsb; - float dsa; - - // Length of the spline segment - float length; - - // interpolation type - int linear; - - // Default constructor - KBCubicSplineSegment () { - - length = 0; - - } - - /** - * Creates a cubic spline segment between two key frames using the - * key frames provided. If creating a spline between the ith frame and - * the (i+1)th frame then send down the (i - 1)th, - * ith , (i+1)th and the (i+2)th key - * frames. - * - * @param kf0 (i - 1)th Key Frame - * @param kf1 ith Key Frame - * @param kf2 (i + 1)th Key Frame - * @param kf3 (i + 2)th Key Frame - */ - - KBCubicSplineSegment (KBKeyFrame kf0, KBKeyFrame kf1, KBKeyFrame kf2, - KBKeyFrame kf3) { - - // Copy KeyFrame information - keyFrame[0] = new KBKeyFrame(kf0); - keyFrame[1] = new KBKeyFrame(kf1); - keyFrame[2] = new KBKeyFrame(kf2); - keyFrame[3] = new KBKeyFrame(kf3); - - // if linear interpolation is requested then just set linear flag - // if spline interpolation is needed then compute spline coefficients - if (kf2.linear == 1) { - this.linear = 1; - } else { - this.linear = 0; - computeCommonCoefficients (kf0, kf1, kf2, kf3); - computeHermiteCoefficients (kf0, kf1, kf2, kf3); - } - - length = computeLength (1.0f); - // System.out.println ("Segment length = " + length); - - } - - // compute the common coefficients - private void computeCommonCoefficients (KBKeyFrame kf0, - KBKeyFrame kf1, - KBKeyFrame kf2, - KBKeyFrame kf3) { - - // variables for destination derivative - float one_minus_t_in = 1.0f - kf1.tension; - float one_minus_c_in = 1.0f - kf1.continuity; - float one_minus_b_in = 1.0f - kf1.bias; - float one_plus_c_in = 1.0f + kf1.continuity; - float one_plus_b_in = 1.0f + kf1.bias; - - // coefficients for the incoming Tangent - ddb = one_minus_t_in * one_minus_c_in * one_minus_b_in; - dda = one_minus_t_in * one_plus_c_in * one_plus_b_in; - - // variables for source derivative - float one_minus_t_out = 1.0f - kf2.tension; - float one_minus_c_out = 1.0f - kf2.continuity; - float one_minus_b_out = 1.0f - kf2.bias; - float one_plus_c_out = 1.0f + kf2.continuity; - float one_plus_b_out = 1.0f + kf2.bias; - - // coefficients for the outgoing Tangent - dsb = one_minus_t_in * one_plus_c_in * one_minus_b_in; - dsa = one_minus_t_in * one_minus_c_in * one_plus_b_in; - } - - - // compute the hermite interpolation basis coefficients - private void computeHermiteCoefficients (KBKeyFrame kf0, - KBKeyFrame kf1, - KBKeyFrame kf2, - KBKeyFrame kf3) { - - - Point3f deltaP = new Point3f(); - Point3f deltaS = new Point3f(); - float deltaH; - float deltaT; - float deltaB; - - // Find the difference in position and scale - deltaP.x = kf2.position.x - kf1.position.x; - deltaP.y = kf2.position.y - kf1.position.y; - deltaP.z = kf2.position.z - kf1.position.z; - - deltaS.x = kf2.scale.x - kf1.scale.x; - deltaS.y = kf2.scale.y - kf1.scale.y; - deltaS.z = kf2.scale.z - kf1.scale.z; - - // Find the difference in heading, pitch, and bank - deltaH = kf2.heading - kf1.heading; - deltaT = kf2.pitch - kf1.pitch; - deltaB = kf2.bank - kf1.bank; - - // Incoming Tangent - Point3f dd_pos = new Point3f(); - Point3f dd_scale = new Point3f(); - float dd_heading, dd_pitch, dd_bank; - - // If this is the first keyframe of the animation - if (kf0.knot == kf1.knot) { - - float ddab = 0.5f * (dda + ddb); - - // Position - dd_pos.x = ddab * deltaP.x; - dd_pos.y = ddab * deltaP.y; - dd_pos.z = ddab * deltaP.z; - - // Scale - dd_scale.x = ddab * deltaS.x; - dd_scale.y = ddab * deltaS.y; - dd_scale.z = ddab * deltaS.z; - - // Heading, Pitch and Bank - dd_heading = ddab * deltaH; - dd_pitch = ddab * deltaT; - dd_bank = ddab * deltaB; - - } else { - - float adj0 = (kf1.knot - kf0.knot)/(kf2.knot - kf0.knot); - - // Position - dd_pos.x = adj0 * - ((ddb * deltaP.x) + (dda * (kf1.position.x - kf0.position.x))); - dd_pos.y = adj0 * - ((ddb * deltaP.y) + (dda * (kf1.position.y - kf0.position.y))); - dd_pos.z = adj0 * - ((ddb * deltaP.z) + (dda * (kf1.position.z - kf0.position.z))); - - // Scale - dd_scale.x = adj0 * - ((ddb * deltaS.x) + (dda * (kf1.scale.x - kf0.scale.x))); - dd_scale.y = adj0 * - ((ddb * deltaS.y) + (dda * (kf1.scale.y - kf0.scale.y))); - dd_scale.z = adj0 * - ((ddb * deltaS.z) + (dda * (kf1.scale.z - kf0.scale.z))); - - // Heading, Pitch and Bank - dd_heading = adj0 * - ((ddb * deltaH) + (dda * (kf1.heading - kf0.heading))); - dd_pitch = adj0 * - ((ddb * deltaT) + (dda * (kf1.pitch - kf0.pitch))); - dd_bank = adj0 * - ((ddb * deltaB) + (dda * (kf1.bank - kf0.bank))); - } - - // Outgoing Tangent - Point3f ds_pos = new Point3f(); - Point3f ds_scale = new Point3f(); - float ds_heading, ds_pitch, ds_bank; - - // If this is the last keyframe of the animation - if (kf2.knot == kf3.knot) { - - float dsab = 0.5f * (dsa + dsb); - - // Position - ds_pos.x = dsab * deltaP.x; - ds_pos.y = dsab * deltaP.y; - ds_pos.z = dsab * deltaP.z; - - // Scale - ds_scale.x = dsab * deltaS.x; - ds_scale.y = dsab * deltaS.y; - ds_scale.z = dsab * deltaS.z; - - // Heading, Pitch and Bank - ds_heading = dsab * deltaH; - ds_pitch = dsab * deltaT; - ds_bank = dsab * deltaB; - - } else { - - float adj1 = (kf2.knot - kf1.knot)/(kf3.knot - kf1.knot); - - // Position - ds_pos.x = adj1 * - ((dsb * (kf3.position.x - kf2.position.x)) + (dsa * deltaP.x)); - ds_pos.y = adj1 * - ((dsb * (kf3.position.y - kf2.position.y)) + (dsa * deltaP.y)); - ds_pos.z = adj1 * - ((dsb * (kf3.position.z - kf2.position.z)) + (dsa * deltaP.z)); - - // Scale - ds_scale.x = adj1 * - ((dsb * (kf3.scale.x - kf2.scale.x)) + (dsa * deltaS.x)); - ds_scale.y = adj1 * - ((dsb * (kf3.scale.y - kf2.scale.y)) + (dsa * deltaS.y)); - ds_scale.z = adj1 * - ((dsb * (kf3.scale.z - kf2.scale.z)) + (dsa * deltaS.z)); - - // Heading, Pitch and Bank - ds_heading = adj1 * - ((dsb * (kf3.heading - kf2.heading)) + (dsa * deltaH)); - ds_pitch = adj1 * - ((dsb * (kf3.pitch - kf2.pitch)) + (dsa * deltaT)); - ds_bank = adj1 * - ((dsb * (kf3.bank - kf2.bank)) + (dsa * deltaB)); - } - - // Calculate the coefficients of the polynomial for position - c0 = new Point3f(); - c0.x = kf1.position.x; - c0.y = kf1.position.y; - c0.z = kf1.position.z; - - c1 = new Point3f(); - c1.x = dd_pos.x; - c1.y = dd_pos.y; - c1.z = dd_pos.z; - - c2 = new Point3f(); - c2.x = 3*deltaP.x - 2*dd_pos.x - ds_pos.x; - c2.y = 3*deltaP.y - 2*dd_pos.y - ds_pos.y; - c2.z = 3*deltaP.z - 2*dd_pos.z - ds_pos.z; - - c3 = new Point3f(); - c3.x = -2*deltaP.x + dd_pos.x + ds_pos.x; - c3.y = -2*deltaP.y + dd_pos.y + ds_pos.y; - c3.z = -2*deltaP.z + dd_pos.z + ds_pos.z; - - // Calculate the coefficients of the polynomial for scale - e0 = new Point3f(); - e0.x = kf1.scale.x; - e0.y = kf1.scale.y; - e0.z = kf1.scale.z; - - e1 = new Point3f(); - e1.x = dd_scale.x; - e1.y = dd_scale.y; - e1.z = dd_scale.z; - - e2 = new Point3f(); - e2.x = 3*deltaS.x - 2*dd_scale.x - ds_scale.x; - e2.y = 3*deltaS.y - 2*dd_scale.y - ds_scale.y; - e2.z = 3*deltaS.z - 2*dd_scale.z - ds_scale.z; - - e3 = new Point3f(); - e3.x = -2*deltaS.x + dd_scale.x + ds_scale.x; - e3.y = -2*deltaS.y + dd_scale.y + ds_scale.y; - e3.z = -2*deltaS.z + dd_scale.z + ds_scale.z; - - // Calculate the coefficients of the polynomial for heading, pitch - // and bank - h0 = kf1.heading; - p0 = kf1.pitch; - b0 = kf1.bank; - - h1 = dd_heading; - p1 = dd_pitch; - b1 = dd_bank; - - h2 = 3*deltaH - 2*dd_heading - ds_heading; - p2 = 3*deltaT - 2*dd_pitch - ds_pitch; - b2 = 3*deltaB - 2*dd_bank - ds_bank; - - h3 = -2*deltaH + dd_heading + ds_heading; - p3 = -2*deltaT + dd_pitch + ds_pitch; - b3 = -2*deltaB + dd_bank + ds_bank; - } - - - /** - * Computes the length of the curve at a given point between - * key frames. - * @param u specifies the point between keyframes where 0 <= u <= 1. - */ - - public float computeLength (float u) { - - float result = 0f; - - // if linear interpolation - if (linear == 1) { - result = u*keyFrame[2].position.distance(keyFrame[1].position); - } else { - // Need to transform domain [0,u] to [-1,1]. If 0 <= x <= u - // and -1 <= t <= 1, then x = u*(t+1)/2. - int degree = 5; - for (int i = 0; i < degree; i++) - result += (float)modCoeff[i]*computeSpeed(u*(float)modRoot[i]); - result *= u; - } - - return result; - } - - // Velocity along curve - private float computeSpeed (float u) { - Point3f v = new Point3f(); - - v.x = c1.x + u * (2 * c2.x + 3 * u * c3.x); - v.y = c1.y + u * (2 * c2.y + 3 * u * c3.y); - v.z = c1.z + u * (2 * c2.z + 3 * u * c3.z); - - return (float)(Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z)); - } - - - /** - * Computes the interpolated scale along the curve at a given point - * between key frames and returns a Point3f with the interpolated - * x, y, and z scale components. This routine uses linear - * interpolation if the (i+1)th key frame's linear - * value is equal to 1. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @param newScale returns the interpolated x,y,z scale value in a Point3f - */ - - public void getInterpolatedScale (float u, Point3f newScale) { - - // if linear interpolation - if (this.linear == 1) { - - newScale.x = keyFrame[1].scale.x + - ((keyFrame[2].scale.x - keyFrame[1].scale.x) * u); - newScale.y = keyFrame[1].scale.y + - ((keyFrame[2].scale.y - keyFrame[1].scale.y) * u); - newScale.z = keyFrame[1].scale.z + - ((keyFrame[2].scale.z - keyFrame[1].scale.z) * u); - - } else { - - newScale.x = e0.x + u * (e1.x + u * (e2.x + u * e3.x)); - newScale.y = e0.y + u * (e1.y + u * (e2.y + u * e3.y)); - newScale.z = e0.z + u * (e1.z + u * (e2.z + u * e3.z)); - - } - } - - - /** - * Computes the interpolated position along the curve at a given point - * between key frames and returns a Point3f with the interpolated - * x, y, and z scale components. This routine uses linear - * interpolation if the (i+1)th key frame's linear - * value is equal to 1. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @param newPos returns the interpolated x,y,z position in a Point3f - */ - - public void getInterpolatedPosition (float u, Point3f newPos) { - - // if linear interpolation - if (this.linear == 1) { - newPos.x = keyFrame[1].position.x + - ((keyFrame[2].position.x - keyFrame[1].position.x) * u); - newPos.y = keyFrame[1].position.y + - ((keyFrame[2].position.y - keyFrame[1].position.y) * u); - newPos.z = keyFrame[1].position.z + - ((keyFrame[2].position.z - keyFrame[1].position.z) * u); - } else { - - newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); - newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); - newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); - - } - } - - - /** - * Computes the interpolated position along the curve at a given point - * between key frames and returns a Vector3f with the interpolated - * x, y, and z scale components. This routine uses linear - * interpolation if the (i+1)th key frame's linear - * value is equal to 1. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @param newPos returns the interpolated x,y,z position in a Vector3f. - */ - - public void getInterpolatedPositionVector (float u, Vector3f newPos) { - // if linear interpolation - if (this.linear == 1) { - newPos.x = keyFrame[1].position.x + - ((keyFrame[2].position.x - keyFrame[1].position.x) * u); - newPos.y = keyFrame[1].position.y + - ((keyFrame[2].position.y - keyFrame[1].position.y) * u); - newPos.z = keyFrame[1].position.z + - ((keyFrame[2].position.z - keyFrame[1].position.z) * u); - } else { - - newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); - newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); - newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); - - } - } - - /** - * Computes the interpolated heading along the curve at a given point - * between key frames and returns the interpolated value as a float - * This routine uses linear interpolation if the (i+1)th - * key frame's linear value is equal to 1. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @return returns the interpolated heading value - */ - - public float getInterpolatedHeading (float u) { - - float newHeading; - - // if linear interpolation - if (this.linear == 1) { - - newHeading = keyFrame[1].heading + - ((keyFrame[2].heading - keyFrame[1].heading) * u); - } else { - - newHeading = h0 + u * (h1 + u * (h2 + u * h3)); - - } - - return newHeading; - } - - - /** - * Computes the interpolated pitch along the curve at a given point - * between key frames and returns the interpolated value as a float - * This routine uses linear interpolation if the (i+1)th - * key frame's linear value is equal to 1. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @return returns the interpolated pitch value - */ - - public float getInterpolatedPitch (float u) { - - float newPitch; - - // if linear interpolation - if (this.linear == 1) { - - newPitch = keyFrame[1].pitch + - ((keyFrame[2].pitch - keyFrame[1].pitch) * u); - } else { - - newPitch = p0 + u * (p1 + u * (p2 + u * p3)); - - } - - return newPitch; - } - - /** - * Computes the interpolated bank along the curve at a given point - * between key frames and returns the interpolated value as a float - * This routine uses linear interpolation if the (i+1)th - * key frame's linear value is equal to 1. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @return returns the interpolated bank value - */ - - public float getInterpolatedBank (float u) { - - float newBank; - - // if linear interpolation - if (this.linear == 1) { - - newBank = keyFrame[1].bank + - ((keyFrame[2].bank - keyFrame[1].bank) * u); - } else { - - newBank = b0 + u * (b1 + u * (b2 + u * b3)); - - } - - return newBank; - } - - - /** - * Computes the ratio of the length of the spline from the ith - * key frame to the position specified by u to the length of the entire - * spline segment from the ith key frame to the (i+1) - * th key frame. When the (i+1)th key frame's linear - * value is equal to 1, this is meaninful otherwise it should return u. - * - * @param u specifies the point between keyframes where 0 <= u <= 1. - * @return the interpolated ratio - */ - - public float getInterpolatedValue (float u) { - return (computeLength(u)/this.length); - } -} diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBKeyFrame.java b/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBKeyFrame.java deleted file mode 100644 index 46b1980..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBKeyFrame.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.interpolators; - -import javax.vecmath.Point3f; - -import com.sun.j3d.internal.J3dUtilsI18N; - -/** - * This class represents a Key Frame that can be used for Kochanek-Bartels - * (also called TCB or Tension-Continuity-Bias Splines) spline interpolation. - * - * @since Java3D 1.2 - */ -public class KBKeyFrame { - - // Position, Rotation and Scale - public Point3f position; - public float heading; - public float pitch; - public float bank; - public Point3f scale; - - // Tension, Continuity & Bias - public float tension; - public float continuity; - public float bias; - - // Sample Time - public float knot; - - // Interpolation type (linear = 0 -> spline interpolation) - public int linear; - - // default constructor - KBKeyFrame () { - tension = continuity = bias = 0.0f; - } - - public KBKeyFrame (KBKeyFrame kf) { - this(kf.knot, kf.linear, kf.position, kf.heading, kf.pitch, kf.bank, - kf.scale, kf.tension, kf.continuity, kf.bias); - - } - - - /** - * Creates a key frame using the given inputs. - * - * @param k knot value for this key frame - * @param l the linear flag (0 - Spline Interp, 1, Linear Interp - * @param pos the position at the key frame - * @param hd the heading value at the key frame - * @param pi the pitch value at the key frame - * @param bk the bank value at the key frame - * @param s the scales at the key frame - * @param t tension (-1.0 < t < 1.0) - * @param c continuity (-1.0 < c < 1.0) - * @param b bias (-1.0 < b < 1.0) - */ - public KBKeyFrame (float k, int l, Point3f pos, float hd, float pi, - float bk, Point3f s, float t, float c, float b) { - - knot = k; - linear = l; - position = new Point3f(pos); - heading = hd; - pitch = pi; - bank = bk; - scale = new Point3f(s); - - // Check for valid tension continuity and bias values - if (t < -1.0f || t > 1.0f) { - throw new IllegalArgumentException(J3dUtilsI18N.getString("KBKeyFrame0")); - } - - if (b < -1.0f || b > 1.0f) { - throw new IllegalArgumentException(J3dUtilsI18N.getString("KBKeyFrame1")); - } - - if (c < -1.0f || c > 1.0f) { - throw new IllegalArgumentException(J3dUtilsI18N.getString("KBKeyFrame2")); - } - - // copy valid tension, continuity and bias values - tension = t; - continuity = c; - bias = b; - } - - /** - * Prints information comtained in this key frame - * @param tag string tag for identifying debug message - */ - public void debugPrint (String tag) { - System.out.println ("\n" + tag); - System.out.println (" knot = " + knot); - System.out.println (" linear = " + linear); - System.out.println (" position(x,y,z) = " + position.x + " " - + position.y + " " + position.z); - - System.out.println (" tension = " + tension); - System.out.println (" continuity = " + continuity); - System.out.println (" bias = " + bias); - } -} - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBRotPosScaleSplinePathInterpolator.java b/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBRotPosScaleSplinePathInterpolator.java deleted file mode 100644 index 457a2ef..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBRotPosScaleSplinePathInterpolator.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.interpolators; - -import javax.media.j3d.Alpha; -import javax.media.j3d.Node; -import javax.media.j3d.NodeComponent; -import javax.media.j3d.RestrictedAccessException; -import javax.media.j3d.Transform3D; -import javax.media.j3d.TransformGroup; -import javax.vecmath.Matrix4d; -import javax.vecmath.Point3f; -import javax.vecmath.Vector3f; - - -/** - * KBRotPosScaleSplinePathInterpolator; A rotation and position path - * interpolation behavior node using Kochanek-Bartels cubic splines - * (also known as TCB or Tension-Continuity-Bias Splines). - * - * @since Java3D 1.2 - */ - -/** - * KBRotPosScaleSplinePathInterpolator behavior. This class defines a - * behavior that varies the rotational, translational, and scale components - * of its target TransformGroup by using the Kochanek-Bartels cubic spline - * interpolation to interpolate among a series of key frames - * (using the value generated by the specified Alpha object). The - * interpolated position, orientation, and scale are used to generate - * a transform in the local coordinate system of this interpolator. - */ - -public class KBRotPosScaleSplinePathInterpolator - extends KBSplinePathInterpolator { - - private Transform3D rotation = new Transform3D(); - - private Matrix4d pitchMat = new Matrix4d(); // pitch matrix - private Matrix4d bankMat = new Matrix4d(); // bank matrix - private Matrix4d tMat = new Matrix4d(); // transformation matrix - private Matrix4d sMat = new Matrix4d(); // scale matrix - //Quat4f iQuat = new Quat4f(); // interpolated quaternion - private Vector3f iPos = new Vector3f(); // interpolated position - private Point3f iScale = new Point3f(); // interpolated scale - float iHeading, iPitch, iBank; // interpolated heading, - // pitch and bank - - KBCubicSplineCurve cubicSplineCurve = new KBCubicSplineCurve(); - KBCubicSplineSegment cubicSplineSegments[]; - int numSegments; - int currentSegmentIndex; - KBCubicSplineSegment currentSegment; - - // non-public, default constructor used by cloneNode - KBRotPosScaleSplinePathInterpolator() { - } - - /** - * Constructs a new KBRotPosScaleSplinePathInterpolator object that - * varies the rotation, translation, and scale of the target - * TransformGroup's transform. At least 2 key frames are required for - * this interpolator. The first key - * frame's knot must have a value of 0.0 and the last knot must have a - * value of 1.0. An intermediate key frame with index k must have a - * knot value strictly greater than the knot value of a key frame with - * index less than k. - * @param alpha the alpha object for this interpolator - * @param target the TransformGroup node affected by this interpolator - * @param axisOfTransform the transform that specifies the local - * coordinate system in which this interpolator operates. - * @param keys an array of key frames that defien the motion path - */ - public KBRotPosScaleSplinePathInterpolator(Alpha alpha, - TransformGroup target, - Transform3D axisOfTransform, - KBKeyFrame keys[]) { - super(alpha,target, axisOfTransform, keys); - - // Create a spline curve using the derived key frames - cubicSplineCurve = new KBCubicSplineCurve(this.keyFrames); - numSegments = cubicSplineCurve.numSegments; - - } - - /** - * @deprecated As of Java 3D version 1.3, replaced by - *TransformInterpolator.setTransformAxis(Transform3D)
- */
- public void setAxisOfRotPosScale(Transform3D axisOfRotPosScale) {
- setTransformAxis(axisOfRotPosScale);
- }
-
- /**
- * @deprecated As of Java 3D version 1.3, replaced by
- * TransformInterpolator.getTransformAxis()
- */
- public Transform3D getAxisOfRotPosScale() {
- return getTransformAxis();
- }
-
- /**
- * Set the key frame at the specified index to keyFrame
- * @param index Index of the key frame to change
- * @param keyFrame The new key frame
- */
- @Override
- public void setKeyFrame( int index, KBKeyFrame keyFrame ) {
- super.setKeyFrame( index, keyFrame );
-
- // TODO Optimize this
- // Create a spline curve using the derived key frames
- cubicSplineCurve = new KBCubicSplineCurve(this.keyFrames);
- numSegments = cubicSplineCurve.numSegments;
- }
-
- /**
- * Set all the key frames
- * @param keyFrame The new key frames
- */
- @Override
- public void setKeyFrames( KBKeyFrame[] keyFrame ) {
- super.setKeyFrames( keyFrame );
-
- // Create a spline curve using the derived key frames
- cubicSplineCurve = new KBCubicSplineCurve(this.keyFrames);
- numSegments = cubicSplineCurve.numSegments;
- }
-
- /**
- * Computes the new transform for this interpolator for a given
- * alpha value.
- *
- * @param alphaValue alpha value between 0.0 and 1.0
- * @param transform object that receives the computed transform for
- * the specified alpha value
- *
- * @since Java 3D 1.3
- */
- @Override
- public void computeTransform(float alphaValue, Transform3D transform) {
- // compute the current value of u from alpha and the
- // determine lower and upper knot points
- computePathInterpolation( alphaValue );
-
- // Determine the segment within which we will be interpolating
- currentSegmentIndex = this.lowerKnot - 1;
-
- // if we are at the start of the curve
- if (currentSegmentIndex == 0 && currentU == 0f) {
-
- iHeading = keyFrames[1].heading;
- iPitch = keyFrames[1].pitch;
- iBank = keyFrames[1].bank;
- iPos.set(keyFrames[1].position);
- iScale.set(keyFrames[1].scale);
-
- // if we are at the end of the curve
- } else if (currentSegmentIndex == (numSegments-1) &&
- currentU == 1.0) {
-
- iHeading = keyFrames[upperKnot].heading;
- iPitch = keyFrames[upperKnot].pitch;
- iBank = keyFrames[upperKnot].bank;
- iPos.set(keyFrames[upperKnot].position);
- iScale.set(keyFrames[upperKnot].scale);
-
- // if we are somewhere in between the curve
- } else {
-
- // Get a reference to the current spline segment i.e. the
- // one bounded by lowerKnot and upperKnot
- currentSegment
- = cubicSplineCurve.getSegment(currentSegmentIndex);
-
- // interpolate quaternions
- iHeading = currentSegment.getInterpolatedHeading (currentU);
- iPitch = currentSegment.getInterpolatedPitch (currentU);
- iBank = currentSegment.getInterpolatedBank (currentU);
-
- // interpolate position
- currentSegment.getInterpolatedPositionVector(currentU,iPos);
-
- // interpolate position
- currentSegment.getInterpolatedScale(currentU,iScale);
-
- }
-
- // Generate a transformation matrix in tMat using interpolated
- // heading, pitch and bank
- pitchMat.setIdentity();
- pitchMat.rotX(-iPitch);
- bankMat.setIdentity();
- bankMat.rotZ(iBank);
- tMat.setIdentity();
- tMat.rotY(-iHeading);
- tMat.mul(pitchMat);
- tMat.mul(bankMat);
-
- // TODO: Handle Non-Uniform scale
- // Currently this interpolator does not handle non uniform scale
- // We cheat by just taking the x scale component
-
- // Scale the transformation matrix
- sMat.set((double)iScale.x);
- tMat.mul(sMat);
-
- // Set the translation components.
- tMat.m03 = iPos.x;
- tMat.m13 = iPos.y;
- tMat.m23 = iPos.z;
- rotation.set(tMat);
-
- // construct a Transform3D from: axis * rotation * axisInverse
- transform.mul(axis, rotation);
- transform.mul(transform, axisInverse);
- }
-
- /**
- * Copies KBRotPosScaleSplinePathInterpolator 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 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
- public Node cloneNode(boolean forceDuplicate) {
- KBRotPosScaleSplinePathInterpolator spline =
- new KBRotPosScaleSplinePathInterpolator();
-
- spline.duplicateNode(this, forceDuplicate);
- return spline;
- }
-
- /**
- * Copies KBRotPosScaleSplinePathInterpolator 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
- public void duplicateNode(Node originalNode, boolean forceDuplicate) {
- super.duplicateNode(originalNode, forceDuplicate);
-
- KBRotPosScaleSplinePathInterpolator interpolator =
- (KBRotPosScaleSplinePathInterpolator)originalNode;
- setAxisOfRotPosScale(interpolator.axis);
- target = interpolator.target;
- cubicSplineCurve = new KBCubicSplineCurve(interpolator.keyFrames);
- numSegments = cubicSplineCurve.numSegments;
- }
-}
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBSplinePathInterpolator.java b/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBSplinePathInterpolator.java
deleted file mode 100644
index 5782a41..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/KBSplinePathInterpolator.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.interpolators;
-
-import javax.media.j3d.Alpha;
-import javax.media.j3d.Node;
-import javax.media.j3d.NodeComponent;
-import javax.media.j3d.RestrictedAccessException;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-import javax.media.j3d.TransformInterpolator;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-/**
- * KBSplinePathInterpolator behavior. This class defines the base class for
- * all Kochanek-Bartels (also known as TCB or Tension-Continuity-Bias)
- * Spline Path Interpolators.
- *
- * @since Java3D 1.2
- */
-
-public abstract class KBSplinePathInterpolator extends TransformInterpolator {
-
- private int keysLength;
- /**
- * An array of KBKeyFrame for interpolator
- */
- protected KBKeyFrame[] keyFrames;
-
- /**
- * This value is the distance between knots
- * value which can be used in further calculations by the subclass.
- */
- protected float currentU;
-
- /**
- * The lower knot
- */
- protected int lowerKnot;
- /**
- * The upper knot
- */
- protected int upperKnot;
-
- /**
- * Constructs a KBSplinePathInterpolator node with a null alpha value and
- * a null target of TransformGroup
- *
- * @since Java 3D 1.3
- */
- KBSplinePathInterpolator() {
- }
-
-
- /**
- * @deprecated As of Java 3D version 1.3, replaced by
- * KBSplinePathInterpolator(Alpha, TransformGroup, TCBKeyFrame[])
- */
- public KBSplinePathInterpolator(Alpha alpha, KBKeyFrame keys[]) {
- this(alpha, null, keys);
- }
-
- /**
- * Constructs a new KBSplinePathInterpolator object that interpolates
- * between keyframes with specified alpha, target and an default
- * axisOfTranform set to identity.
- * It takes at least two key frames. The first key
- * frame's knot must have a value of 0.0 and the last knot must have a
- * value of 1.0. An intermediate key frame with index k must have a
- * knot value strictly greater than the knot value of a key frame with
- * index less than k. Once this constructor has all the valid key frames
- * it creates its own list of key fames that duplicates the first key frame
- * at the beginning of the list and the last key frame at the end of the
- * list.
- * @param alpha the alpha object for this interpolator
- * @param target the TransformGroup node affected by this interpolator
- * @param keys an array of KBKeyFrame. Requires at least two key frames.
- *
- * @since Java 3D 1.3
- */
- public KBSplinePathInterpolator(Alpha alpha, TransformGroup target, KBKeyFrame keys[]) {
- super(alpha, target);
- processKeyFrames( keys );
- }
-
- /**
- * Constructs a new KBSplinePathInterpolator object that interpolates
- * between keyframes with specified alpha, target and axisOfTransform.
- * It takes at least two key frames. The first key
- * frame's knot must have a value of 0.0 and the last knot must have a
- * value of 1.0. An intermediate key frame with index k must have a
- * knot value strictly greater than the knot value of a key frame with
- * index less than k. Once this constructor has all the valid key frames
- * it creates its own list of key fames that duplicates the first key frame
- * at the beginning of the list and the last key frame at the end of the
- * list.
- * @param alpha the alpha object for this interpolator
- * @param target the TransformGroup node affected by this interpolator
- * @param axisOfTransform the transform that defines the local coordinate
- * @param keys an array of KBKeyFrame. Requires at least two key frames
- *
- * @since Java 3D 1.3
- */
- public KBSplinePathInterpolator(Alpha alpha,
- TransformGroup target,
- Transform3D axisOfTransform,
- KBKeyFrame keys[]) {
- super(alpha, target, axisOfTransform);
- processKeyFrames( keys );
- }
-
- /**
- * Process the new array of key frames
- */
- private void processKeyFrames( KBKeyFrame[] keys ) {
-
- // Make sure that we have at least two key frames
- keysLength = keys.length;
- if (keysLength < 2) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator0"));
-
- }
-
- // Make sure that the first key frame's knot is equal to 0.0
- if (keys[0].knot < -0.0001 || keys[0].knot > 0.0001) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator1"));
- }
-
- // Make sure that the last key frames knot is equal to 1.0
- if (keys[keysLength-1].knot -1.0 < -0.0001 || keys[keysLength-1].knot -1.0 > 0.0001) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator2"));
- }
-
- // Make sure that all the knots are in sequence
- for (int i = 0; i < keysLength; i++) {
- if (i>0 && keys[i].knot < keys[i-1].knot) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator3"));
- }
- }
-
- // Make space for a leading and trailing key frame in addition to
- // the keys passed in
- keyFrames = new KBKeyFrame[keysLength+2];
- keyFrames[0] = new KBKeyFrame();
- keyFrames[0] = keys[0];
- for (int i = 1; i < keysLength+1; i++) {
- keyFrames[i] = keys[i-1];
- }
- keyFrames[keysLength+1] = new KBKeyFrame();
- keyFrames[keysLength+1] = keys[keysLength-1];
-
- // Make key frame length reflect the 2 added key frames
- keysLength += 2;
- }
-
- /**
- * This method retrieves the length of the key frame array.
- * @return the number of key frames
- */
- public int getArrayLength(){
- return keysLength-2;
- }
-
- /**
- * This method retrieves the key frame at the specified index.
- * @param index the index of the key frame requested
- * @return the key frame at the associated index
- */
- public KBKeyFrame getKeyFrame (int index) {
-
- // We add 1 to index because we have added a leading keyFrame
- return this.keyFrames[index+1];
- }
-
- /**
- * Set the key frame at the specified index to keyFrame
- * @param index Index of the key frame to change
- * @param keyFrame The new key frame
- * @since Java 3D 1.3
- */
- public void setKeyFrame( int index, KBKeyFrame keyFrame ) {
- this.keyFrames[index+1] = keyFrame;
- }
-
- /**
- * Set allthe key frames
- * @param keyFrames The new key frame
- * @since Java 3D 1.3
- */
- public void setKeyFrames( KBKeyFrame[] keyFrames ) {
- processKeyFrames( keyFrames );
- }
-
- /**
- * @deprecated As of Java 3D version 1.3, replaced by
- * computePathInterpolation(float)
- */
- protected void computePathInterpolation() {
- computePathInterpolation(this.getAlpha().value());
- }
-
- /**
- * This method computes the bounding knot indices and interpolation value
- * "CurrentU" given the current value of the knots[] array and the
- * specified alpha value
- * @param alphaValue alpha value between 0.0 and 1.0
- *
- * @since Java 3D 1.3
- */
- protected void computePathInterpolation( float alphaValue ) {
-
- // skip knots till we find the two we fall between
- int i = 1;
- int len = keysLength - 2;
- while ((alphaValue > keyFrames[i].knot) && (i < len)) {
- i++;
- }
-
- if (i == 1) {
- currentU = 0f;
- lowerKnot = 1;
- upperKnot = 2;
- } else {
- currentU = (alphaValue - keyFrames[i-1].knot)/
- (keyFrames[i].knot - keyFrames[i-1].knot);
- lowerKnot = i-1;
- upperKnot = i;
- }
- }
-
- /**
- * Copies all KBSplinePathInterpolator 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
- public void duplicateNode(Node originalNode, boolean forceDuplicate) {
- super.duplicateNode(originalNode, forceDuplicate);
- KBSplinePathInterpolator originalSpline =
- (KBSplinePathInterpolator) originalNode;
- setAlpha(originalSpline.getAlpha());
- keysLength = originalSpline.keysLength;
- keyFrames = new KBKeyFrame[keysLength];
- System.arraycopy(originalSpline.keyFrames, 0,
- keyFrames, 0, keysLength);
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/RotPosScaleTCBSplinePathInterpolator.java b/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/RotPosScaleTCBSplinePathInterpolator.java
deleted file mode 100644
index ab856b2..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/RotPosScaleTCBSplinePathInterpolator.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.interpolators;
-
-import javax.media.j3d.Alpha;
-import javax.media.j3d.Node;
-import javax.media.j3d.NodeComponent;
-import javax.media.j3d.RestrictedAccessException;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-import javax.vecmath.Matrix4d;
-import javax.vecmath.Point3f;
-import javax.vecmath.Quat4f;
-import javax.vecmath.Vector3d;
-import javax.vecmath.Vector3f;
-
-
-/**
- * RotPosScaleTCBSplinePathInterpolator behavior. This class defines a
- * behavior that varies the rotational, translational, and scale components
- * of its target TransformGroup by using the Kochanek-Bartels cubic spline
- * interpolation to interpolate among a series of key frames
- * (using the value generated by the specified Alpha object). The
- * interpolated position, orientation, and scale are used to generate
- * a transform in the local coordinate system of this interpolator.
- *
- * @since Java3D 1.1
- */
-
-public class RotPosScaleTCBSplinePathInterpolator
-extends TCBSplinePathInterpolator {
-
- private Transform3D rotation = new Transform3D();
- private Matrix4d tMat = new Matrix4d();
- private Matrix4d sMat = new Matrix4d();
- private Quat4f iQuat = new Quat4f(); // interpolated quaternion
- private Vector3f iPos = new Vector3f(); // interpolated position
- private Point3f iScale = new Point3f(); // interpolated scale
-
- CubicSplineCurve cubicSplineCurve = new CubicSplineCurve();
- CubicSplineSegment cubicSplineSegments[];
- int numSegments;
- int currentSegmentIndex;
- CubicSplineSegment currentSegment;
-
- // non-public, default constructor used by cloneNode
- RotPosScaleTCBSplinePathInterpolator() {
- }
-
- /**
- * Constructs a new RotPosScaleTCBSplinePathInterpolator object that
- * varies the rotation, translation, and scale of the target
- * TransformGroup's transform. At least 2 key frames are required for
- * this interpolator. The first key
- * frame's knot must have a value of 0.0 and the last knot must have a
- * value of 1.0. An intermediate key frame with index k must have a
- * knot value strictly greater than the knot value of a key frame with
- * index less than k.
- * @param alpha the alpha object for this interpolator
- * @param target the TransformGroup node affected by this interpolator
- * @param axisOfTransform the transform that specifies the local
- * coordinate system in which this interpolator operates.
- * @param keys an array of key frames that defien the motion path
- */
- public RotPosScaleTCBSplinePathInterpolator(Alpha alpha,
- TransformGroup target,
- Transform3D axisOfTransform,
- TCBKeyFrame keys[]) {
- super(alpha, target, axisOfTransform, keys);
- // Create a spline curve using the derived key frames
- cubicSplineCurve = new CubicSplineCurve(this.keyFrames);
- numSegments = cubicSplineCurve.numSegments;
-
- }
-
-
- /**
- * @deprecated As of Java 3D version 1.3, replaced by
- * TransformInterpolator.setTransformAxis(Transform3D)
- */
- public void setAxisOfRotPosScale(Transform3D axisOfRotPosScale) {
- setTransformAxis(axisOfRotPosScale);
- }
-
- /**
- * @deprecated As of Java 3D version 1.3, replaced by
- * TransformInterpolator.getTransformAxis()
- */
- public Transform3D getAxisOfRotPosScale() {
- return getTransformAxis();
- }
-
- /**
- * Computes the new transform for this interpolator for a given
- * alpha value.
- *
- * @param alphaValue alpha value between 0.0 and 1.0
- * @param transform object that receives the computed transform for
- * the specified alpha value
- *
- * @since Java 3D 1.3
- */
- @Override
- public void computeTransform(float alphaValue, Transform3D transform) {
-
- // compute the current value of u from alpha and the
- // determine lower and upper knot points
- computePathInterpolation(alphaValue);
-
- // Determine the segment within which we will be interpolating
- currentSegmentIndex = this.lowerKnot - 1;
-
- // if we are at the start of the curve
- if (currentSegmentIndex == 0 && currentU == 0f) {
-
- iQuat.set(keyFrames[1].quat);
- iPos.set(keyFrames[1].position);
- iScale.set(keyFrames[1].scale);
-
- // if we are at the end of the curve
- } else if (currentSegmentIndex == (numSegments-1) &&
- currentU == 1.0) {
-
- iQuat.set(keyFrames[upperKnot].quat);
- iPos.set(keyFrames[upperKnot].position);
- iScale.set(keyFrames[upperKnot].scale);
-
- // if we are somewhere in between the curve
- } else {
-
- // Get a reference to the current spline segment i.e. the
- // one bounded by lowerKnot and upperKnot
- currentSegment
- = cubicSplineCurve.getSegment(currentSegmentIndex);
-
- // interpolate quaternions
- currentSegment.getInterpolatedQuaternion(currentU,iQuat);
-
- // interpolate position
- currentSegment.getInterpolatedPositionVector(currentU,iPos);
-
- // interpolate position
- currentSegment.getInterpolatedScale(currentU,iScale);
-
- }
-
- // Alway normalize the quaternion
- iQuat.normalize();
- tMat.set(iQuat);
-
- // Set the translation components.
- tMat.m03 = iPos.x;
- tMat.m13 = iPos.y;
- tMat.m23 = iPos.z;
- rotation.set(tMat);
-
- // construct a Transform3D from: axis * rotation * axisInverse
- transform.mul(axis, rotation);
- transform.setScale(new Vector3d(iScale));
- transform.mul(transform, axisInverse);
-
- }
-
- /**
- * Used to create 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.
- *
- * @see Node#cloneTree
- * @see Node#cloneNode
- * @see Node#duplicateNode
- * @see NodeComponent#setDuplicateOnCloneTree
- */
- @Override
- public Node cloneNode(boolean forceDuplicate) {
- RotPosScaleTCBSplinePathInterpolator spline =
- new RotPosScaleTCBSplinePathInterpolator();
- spline.duplicateNode(this, forceDuplicate);
- return spline;
- }
-
- /**
- * Copies RotPosScaleTCBSplinePathInterpolator 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
- public void duplicateNode(Node originalNode, boolean forceDuplicate) {
- super.duplicateNode(originalNode, forceDuplicate);
- RotPosScaleTCBSplinePathInterpolator interpolator =
- (RotPosScaleTCBSplinePathInterpolator)originalNode;
-
- cubicSplineCurve = new CubicSplineCurve(interpolator.keyFrames);
- numSegments = cubicSplineCurve.numSegments;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBKeyFrame.java b/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBKeyFrame.java
deleted file mode 100644
index 2b5db45..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBKeyFrame.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.interpolators;
-
-import javax.vecmath.Point3f;
-import javax.vecmath.Quat4f;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-/**
- * This class represents a Key Frame that can be used for Kochanek-Bartels
- * (TCB) spline interpolation.
- *
- * @since Java3D 1.1
- */
-
-public class TCBKeyFrame {
-
- // Position, Rotation and Scale
- public Point3f position;
- public Quat4f quat;
- public Point3f scale;
-
- // Tension, Continuity & Bias
- public float tension;
- public float continuity;
- public float bias;
-
- // Sample Time
- public float knot;
-
- // Interpolation type (linear = 0 -> spline interpolation)
- public int linear;
-
- // default constructor
- TCBKeyFrame () {
- tension = continuity = bias = 0.0f;
- }
-
- public TCBKeyFrame (TCBKeyFrame kf) {
- this(kf.knot, kf.linear, kf.position, kf.quat, kf.scale,
- kf.tension, kf.continuity, kf.bias);
-
- }
-
- /**
- * Creates a key frame using the given inputs.
- *
- * @param k knot value for this key frame
- * @param l the linear flag (0 - Spline Interp, 1, Linear Interp
- * @param pos the position at the key frame
- * @param q the rotations at the key frame
- * @param s the scales at the key frame
- * @param t tension (-1.0 < t < 1.0)
- * @param c continuity (-1.0 < c < 1.0)
- * @param b bias (-1.0 < b < 1.0)
- */
- public TCBKeyFrame (float k, int l, Point3f pos, Quat4f q, Point3f s,
- float t, float c, float b) {
-
- knot = k;
- linear = l;
- position = new Point3f(pos);
- quat = new Quat4f(q);
- scale = new Point3f(s);
-
- // Check for valid tension continuity and bias values
- if (t < -1.0f || t > 1.0f) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBKeyFrame0"));
- }
-
- if (b < -1.0f || b > 1.0f) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBKeyFrame1"));
- }
-
- if (c < -1.0f || c > 1.0f) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBKeyFrame2"));
- }
-
- // copy valid tension, continuity and bias values
- tension = t;
- continuity = c;
- bias = b;
- }
-
- /**
- * Prints information comtained in this key frame
- * @param tag string tag for identifying debug message
- */
- public void debugPrint (String tag) {
- System.out.println ("\n" + tag);
- System.out.println (" knot = " + knot);
- System.out.println (" linear = " + linear);
- System.out.println (" position(x,y,z) = " + position.x + " "
- + position.y + " " + position.z);
-
- System.out.println (" tension = " + tension);
- System.out.println (" continuity = " + continuity);
- System.out.println (" bias = " + bias);
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBSplinePathInterpolator.java b/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBSplinePathInterpolator.java
deleted file mode 100644
index b8fe090..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/TCBSplinePathInterpolator.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.interpolators;
-
-import javax.media.j3d.Alpha;
-import javax.media.j3d.Node;
-import javax.media.j3d.NodeComponent;
-import javax.media.j3d.RestrictedAccessException;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-import javax.media.j3d.TransformInterpolator;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-/**
- * TCBSplinePathInterpolator behavior. This class defines the base class for
- * all TCB (Kochanek-Bartels) Spline Path Interpolators.
- *
- * @since Java3D 1.1
- */
-
-public abstract class TCBSplinePathInterpolator extends TransformInterpolator {
-
- private int keysLength;
-
- /**
- * An array of KBKeyFrame for interpolator
- */
- protected TCBKeyFrame[] keyFrames;
-
- /**
- * This value is the distance between knots
- * value which can be used in further calculations by the subclass.
- */
- protected float currentU;
-
- /**
- * The lower knot
- */
- protected int lowerKnot;
-
- /**
- * The upper knot
- */
- protected int upperKnot;
-
- /**
- * Constructs a TCBSplinePathInterpolator node with a null alpha value and
- * a null target of TransformGroup
- *
- * @since Java 3D 1.3
- */
-
- TCBSplinePathInterpolator() {
- }
-
- /**
- * @deprecated As of Java 3D version 1.3, replaced by
- * TCBSplinePathInterpolator(Alpha, TransformGroup, TCBKeyFrame[])
- */
- public TCBSplinePathInterpolator(Alpha alpha, TCBKeyFrame keys[]) {
- this(alpha, null, keys);
- }
-
- /**
- * Constructs a new TCBSplinePathInterpolator object that interpolates
- * between keyframes with specified alpha, target and default axisOfTransform
- * set to identity. It takes at least two key frames. The first key
- * frame's knot must have a value of 0.0 and the last knot must have a
- * value of 1.0. An intermediate key frame with index k must have a
- * knot value strictly greater than the knot value of a key frame with
- * index less than k. Once this constructor has all the valid key frames
- * it creates its own list of key fames that duplicates the first key frame
- * at the beginning of the list and the last key frame at the end of the
- * list.
- * @param alpha the alpha object for this interpolator
- * @param target the TransformGroup node effected by this TCBSplinePathInterpolator
- * @param keys an array of TCBKeyFrame. Requires at least two key frames.
- *
- * @since Java 3D 1.3
- */
- public TCBSplinePathInterpolator(Alpha alpha, TransformGroup target, TCBKeyFrame keys[]) {
- super(alpha, target);
- processKeyFrames(keys);
- }
-
- /**
- * Constructs a new TCBSplinePathInterpolator object that interpolates
- * between keyframes with specified alpha, target and axisOfTransform.
- * It takes at least two key frames. The first key
- * frame's knot must have a value of 0.0 and the last knot must have a
- * value of 1.0. An intermediate key frame with index k must have a
- * knot value strictly greater than the knot value of a key frame with
- * index less than k. Once this constructor has all the valid key frames
- * it creates its own list of key fames that duplicates the first key frame
- * at the beginning of the list and the last key frame at the end of the
- * list.
- * @param alpha the alpha object for this interpolator
- * @param target the TransformGroup node effected by this TCBSplinePathInterpolator
- * @param axisOfTransform the transform that defines the local coordinate
- * @param keys an array of TCBKeyFrame. Requires at least two key frames.
- *
- * @since Java 3D 1.3
- */
- public TCBSplinePathInterpolator(Alpha alpha, TransformGroup target, Transform3D axisOfTransform,
- TCBKeyFrame keys[]) {
- super(alpha, target, axisOfTransform);
- processKeyFrames(keys);
- }
-
- /**
- * Process the new array of key frames
- */
- private void processKeyFrames( TCBKeyFrame keys[] ){
-
- // Make sure that we have at least two key frames
- keysLength = keys.length;
- if (keysLength < 2) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator0"));
-
- }
-
- // Make sure that the first key frame's knot is equal to 0.0
- if (keys[0].knot < -0.0001 || keys[0].knot > 0.0001) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator1"));
- }
-
- // Make sure that the last key frames knot is equal to 1.0
- if (keys[keysLength-1].knot -1.0 < -0.0001 || keys[keysLength-1].knot -1.0 > 0.0001) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator2"));
- }
-
- // Make sure that all the knots are in sequence
- for (int i = 0; i < keysLength; i++) {
- if (i>0 && keys[i].knot < keys[i-1].knot) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator3"));
- }
- }
-
- // Make space for a leading and trailing key frame in addition to
- // the keys passed in
- keyFrames = new TCBKeyFrame[keysLength+2];
- keyFrames[0] = new TCBKeyFrame();
- keyFrames[0] = keys[0];
- for (int i = 1; i < keysLength+1; i++) {
- keyFrames[i] = keys[i-1];
- }
- keyFrames[keysLength+1] = new TCBKeyFrame();
- keyFrames[keysLength+1] = keys[keysLength-1];
-
- // Make key frame length reflect the 2 added key frames
- keysLength += 2;
- }
-
- /**
- * This method retrieves the length of the key frame array.
- * @return the number of key frames
- */
- public int getArrayLength(){
- return keysLength-2;
- }
-
- /**
- * This method retrieves the key frame at the specified index.
- * @param index the index of the key frame requested
- * @return the key frame at the associated index
- */
- public TCBKeyFrame getKeyFrame (int index) {
-
- // We add 1 to index because we have added a leading keyFrame
- return this.keyFrames[index+1];
- }
-
- /**
- * This method computes the bounding knot indices and interpolation value
- * "CurrentU" given the specified value of alpha and the knots[] array.
- * @param alphaValue alpha value between 0.0 and 1.0
- *
- * @since Java 3D 1.3
- */
- protected void computePathInterpolation(float alphaValue) {
-
- // skip knots till we find the two we fall between
- int i = 1;
- int len = keysLength - 2;
- while ((alphaValue > keyFrames[i].knot) && (i < len)) {
- i++;
- }
-
- if (i == 1) {
- currentU = 0f;
- lowerKnot = 1;
- upperKnot = 2;
- } else {
- currentU = (alphaValue - keyFrames[i-1].knot)/
- (keyFrames[i].knot - keyFrames[i-1].knot);
- lowerKnot = i-1;
- upperKnot = i;
- }
- }
-
- /**
- * @deprecated As of Java 3D version 1.3, replaced by
- * computePathInterpolation(float)
- */
- protected void computePathInterpolation() {
- float value = (this.getAlpha()).value();
- computePathInterpolation(value);
- }
-
- /**
- * Copies all TCBSplinePathInterpolator 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
- public void duplicateNode(Node originalNode, boolean forceDuplicate) {
- super.duplicateNode(originalNode, forceDuplicate);
- TCBSplinePathInterpolator originalSpline = (TCBSplinePathInterpolator) originalNode;
- setAlpha(originalSpline.getAlpha());
- keysLength = originalSpline.keysLength;
- keyFrames = new TCBKeyFrame[keysLength];
- System.arraycopy(originalSpline.keyFrames, 0,
- keyFrames, 0, keysLength);
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/package.html b/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/package.html
deleted file mode 100644
index 7f18f4a..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/interpolators/package.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
Provides spline-based interpolation behaviors.
- - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigator.java b/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigator.java deleted file mode 100644 index 1df3d62..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigator.java +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.keyboard; - -import java.awt.event.KeyEvent; - -import javax.media.j3d.Transform3D; -import javax.media.j3d.TransformGroup; -import javax.vecmath.Matrix4d; -import javax.vecmath.Point3d; -import javax.vecmath.Quat4d; -import javax.vecmath.Vector3d; - -/** - * This is the KeyNavigator class. It accumulates AWT key events (key - * press and key release) and computes a new transform based on the - * accumulated events and elapsed time. - */ -public class KeyNavigator { - - private Vector3d navVec; - private long time; - - private Vector3d fwdAcc; - private Vector3d bwdAcc; - private Vector3d leftAcc; - private Vector3d rightAcc; - private Vector3d upAcc; - private Vector3d downAcc; - - private Vector3d fwdDrag; - private Vector3d bwdDrag; - private Vector3d leftDrag; - private Vector3d rightDrag; - private Vector3d upDrag; - private Vector3d downDrag; - - private double fwdVMax; - private double bwdVMax; - private double leftVMax; - private double rightVMax; - private double upVMax; - private double downVMax; - - private float leftRotAngle; - private float rightRotAngle; - private float upRotAngle; - private float downRotAngle; - - private double mmx; - - private Vector3d a = new Vector3d(); - private Vector3d dv = new Vector3d(); - private Point3d dp = new Point3d(); - private Quat4d udQuat = new Quat4d(); - private Quat4d lrQuat = new Quat4d(); - private Vector3d vpPos = new Vector3d(); - private double vpScale; - private Quat4d vpQuat = new Quat4d(); - private Matrix4d vpMatrix = new Matrix4d(); - private Transform3D vpTrans = new Transform3D(); - private Matrix4d mat = new Matrix4d(); - private Vector3d nda = new Vector3d(); - private Vector3d temp = new Vector3d(); - private Transform3D nominal = new Transform3D(); - private TransformGroup targetTG; - - private static final int UP_ARROW = (1<<0); - private static final int DOWN_ARROW = (1<<1); - private static final int LEFT_ARROW = (1<<2); - private static final int RIGHT_ARROW = (1<<3); - private static final int PLUS_SIGN = (1<<4); - private static final int MINUS_SIGN = (1<<5); - private static final int PAGE_UP = (1<<6); - private static final int PAGE_DOWN = (1<<7); - private static final int HOME_DIR = (1<<8); - private static final int HOME_NOMINAL = (1<<9); - - private static final int SHIFT = (1<<10); - private static final int ALT = (1<<11); - private static final int META = (1<<12); - - private static final int KEY_UP = (1<<13); - private static final int KEY_DOWN = (1<<14); - - private int key_state = 0; - private int modifier_key_state = 0; - - - /** - * Constructs a new key navigator object that operates on the specified - * transform group. All parameters are set to their default, idle state. - * @param targetTG the target transform group - */ - public KeyNavigator(TransformGroup targetTG) { - this.targetTG = targetTG; - targetTG.getTransform(nominal); - - mmx = 128.0; - navVec = new Vector3d(0.0,0.0,0.0); - - fwdAcc = new Vector3d( 0.0, 0.0,-mmx); - bwdAcc = new Vector3d( 0.0, 0.0, mmx); - leftAcc = new Vector3d(-mmx, 0.0, 0.0); - rightAcc = new Vector3d( mmx, 0.0, 0.0); - upAcc = new Vector3d( 0.0, mmx, 0.0); - downAcc = new Vector3d( 0.0,-mmx, 0.0); - - fwdDrag = new Vector3d( 0.0, 0.0, mmx); - bwdDrag = new Vector3d( 0.0, 0.0,-mmx); - leftDrag = new Vector3d( mmx, 0.0, 0.0); - rightDrag = new Vector3d(-mmx, 0.0, 0.0); - upDrag = new Vector3d( 0.0,-mmx, 0.0); - downDrag = new Vector3d( 0.0, mmx, 0.0); - - fwdVMax = -mmx; - bwdVMax = mmx; - leftVMax = -mmx; - rightVMax = mmx; - upVMax = mmx; - downVMax = -mmx; - - leftRotAngle = (float) (-Math.PI*2.0/3.0); - rightRotAngle = (float) (Math.PI*2.0/3.0); - upRotAngle = (float) (Math.PI*2.0/3.0); - downRotAngle = (float) (-Math.PI*2.0/3.0); - - // Create Timer here. - time = System.currentTimeMillis(); - - } - - - private long getDeltaTime() { - long newTime = System.currentTimeMillis(); - long deltaTime = newTime - time; - time = newTime; - if (deltaTime > 2000) return 0; - else return deltaTime; - } - - /* Generate a quaterion as a rotation of radians av about 0/x 1/y 2/z axis */ - private void genRotQuat(double av, int axis, Quat4d q) { - double b; - - q.x = q.y = q.z = 0.0; - q.w = Math.cos(av/2.0); - - b = 1.0 - q.w*q.w; - - if (b > 0.0) - b = Math.sqrt(b); - else - return; - - if (av < 0.0) - b = -b; - if (axis == 0) - q.x = b; - else if (axis == 1) - q.y = b; - else - q.z = b; - - } - - private void accKeyAdd(Vector3d a, Vector3d da, Vector3d drag, double scaleVel) { - - /* Scaling of acceleration due to modification keys */ - nda.scale(scaleVel, da); - /* Addition of sufficent acceleration to counteract drag */ - nda.sub(drag); - - /* Summing into overall acceleration */ - a.add(nda); - - } - - - /** - * Computes a new transform for the next frame based on - * the current transform, accumulated keyboard inputs, and - * elapsed time. This new transform is written into the target - * transform group. - * This method should be called once per frame. - */ - public void integrateTransformChanges() { - double scaleVel, scaleRot, scaleScale, pre; - double udAng, lrAng, r; - - // Get the current View Platform transform into a transform3D object. - targetTG.getTransform(vpTrans); - // Extract the position, quaterion, and scale from the transform3D. - vpScale = vpTrans.get(vpQuat, vpPos); - - - double deltaTime = (double) getDeltaTime(); - deltaTime *= 0.001; - - /* Calculate scale due to modification keys */ - if ((modifier_key_state & SHIFT) != 0 && - (modifier_key_state & META) == 0) { - scaleVel = 3.0; scaleRot = 2.0; scaleScale = 4.0; - } - else if ((modifier_key_state & SHIFT) == 0 && - (modifier_key_state & META) != 0) { - scaleVel = 0.1; scaleRot = 0.1; scaleScale = 0.1; - } - else if ((modifier_key_state & SHIFT) != 0 && - (modifier_key_state & META) != 0) { - scaleVel = 0.3; scaleRot = 0.5; scaleScale = 0.1; - } - else { - scaleRot = scaleVel = 1.0; scaleScale = 4.0; - } - - /* - * Processing of rectiliear motion keys. - */ - - a.x = a.y = a.z = 0.0; /* acceleration initially 0 */ - - /* Acceleration due to keys being down */ - if ((key_state & UP_ARROW) != 0 && (key_state & DOWN_ARROW) == 0) - accKeyAdd(a, fwdAcc, fwdDrag, scaleVel); - else - if ((key_state & UP_ARROW) == 0 && (key_state & DOWN_ARROW) != 0) - accKeyAdd(a, bwdAcc, bwdDrag, scaleVel); - - if (((modifier_key_state & ALT) != 0) && - (key_state & LEFT_ARROW) != 0 && (key_state & RIGHT_ARROW) == 0) { - accKeyAdd(a, leftAcc, leftDrag, scaleVel); - } else - if (((modifier_key_state & ALT) != 0) && - (key_state & LEFT_ARROW) == 0 && (key_state & RIGHT_ARROW) != 0) - accKeyAdd(a, rightAcc, rightDrag, scaleVel); - - if (((modifier_key_state & ALT) != 0) && - (key_state & PAGE_UP) != 0 && (key_state & PAGE_DOWN) == 0) - accKeyAdd(a, upAcc, upDrag, scaleVel); - else - if (((modifier_key_state & ALT) != 0) && - (key_state & PAGE_UP) == 0 && (key_state & PAGE_DOWN) != 0) - accKeyAdd(a, downAcc, downDrag, scaleVel); - - - /* - * Drag due to new or existing motion - */ - pre = navVec.z + a.z * deltaTime; - if (pre < 0.0) { - if (pre + fwdDrag.z * deltaTime < 0.0) - a.add(fwdDrag); - else - a.z -= pre/deltaTime; - } else if (pre > 0.0) { - if (pre + bwdDrag.z * deltaTime > 0.0) - a.add(bwdDrag); - else - a.z -= pre/deltaTime; - } - - pre = navVec.x + a.x * deltaTime; - if (pre < 0.0) { - if (pre + leftDrag.x * deltaTime < 0.0) - a.add(leftDrag); - else - a.x -= pre/deltaTime; - } else if (pre > 0.0) { - if (pre + rightDrag.x * deltaTime > 0.0) - a.add(rightDrag); - else - a.x -= pre/deltaTime; - } - - pre = navVec.y + a.y * deltaTime; - if (pre < 0.0) { - if (pre + downDrag.y * deltaTime < 0.0) - a.add(downDrag); - else - a.y -= pre/deltaTime; - } else if (pre > 0.0) { - if (pre + upDrag.y * deltaTime > 0.0) - a.add(upDrag); - else - a.y -= pre/deltaTime; - } - - /* Integration of acceleration to velocity */ - dv.scale(deltaTime, a); - navVec.add(dv); - - /* Speed limits */ - if (navVec.z < scaleVel * fwdVMax) navVec.z = scaleVel * fwdVMax; - if (navVec.z > scaleVel * bwdVMax) navVec.z = scaleVel * bwdVMax; - if (navVec.x < scaleVel * leftVMax) navVec.x = scaleVel * leftVMax; - if (navVec.x > scaleVel * rightVMax) navVec.x = scaleVel* rightVMax; - if (navVec.y > scaleVel * upVMax) navVec.y = scaleVel * upVMax; - if (navVec.y < scaleVel * downVMax) navVec.y = scaleVel * downVMax; - - /* Integration of velocity to distance */ - dp.scale(deltaTime, navVec); - - /* Scale our motion to the current avatar scale */ - // 1.0 eventually needs to be a more complex value (see hs). - // r = workplace_coexistence_to_vworld_ori.scale/ - // one_to_one_coexistence_to_vworld_ori.scale; - r = vpScale/1.0; - dp.scale(r, dp); - - /* - * Processing of rotation motion keys. - */ - udAng = lrAng = 0.0; - - /* Rotation due to keys being down */ - if (((modifier_key_state & ALT) == 0) && - (key_state & LEFT_ARROW) != 0 && (key_state & RIGHT_ARROW) == 0) - lrAng = (double) leftRotAngle; - else if (((modifier_key_state & ALT) == 0) && - (key_state & LEFT_ARROW) == 0 && (key_state & RIGHT_ARROW) != 0) - lrAng = (double) rightRotAngle; - - if (((modifier_key_state & ALT) == 0) && - (key_state & PAGE_UP) != 0 && (key_state & PAGE_DOWN) == 0) - udAng = (double) upRotAngle; - else if (((modifier_key_state & ALT) == 0) && - (key_state & PAGE_UP) == 0 && (key_state & PAGE_DOWN) != 0) - udAng = (double) downRotAngle; - - lrAng *= scaleRot; - udAng *= scaleRot; - - /* Scaling of angle change to delta time */ - lrAng *= deltaTime; - udAng *= deltaTime; - - - /* Addition to existing orientation */ - // vr_quat_inverse(&workplace_coexistence_to_vworld_ori.quat, &vpQuat); - // vpQuat gotten at top of method. - vpQuat.inverse(); - - if(lrAng != 0.0) { - genRotQuat(lrAng, 1, lrQuat); - vpQuat.mul(lrQuat, vpQuat); - } - - if(udAng != 0.0) { - genRotQuat(udAng, 0, udQuat); - vpQuat.mul(udQuat, vpQuat); - } - - /* Rotation of distance vector */ - vpQuat.inverse(); - vpQuat.normalize(); /* Improvment over HoloSketch */ - mat.set(vpQuat); - mat.transform(dp); - - /* Processing of scale */ - if ((key_state & PLUS_SIGN) != 0) { - vpScale *= (1.0 + (scaleScale*deltaTime)); - if (vpScale > 10e+14) vpScale = 1.0; - } else if ((key_state & MINUS_SIGN) != 0) { - vpScale /= (1.0 + (scaleScale*deltaTime)); - if (vpScale < 10e-14) vpScale = 1.0; - } - - // add dp into current vp position. - vpPos.add(dp); - - if ((key_state & HOME_NOMINAL) != 0) { - resetVelocity(); - // Extract the position, quaterion, and scale from the nominal - // transform - vpScale = nominal.get(vpQuat, vpPos); - } - - - /* Final update of view platform */ - // Put the transform back into the transform group. - vpTrans.set(vpQuat, vpPos, vpScale); - targetTG.setTransform(vpTrans); - } - - - /** - * Resets the keyboard navigation velocity to 0. - */ - private void resetVelocity() { - navVec.x = navVec.y = navVec.z = 0.0; - } - - - /** - * Processed a keyboard event. This routine should be called - * every time a KEY_PRESSED or KEY_RELEASED event is received. - * @param keyEvent the AWT key event - */ - public void processKeyEvent(KeyEvent keyEvent) { - int keyCode = keyEvent.getKeyCode(); - int keyChar = keyEvent.getKeyChar(); - -//System.err.println("keyCode " + keyCode + " keyChar " + keyChar); - - if (keyEvent.getID() == KeyEvent.KEY_RELEASED) { - if (keyChar == '+') key_state &= ~PLUS_SIGN; - else - switch (keyCode) { - case KeyEvent.VK_UP: key_state &= ~UP_ARROW; break; - case KeyEvent.VK_DOWN: key_state &= ~DOWN_ARROW; break; - case KeyEvent.VK_LEFT: key_state &= ~LEFT_ARROW; break; - case KeyEvent.VK_RIGHT: key_state &= ~RIGHT_ARROW; break; - case KeyEvent.VK_PAGE_UP: key_state &= ~PAGE_UP; break; - case KeyEvent.VK_PAGE_DOWN: key_state &= ~PAGE_DOWN; break; - case KeyEvent.VK_EQUALS: key_state &= ~HOME_NOMINAL;break; - default: switch(keyChar) { - case '-': key_state &= ~MINUS_SIGN; break; - } - } - } else if (keyEvent.getID() == KeyEvent.KEY_PRESSED) { - if (keyChar == '+') key_state |= PLUS_SIGN; - switch (keyCode) { - case KeyEvent.VK_UP: key_state |= UP_ARROW; break; - case KeyEvent.VK_DOWN: key_state |= DOWN_ARROW; break; - case KeyEvent.VK_LEFT: key_state |= LEFT_ARROW; break; - case KeyEvent.VK_RIGHT: key_state |= RIGHT_ARROW; break; - case KeyEvent.VK_PAGE_UP: key_state |= PAGE_UP; break; - case KeyEvent.VK_PAGE_DOWN: key_state |= PAGE_DOWN; break; - case KeyEvent.VK_EQUALS: key_state |= HOME_NOMINAL;break; - default: switch(keyChar) { - case '-': key_state |= MINUS_SIGN; break; - } - } - } - - /* Check modifier keys */ - if (keyEvent.isShiftDown()) - modifier_key_state |= SHIFT; - else - modifier_key_state &= ~SHIFT; - - if (keyEvent.isMetaDown()) - modifier_key_state |= META; - else - modifier_key_state &= ~META; - - if (keyEvent.isAltDown()) - modifier_key_state |= ALT; - else - modifier_key_state &= ~ALT; - -//System.err.println("keyCode " + keyEvent.getKeyCode() + " modifiers " + keyEvent.getModifiers()); -//System.err.println("SHIFT_MASK " + keyEvent.SHIFT_MASK); -//System.err.println("CTRL_MASK " + keyEvent.CTRL_MASK); -//System.err.println("META_MASK " + keyEvent.META_MASK); -//System.err.println("ALT_MASK " + keyEvent.ALT_MASK); - - } -} diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigatorBehavior.java b/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigatorBehavior.java deleted file mode 100644 index 4d38238..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/KeyNavigatorBehavior.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.keyboard; - -import java.awt.AWTEvent; -import java.awt.Component; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.util.Enumeration; -import java.util.LinkedList; - -import javax.media.j3d.Behavior; -import javax.media.j3d.TransformGroup; -import javax.media.j3d.WakeupCondition; -import javax.media.j3d.WakeupCriterion; -import javax.media.j3d.WakeupOnAWTEvent; -import javax.media.j3d.WakeupOnBehaviorPost; -import javax.media.j3d.WakeupOnElapsedFrames; -import javax.media.j3d.WakeupOr; - -import com.sun.j3d.internal.J3dUtilsI18N; - -/** - * This class is a simple behavior that invokes the KeyNavigator - * to modify the view platform transform. - */ -public class KeyNavigatorBehavior extends Behavior implements KeyListener { - private WakeupCriterion w1 = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED); - private WakeupCriterion w2 = new WakeupOnAWTEvent(KeyEvent.KEY_RELEASED); - private WakeupOnElapsedFrames w3 = new WakeupOnElapsedFrames(0); - private WakeupCriterion[] warray = { w1, w2, w3 }; - private WakeupCondition w = new WakeupOr(warray); - private KeyEvent eventKey; - private KeyNavigator keyNavigator; - private boolean listener = false; - - private LinkedList eventq; - - - /** - * Override Behavior's initialize method to setup wakeup criteria. - */ - @Override - public void initialize() { - // Establish initial wakeup criteria - if (listener) { - w1 = new WakeupOnBehaviorPost(this, KeyEvent.KEY_PRESSED); - w2 = new WakeupOnBehaviorPost(this, KeyEvent.KEY_RELEASED); - warray[0] = w1; - warray[1] = w2; - w = new WakeupOr(warray); - eventq = new LinkedList(); - } - wakeupOn(w); - } - - /** - * Override Behavior's stimulus method to handle the event. - */ - @Override - public void processStimulus(Enumeration criteria) { - WakeupOnAWTEvent ev; - WakeupCriterion genericEvt; - AWTEvent[] events; - boolean sawFrame = false; - - while (criteria.hasMoreElements()) { - genericEvt = (WakeupCriterion) criteria.nextElement(); - if (genericEvt instanceof WakeupOnAWTEvent) { - ev = (WakeupOnAWTEvent) genericEvt; - events = ev.getAWTEvent(); - processAWTEvent(events); - } else if (genericEvt instanceof WakeupOnElapsedFrames && - eventKey != null) { - sawFrame = true; - } else if ((genericEvt instanceof WakeupOnBehaviorPost)) { - while(true) { - // access to the queue must be synchronized - synchronized (eventq) { - if (eventq.isEmpty()) break; - eventKey = (KeyEvent)eventq.remove(0); - if (eventKey.getID() == KeyEvent.KEY_PRESSED || - eventKey.getID() == KeyEvent.KEY_RELEASED) { - keyNavigator.processKeyEvent(eventKey); - } - } - } - } - } - if (sawFrame) - keyNavigator.integrateTransformChanges(); - - // Set wakeup criteria for next time - wakeupOn(w); - } - - /** - * Process a keyboard event - */ - private void processAWTEvent(AWTEvent[] events) { - for (int loop = 0; loop < events.length; loop++) { - if (events[loop] instanceof KeyEvent) { - eventKey = (KeyEvent) events[loop]; - // change the transformation; for example to zoom - if (eventKey.getID() == KeyEvent.KEY_PRESSED || - eventKey.getID() == KeyEvent.KEY_RELEASED) { - //System.out.println("Keyboard is hit! " + eventKey); - keyNavigator.processKeyEvent(eventKey); - } - } - } - } - - /** - * Adds this behavior as a KeyListener to the specified component. - * This method can only be called if - * the behavior was created with one of the constructors that takes - * a Component as a parameter. - * @param c The component to add the KeyListener to. - * @exception IllegalStateException if the behavior was not created - * as a listener - * @since Java 3D 1.2.1 - */ - public void addListener(Component c) { - if (!listener) { - throw new IllegalStateException(J3dUtilsI18N.getString("Behavior0")); - } - c.addKeyListener(this); - } - - /** - * Constructs a new key navigator behavior node that operates - * on the specified transform group. - * @param targetTG the target transform group - */ - public KeyNavigatorBehavior(TransformGroup targetTG) { - keyNavigator = new KeyNavigator(targetTG); - } - - /** - * Constructs a key navigator behavior that uses AWT listeners - * and behavior posts rather than WakeupOnAWTEvent. The behavior - * is added to the specified Component and works on the given - * TransformGroup. A null component can be passed to specify - * the behavior should use listeners. Components can then be added - * to the behavior with the addListener(Component c) method. - * @param c The component to add the KeyListener to. - * @param targetTG The target transform group. - * @since Java 3D 1.2.1 - */ - public KeyNavigatorBehavior(Component c, TransformGroup targetTG) { - this(targetTG); - if (c != null) { - c.addKeyListener(this); - } - listener = true; - } - - @Override - public void keyPressed(KeyEvent evt) { -// System.out.println("keyPressed"); - - // add new event to the queue - // must be MT safe - synchronized (eventq) { - eventq.add(evt); - // only need to post if this is the only event in the queue - if (eventq.size() == 1) postId(KeyEvent.KEY_PRESSED); - } - } - - @Override - public void keyReleased(KeyEvent evt) { -// System.out.println("keyReleased"); - - // add new event to the queue - // must be MT safe - synchronized (eventq) { - eventq.add(evt); - // only need to post if this is the only event in the queue - if (eventq.size() == 1) postId(KeyEvent.KEY_RELEASED); - } - } - - @Override - public void keyTyped(KeyEvent evt) {} - -} diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/package.html b/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/package.html deleted file mode 100644 index b22646e..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/keyboard/package.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - -Provides keyboard navigation utility classes.
- - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehavior.java b/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehavior.java deleted file mode 100644 index 73b2b25..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehavior.java +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.mouse; - -import java.awt.Component; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; -import java.util.Enumeration; -import java.util.LinkedList; - -import javax.media.j3d.Behavior; -import javax.media.j3d.Transform3D; -import javax.media.j3d.TransformGroup; -import javax.media.j3d.WakeupCriterion; -import javax.media.j3d.WakeupOnAWTEvent; -import javax.media.j3d.WakeupOnBehaviorPost; -import javax.media.j3d.WakeupOr; - -import com.sun.j3d.internal.J3dUtilsI18N; - - -/** - * Base class for all mouse manipulators (see MouseRotate, MouseZoom - * and MouseTranslate for - * examples of how to extend this base class). - */ - -public abstract class MouseBehavior extends Behavior - implements MouseListener, MouseMotionListener, MouseWheelListener { - - private boolean listener = false; - - protected WakeupCriterion[] mouseEvents; - protected WakeupOr mouseCriterion; - protected int x, y; - protected int x_last, y_last; - protected TransformGroup transformGroup; - protected Transform3D transformX; - protected Transform3D transformY; - protected Transform3D currXform; - protected boolean buttonPress = false; - protected boolean reset = false; - protected boolean invert = false; - protected boolean wakeUp = false; - protected int flags = 0; - - // to queue the mouse events - protected LinkedList mouseq; - - // true if this behavior is enable - protected boolean enable = true; - - /** - * Set this flag if you want to manually wakeup the behavior. - */ - public static final int MANUAL_WAKEUP = 0x1; - - /** - * Set this flag if you want to invert the inputs. This is useful when - * the transform for the view platform is being changed instead of the - * transform for the object. - */ - public static final int INVERT_INPUT = 0x2; - - /** - * Creates a mouse behavior object with a given transform group. - * @param transformGroup The transform group to be manipulated. - */ - public MouseBehavior(TransformGroup transformGroup) { - super(); - // need to remove old behavior from group - this.transformGroup = transformGroup; - currXform = new Transform3D(); - transformX = new Transform3D(); - transformY = new Transform3D(); - reset = true; - } - - /** - * Initializes standard fields. Note that this behavior still - * needs a transform group to work on (use setTransformGroup(tg)) and - * the transform group must add this behavior. - * @param format flags - */ - public MouseBehavior(int format) { - super(); - flags = format; - currXform = new Transform3D(); - transformX = new Transform3D(); - transformY = new Transform3D(); - reset = true; - } - - /** - * Creates a mouse behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behaviors is added to - * the specified Component and works on the given TransformGroup. - * A null component can be passed to specify the behaviors should use - * listeners. Components can then be added to the behavior with the - * addListener(Component c) method. - * @param c The Component to add the MouseListener and - * MouseMotionListener to. - * @param transformGroup The TransformGroup to operate on. - * @since Java 3D 1.2.1 - */ - public MouseBehavior(Component c, TransformGroup transformGroup) { - this(transformGroup); - if (c != null) { - c.addMouseListener(this); - c.addMouseMotionListener(this); - c.addMouseWheelListener(this); - } - listener = true; - } - - /** - * Creates a mouse behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behavior is added to the - * specified Component. A null component can be passed to specify - * the behavior should use listeners. Components can then be added - * to the behavior with the addListener(Component c) method. - * Note that this behavior still needs a transform - * group to work on (use setTransformGroup(tg)) and the transform - * group must add this behavior. - * @param format interesting flags (wakeup conditions). - * @since Java 3D 1.2.1 - */ - public MouseBehavior(Component c, int format) { - this(format); - if (c != null) { - c.addMouseListener(this); - c.addMouseMotionListener(this); - c.addMouseWheelListener(this); - } - listener = true; - } - - /** - * Swap a new transformGroup replacing the old one. This allows - * manipulators to operate on different nodes. - * - * @param transformGroup The *new* transform group to be manipulated. - */ - public void setTransformGroup(TransformGroup transformGroup){ - // need to remove old behavior from group - this.transformGroup = transformGroup; - currXform = new Transform3D(); - transformX = new Transform3D(); - transformY = new Transform3D(); - reset = true; - } - - /** - * Return the transformGroup on which this node is operating - */ - public TransformGroup getTransformGroup() { - return this.transformGroup; - } - - /** Initializes the behavior. - */ - - @Override - public void initialize() { - mouseEvents = new WakeupCriterion[4]; - - if (!listener) { - mouseEvents[0] = new WakeupOnAWTEvent(MouseEvent.MOUSE_DRAGGED); - mouseEvents[1] = new WakeupOnAWTEvent(MouseEvent.MOUSE_PRESSED); - mouseEvents[2] = new WakeupOnAWTEvent(MouseEvent.MOUSE_RELEASED); - mouseEvents[3] = new WakeupOnAWTEvent(MouseEvent.MOUSE_WHEEL); - } - else { - mouseEvents[0] = new WakeupOnBehaviorPost(this, - MouseEvent.MOUSE_DRAGGED); - mouseEvents[1] = new WakeupOnBehaviorPost(this, - MouseEvent.MOUSE_PRESSED); - mouseEvents[2] = new WakeupOnBehaviorPost(this, - MouseEvent.MOUSE_RELEASED); - mouseEvents[3] = new WakeupOnBehaviorPost(this, - MouseEvent.MOUSE_WHEEL); - mouseq = new LinkedList(); - } - mouseCriterion = new WakeupOr(mouseEvents); - wakeupOn (mouseCriterion); - x = 0; - y = 0; - x_last = 0; - y_last = 0; - } - - /** - * Manually wake up the behavior. If MANUAL_WAKEUP flag was set upon - * creation, you must wake up this behavior each time it is handled. - */ - - public void wakeup() - { - wakeUp = true; - } - - /** - * Handles mouse events - */ - public void processMouseEvent(MouseEvent evt) { - if (evt.getID()==MouseEvent.MOUSE_PRESSED) { - buttonPress = true; - return; - } - else if (evt.getID()==MouseEvent.MOUSE_RELEASED){ - buttonPress = false; - wakeUp = false; - } - /* - else if (evt.getID() == MouseEvent.MOUSE_MOVED) { - // Process mouse move event - } - else if (evt.getID() == MouseEvent.MOUSE_WHEEL) { - // Process mouse wheel event - } - */ - } - - /** - * All mouse manipulators must implement this. - */ - @Override - public abstract void processStimulus (Enumeration criteria); - - /** - * Adds this behavior as a MouseListener, mouseWheelListener and MouseMotionListener to - * the specified component. This method can only be called if - * the behavior was created with one of the constructors that takes - * a Component as a parameter. - * @param c The component to add the MouseListener, MouseWheelListener and - * MouseMotionListener to. - * @exception IllegalStateException if the behavior was not created - * as a listener - * @since Java 3D 1.2.1 - */ - public void addListener(Component c) { - if (!listener) { - throw new IllegalStateException(J3dUtilsI18N.getString("Behavior0")); - } - c.addMouseListener(this); - c.addMouseMotionListener(this); - c.addMouseWheelListener(this); - } - - @Override - public void mouseClicked(MouseEvent e) {} - @Override - public void mouseEntered(MouseEvent e) {} - @Override - public void mouseExited(MouseEvent e) {} - - @Override - public void mousePressed(MouseEvent e) { -// System.out.println("mousePressed"); - - // add new event to the queue - // must be MT safe - if (enable) { - synchronized (mouseq) { - mouseq.add(e); - // only need to post if this is the only event in the queue - if (mouseq.size() == 1) - postId(MouseEvent.MOUSE_PRESSED); - } - } - } - - @Override - public void mouseReleased(MouseEvent e) { -// System.out.println("mouseReleased"); - - // add new event to the queue - // must be MT safe - if (enable) { - synchronized (mouseq) { - mouseq.add(e); - // only need to post if this is the only event in the queue - if (mouseq.size() == 1) - postId(MouseEvent.MOUSE_RELEASED); - } - } - } - - @Override - public void mouseDragged(MouseEvent e) { -// System.out.println("mouseDragged"); - - // add new event to the to the queue - // must be MT safe. - if (enable) { - synchronized (mouseq) { - mouseq.add(e); - // only need to post if this is the only event in the queue - if (mouseq.size() == 1) - postId(MouseEvent.MOUSE_DRAGGED); - } - } - } - - @Override - public void mouseMoved(MouseEvent e) {} - - @Override - public void setEnable(boolean state) { - super.setEnable(state); - this.enable = state; - if (!enable && (mouseq != null)) { - mouseq.clear(); - } - } - - @Override - public void mouseWheelMoved(MouseWheelEvent e){ -// System.out.println("MouseBehavior : mouseWheel enable = " + enable ); - - // add new event to the to the queue - // must be MT safe. - if (enable) { - synchronized (mouseq) { - mouseq.add(e); - // only need to post if this is the only event in the queue - if (mouseq.size() == 1) - postId(MouseEvent.MOUSE_WHEEL); - } - } - } -} - - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehaviorCallback.java b/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehaviorCallback.java deleted file mode 100644 index 29854a0..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseBehaviorCallback.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.mouse; - -import javax.media.j3d.Transform3D; - -/** - * The MouseBehaviorCallback interface allows a class to be notified - * when the transform is changed by one of the MouseBehaviors. The - * class that is interested in transform changes implements this - * interface, and the object created with that class is registered - * with the desired subclass of MouseBehavior using the - *setupCallback
method. When the transform changes, the
- * registered object's transformChanged
method is
- * invoked.
- */
-
-public interface MouseBehaviorCallback {
-
- public final static int ROTATE=0;
- public final static int TRANSLATE=1;
- public final static int ZOOM=2;
-
- /**
- * Classes implementing this interface that are registered with
- * one of the MouseBehaviors will be called every time the
- * behavior updates the Transform
- * @param type will be one of ROTATE, TRANSLATE or ZOOM
- */
- public void transformChanged( int type, Transform3D transform );
-}
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseRotate.java b/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseRotate.java
deleted file mode 100644
index 33aaba8..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseRotate.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.mouse;
-
-import java.awt.AWTEvent;
-import java.awt.Component;
-import java.awt.event.MouseEvent;
-import java.util.Enumeration;
-
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-import javax.media.j3d.WakeupCriterion;
-import javax.media.j3d.WakeupOnAWTEvent;
-import javax.media.j3d.WakeupOnBehaviorPost;
-import javax.vecmath.Matrix4d;
-import javax.vecmath.Vector3d;
-
-/**
- * MouseRotate is a Java3D behavior object that lets users control the
- * rotation of an object via a mouse.
- * - * To use this utility, first create a transform group that this - * rotate behavior will operate on. Then, - *
- * The above code will add the rotate behavior to the transform - * group. The user can rotate any object attached to the objTrans. - */ - -public class MouseRotate extends MouseBehavior { - double x_angle, y_angle; - double x_factor = .03; - double y_factor = .03; - - private MouseBehaviorCallback callback = null; - - /** - * Creates a rotate behavior given the transform group. - * @param transformGroup The transformGroup to operate on. - */ - public MouseRotate(TransformGroup transformGroup) { - super(transformGroup); - } - - /** - * Creates a default mouse rotate behavior. - **/ - public MouseRotate() { - super(0); - } - - /** - * Creates a rotate behavior. - * Note that this behavior still needs a transform - * group to work on (use setTransformGroup(tg)) and - * the transform group must add this behavior. - * @param flags interesting flags (wakeup conditions). - */ - public MouseRotate(int flags) { - super(flags); - } - - /** - * Creates a rotate behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behavior is added to the - * specified Component. A null component can be passed to specify - * the behavior should use listeners. Components can then be added - * to the behavior with the addListener(Component c) method. - * @param c The Component to add the MouseListener - * and MouseMotionListener to. - * @since Java 3D 1.2.1 - */ - public MouseRotate(Component c) { - super(c, 0); - } - - /** - * Creates a rotate behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behaviors is added to - * the specified Component and works on the given TransformGroup. - * A null component can be passed to specify the behavior should use - * listeners. Components can then be added to the behavior with the - * addListener(Component c) method. - * @param c The Component to add the MouseListener and - * MouseMotionListener to. - * @param transformGroup The TransformGroup to operate on. - * @since Java 3D 1.2.1 - */ - public MouseRotate(Component c, TransformGroup transformGroup) { - super(c, transformGroup); - } - - /** - * Creates a rotate behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behavior is added to the - * specified Component. A null component can be passed to specify - * the behavior should use listeners. Components can then be added to - * the behavior with the addListener(Component c) method. - * Note that this behavior still needs a transform - * group to work on (use setTransformGroup(tg)) and the transform - * group must add this behavior. - * @param flags interesting flags (wakeup conditions). - * @since Java 3D 1.2.1 - */ - public MouseRotate(Component c, int flags) { - super(c, flags); - } - - @Override - public void initialize() { - super.initialize(); - x_angle = 0; - y_angle = 0; - if ((flags & INVERT_INPUT) == INVERT_INPUT) { - invert = true; - x_factor *= -1; - y_factor *= -1; - } - } - - /** - * Return the x-axis movement multipler. - **/ - public double getXFactor() { - return x_factor; - } - - /** - * Return the y-axis movement multipler. - **/ - public double getYFactor() { - return y_factor; - } - - - /** - * Set the x-axis amd y-axis movement multipler with factor. - **/ - public void setFactor( double factor) { - x_factor = y_factor = factor; - } - - /** - * Set the x-axis amd y-axis movement multipler with xFactor and yFactor - * respectively. - **/ - public void setFactor( double xFactor, double yFactor) { - x_factor = xFactor; - y_factor = yFactor; - } - - @Override - public void processStimulus (Enumeration criteria) { - WakeupCriterion wakeup; - AWTEvent[] events; - MouseEvent evt; -// int id; -// int dx, dy; - - while (criteria.hasMoreElements()) { - wakeup = (WakeupCriterion) criteria.nextElement(); - if (wakeup instanceof WakeupOnAWTEvent) { - events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); - if (events.length > 0) { - evt = (MouseEvent) events[events.length-1]; - doProcess(evt); - } - } - - else if (wakeup instanceof WakeupOnBehaviorPost) { - while (true) { - // access to the queue must be synchronized - synchronized (mouseq) { - if (mouseq.isEmpty()) break; - evt = (MouseEvent)mouseq.remove(0); - // consolidate MOUSE_DRAG events - while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) && - !mouseq.isEmpty() && - (((MouseEvent)mouseq.get(0)).getID() == - MouseEvent.MOUSE_DRAGGED)) { - evt = (MouseEvent)mouseq.remove(0); - } - } - doProcess(evt); - } - } - - } - wakeupOn (mouseCriterion); - } - - void doProcess(MouseEvent evt) { - int id; - int dx, dy; - - processMouseEvent(evt); - if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || - ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))) { - id = evt.getID(); - if ((id == MouseEvent.MOUSE_DRAGGED) && - !evt.isMetaDown() && ! evt.isAltDown()){ - x = evt.getX(); - y = evt.getY(); - - dx = x - x_last; - dy = y - y_last; - - if (!reset){ - x_angle = dy * y_factor; - y_angle = dx * x_factor; - - transformX.rotX(x_angle); - transformY.rotY(y_angle); - - transformGroup.getTransform(currXform); - - Matrix4d mat = new Matrix4d(); - // Remember old matrix - currXform.get(mat); - - // Translate to origin - currXform.setTranslation(new Vector3d(0.0,0.0,0.0)); - if (invert) { - currXform.mul(currXform, transformX); - currXform.mul(currXform, transformY); - } else { - currXform.mul(transformX, currXform); - currXform.mul(transformY, currXform); - } - - // Set old translation back - Vector3d translation = new - Vector3d(mat.m03, mat.m13, mat.m23); - currXform.setTranslation(translation); - - // Update xform - transformGroup.setTransform(currXform); - - transformChanged( currXform ); - - if (callback!=null) - callback.transformChanged( MouseBehaviorCallback.ROTATE, - currXform ); - } - else { - reset = false; - } - - x_last = x; - y_last = y; - } - else if (id == MouseEvent.MOUSE_PRESSED) { - x_last = evt.getX(); - y_last = evt.getY(); - } - } - } - - /** - * Users can overload this method which is called every time - * the Behavior updates the transform - * - * Default implementation does nothing - */ - public void transformChanged( Transform3D transform ) { - } - - - /** - * The transformChanged method in the callback class will - * be called every time the transform is updated - */ - public void setupCallback( MouseBehaviorCallback callback ) { - this.callback = callback; - } -} diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseTranslate.java b/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseTranslate.java deleted file mode 100644 index f81366a..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseTranslate.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.mouse; - -import java.awt.AWTEvent; -import java.awt.Component; -import java.awt.event.MouseEvent; -import java.util.Enumeration; - -import javax.media.j3d.Transform3D; -import javax.media.j3d.TransformGroup; -import javax.media.j3d.WakeupCriterion; -import javax.media.j3d.WakeupOnAWTEvent; -import javax.media.j3d.WakeupOnBehaviorPost; -import javax.vecmath.Vector3d; - -/** - * MouseTranslate is a Java3D behavior object that lets users control the - * translation (X, Y) of an object via a mouse drag motion with the third - * mouse button (alt-click on PC). See MouseRotate for similar usage info. - */ - -public class MouseTranslate extends MouseBehavior { - - double x_factor = .02; - double y_factor = .02; - Vector3d translation = new Vector3d(); - - private MouseBehaviorCallback callback = null; - - /** - * Creates a mouse translate behavior given the transform group. - * @param transformGroup The transformGroup to operate on. - */ - public MouseTranslate(TransformGroup transformGroup) { - super(transformGroup); - } - - /** - * Creates a default translate behavior. - */ - public MouseTranslate(){ - super(0); - } - - /** - * Creates a translate behavior. - * Note that this behavior still needs a transform - * group to work on (use setTransformGroup(tg)) and - * the transform group must add this behavior. - * @param flags - */ - public MouseTranslate(int flags) { - super(flags); - } - - /** - * Creates a translate behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behavior is added to the - * specified Component. A null component can be passed to specify - * the behavior should use listeners. Components can then be added - * to the behavior with the addListener(Component c) method. - * @param c The Component to add the MouseListener - * and MouseMotionListener to. - * @since Java 3D 1.2.1 - */ - public MouseTranslate(Component c) { - super(c, 0); - } - - /** - * Creates a translate behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behaviors is added to - * the specified Component and works on the given TransformGroup. - * A null component can be passed to specify the behavior should use - * listeners. Components can then be added to the behavior with the - * addListener(Component c) method. - * @param c The Component to add the MouseListener and - * MouseMotionListener to. - * @param transformGroup The TransformGroup to operate on. - * @since Java 3D 1.2.1 - */ - public MouseTranslate(Component c, TransformGroup transformGroup) { - super(c, transformGroup); - } - - /** - * Creates a translate behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behavior is added to the - * specified Component. A null component can be passed to specify - * the behavior should use listeners. Components can then be added to - * the behavior with the addListener(Component c) method. - * Note that this behavior still needs a transform - * group to work on (use setTransformGroup(tg)) and the transform - * group must add this behavior. - * @param flags interesting flags (wakeup conditions). - * @since Java 3D 1.2.1 - */ - public MouseTranslate(Component c, int flags) { - super(c, flags); - } - - @Override - public void initialize() { - super.initialize(); - if ((flags & INVERT_INPUT) == INVERT_INPUT) { - invert = true; - x_factor *= -1; - y_factor *= -1; - } - } - - /** - * Return the x-axis movement multipler. - **/ - public double getXFactor() { - return x_factor; - } - - /** - * Return the y-axis movement multipler. - **/ - public double getYFactor() { - return y_factor; - } - - /** - * Set the x-axis amd y-axis movement multipler with factor. - **/ - public void setFactor( double factor) { - x_factor = y_factor = factor; - } - - /** - * Set the x-axis amd y-axis movement multipler with xFactor and yFactor - * respectively. - **/ - public void setFactor( double xFactor, double yFactor) { - x_factor = xFactor; - y_factor = yFactor; - } - - @Override - public void processStimulus (Enumeration criteria) { - WakeupCriterion wakeup; - AWTEvent[] events; - MouseEvent evt; -// int id; -// int dx, dy; - - while (criteria.hasMoreElements()) { - wakeup = (WakeupCriterion) criteria.nextElement(); - - if (wakeup instanceof WakeupOnAWTEvent) { - events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); - if (events.length > 0) { - evt = (MouseEvent) events[events.length-1]; - doProcess(evt); - } - } - - else if (wakeup instanceof WakeupOnBehaviorPost) { - while (true) { - // access to the queue must be synchronized - synchronized (mouseq) { - if (mouseq.isEmpty()) break; - evt = (MouseEvent)mouseq.remove(0); - // consolodate MOUSE_DRAG events - while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) && - !mouseq.isEmpty() && - (((MouseEvent)mouseq.get(0)).getID() == - MouseEvent.MOUSE_DRAGGED)) { - evt = (MouseEvent)mouseq.remove(0); - } - } - doProcess(evt); - } - } - - } - wakeupOn(mouseCriterion); - } - - void doProcess(MouseEvent evt) { - int id; - int dx, dy; - - processMouseEvent(evt); - - if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || - ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))){ - id = evt.getID(); - if ((id == MouseEvent.MOUSE_DRAGGED) && - !evt.isAltDown() && evt.isMetaDown()) { - - x = evt.getX(); - y = evt.getY(); - - dx = x - x_last; - dy = y - y_last; - - if ((!reset) && ((Math.abs(dy) < 50) && (Math.abs(dx) < 50))) { - //System.out.println("dx " + dx + " dy " + dy); - transformGroup.getTransform(currXform); - - translation.x = dx*x_factor; - translation.y = -dy*y_factor; - - transformX.set(translation); - - if (invert) { - currXform.mul(currXform, transformX); - } else { - currXform.mul(transformX, currXform); - } - - transformGroup.setTransform(currXform); - - transformChanged( currXform ); - - if (callback!=null) - callback.transformChanged( MouseBehaviorCallback.TRANSLATE, - currXform ); - - } - else { - reset = false; - } - x_last = x; - y_last = y; - } - else if (id == MouseEvent.MOUSE_PRESSED) { - x_last = evt.getX(); - y_last = evt.getY(); - } - } - } - - /** - * Users can overload this method which is called every time - * the Behavior updates the transform - * - * Default implementation does nothing - */ - public void transformChanged( Transform3D transform ) { - } - - /** - * The transformChanged method in the callback class will - * be called every time the transform is updated - */ - public void setupCallback( MouseBehaviorCallback callback ) { - this.callback = callback; - } -} - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseWheelZoom.java b/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseWheelZoom.java deleted file mode 100644 index 8d360b2..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseWheelZoom.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.mouse; - -import java.awt.AWTEvent; -import java.awt.Component; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelEvent; -import java.util.Enumeration; - -import javax.media.j3d.Transform3D; -import javax.media.j3d.TransformGroup; -import javax.media.j3d.WakeupCriterion; -import javax.media.j3d.WakeupOnAWTEvent; -import javax.media.j3d.WakeupOnBehaviorPost; -import javax.vecmath.Vector3d; - - -/** - * MouseWheelZoom is a Java3D behavior object that lets users control the - * Z axis translation of an object via mouse wheel. - * @since Java 3D 1.3.2 - */ - -public class MouseWheelZoom extends MouseBehavior { - - double z_factor = .1; - Vector3d translation = new Vector3d(); - - private MouseBehaviorCallback callback = null; - - /** - * Creates a zoom behavior given the transform group. - * @param transformGroup The transformGroup to operate on. - */ - public MouseWheelZoom(TransformGroup transformGroup) { - super(transformGroup); - } - - /** - * Creates a default mouse zoom behavior. - **/ - public MouseWheelZoom() { - super(0); - } - - /** - * Creates a zoom behavior. - * Note that this behavior still needs a transform - * group to work on (use setTransformGroup(tg)) and - * the transform group must add this behavior. - * @param flags - */ - public MouseWheelZoom(int flags) { - super(flags); - } - - /** - * Creates a zoom behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behavior is added to the - * specified Component. A null component can be passed to specify - * the behavior should use listeners. Components can then be added - * to the behavior with the addListener(Component c) method. - * @param c The Component to add the MouseListener - * and MouseMotionListener to. - * @since Java 3D 1.3.2 - */ - public MouseWheelZoom(Component c) { - super(c, 0); - } - - /** - * Creates a zoom behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behaviors is added to - * the specified Component and works on the given TransformGroup. - * @param c The Component to add the MouseListener and - * MouseMotionListener to. A null component can be passed to specify - * the behavior should use listeners. Components can then be added - * to the behavior with the addListener(Component c) method. - * @param transformGroup The TransformGroup to operate on. - * @since Java 3D 1.3.2 - */ - public MouseWheelZoom(Component c, TransformGroup transformGroup) { - super(c, transformGroup); - } - - /** - * Creates a zoom behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behavior is added to the - * specified Component. A null component can be passed to specify - * the behavior should use listeners. Components can then be added - * to the behavior with the addListener(Component c) method. - * Note that this behavior still needs a transform - * group to work on (use setTransformGroup(tg)) and the transform - * group must add this behavior. - * @param flags interesting flags (wakeup conditions). - * @since Java 3D 1.3.2 - */ - public MouseWheelZoom(Component c, int flags) { - super(c, flags); - } - - @Override - public void initialize() { - super.initialize(); - if ((flags & INVERT_INPUT) == INVERT_INPUT) { - z_factor *= -1; - invert = true; - } - } - - /** - * Return the y-axis movement multipler. - **/ - public double getFactor() { - return z_factor; - } - - /** - * Set the wheel units movement multipler with factor. - **/ - public void setFactor( double factor) { - z_factor = factor; - } - - - @Override - public void processStimulus(Enumeration criteria) { - WakeupCriterion wakeup; - AWTEvent[] events; - MouseEvent evt; - - while (criteria.hasMoreElements()) { - wakeup = (WakeupCriterion) criteria.nextElement(); - if (wakeup instanceof WakeupOnAWTEvent) { - events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); - if (events.length > 0) { - evt = (MouseEvent) events[events.length-1]; - doProcess(evt); - } - } - - else if (wakeup instanceof WakeupOnBehaviorPost) { - while (true) { - synchronized (mouseq) { - if (mouseq.isEmpty()) break; - evt = (MouseEvent)mouseq.remove(0); - // consolidate MOUSE_WHEEL events - while((evt.getID() == MouseEvent.MOUSE_WHEEL) && - !mouseq.isEmpty() && - (((MouseEvent)mouseq.get(0)).getID() == - MouseEvent.MOUSE_WHEEL)) { - evt = (MouseEvent)mouseq.remove(0); - } - } - doProcess(evt); - } - } - - } - wakeupOn(mouseCriterion); - } - - void doProcess(MouseEvent evt) { - int units = 0; - - processMouseEvent(evt); - - if ((evt.getID() == MouseEvent.MOUSE_WHEEL)) { - MouseWheelEvent wheelEvent = (MouseWheelEvent)evt; - if (wheelEvent.getScrollType() == wheelEvent.WHEEL_UNIT_SCROLL ) { - units = wheelEvent.getUnitsToScroll(); - } - - if (!reset) { - transformGroup.getTransform(currXform); - - translation.z = units*z_factor; - - transformX.set(translation); - - if (invert) { - currXform.mul(currXform, transformX); - } else { - currXform.mul(transformX, currXform); - } - - transformGroup.setTransform(currXform); - - transformChanged( currXform ); - - if (callback!=null) - callback.transformChanged( MouseBehaviorCallback.ZOOM, - currXform ); - - } - else { - reset = false; - } - } - } - - - /** - * Users can overload this method which is called every time - * the Behavior updates the transform - * - * Default implementation does nothing - */ - public void transformChanged( Transform3D transform ) { - } - - /** - * The transformChanged method in the callback class will - * be called every time the transform is updated - */ - public void setupCallback( MouseBehaviorCallback callback ){ - this.callback = callback; - } -} - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseZoom.java b/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseZoom.java deleted file mode 100644 index 86471a5..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/MouseZoom.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.mouse; - -import java.awt.AWTEvent; -import java.awt.Component; -import java.awt.event.MouseEvent; -import java.util.Enumeration; - -import javax.media.j3d.Transform3D; -import javax.media.j3d.TransformGroup; -import javax.media.j3d.WakeupCriterion; -import javax.media.j3d.WakeupOnAWTEvent; -import javax.media.j3d.WakeupOnBehaviorPost; -import javax.vecmath.Vector3d; - - -/** - * MouseZoom is a Java3D behavior object that lets users control the - * Z axis translation of an object via a mouse drag motion with the second - * mouse button. See MouseRotate for similar usage info. - */ - -public class MouseZoom extends MouseBehavior { - - double z_factor = .04; - Vector3d translation = new Vector3d(); - - private MouseBehaviorCallback callback = null; - - /** - * Creates a zoom behavior given the transform group. - * @param transformGroup The transformGroup to operate on. - */ - public MouseZoom(TransformGroup transformGroup) { - super(transformGroup); - } - - /** - * Creates a default mouse zoom behavior. - **/ - public MouseZoom(){ - super(0); - } - - /** - * Creates a zoom behavior. - * Note that this behavior still needs a transform - * group to work on (use setTransformGroup(tg)) and - * the transform group must add this behavior. - * @param flags - */ - public MouseZoom(int flags) { - super(flags); - } - - /** - * Creates a zoom behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behavior is added to the - * specified Component. A null component can be passed to specify - * the behavior should use listeners. Components can then be added - * to the behavior with the addListener(Component c) method. - * @param c The Component to add the MouseListener - * and MouseMotionListener to. - * @since Java 3D 1.2.1 - */ - public MouseZoom(Component c) { - super(c, 0); - } - - /** - * Creates a zoom behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behaviors is added to - * the specified Component and works on the given TransformGroup. - * @param c The Component to add the MouseListener and - * MouseMotionListener to. A null component can be passed to specify - * the behavior should use listeners. Components can then be added - * to the behavior with the addListener(Component c) method. - * @param transformGroup The TransformGroup to operate on. - * @since Java 3D 1.2.1 - */ - public MouseZoom(Component c, TransformGroup transformGroup) { - super(c, transformGroup); - } - - /** - * Creates a zoom behavior that uses AWT listeners and behavior - * posts rather than WakeupOnAWTEvent. The behavior is added to the - * specified Component. A null component can be passed to specify - * the behavior should use listeners. Components can then be added - * to the behavior with the addListener(Component c) method. - * Note that this behavior still needs a transform - * group to work on (use setTransformGroup(tg)) and the transform - * group must add this behavior. - * @param flags interesting flags (wakeup conditions). - * @since Java 3D 1.2.1 - */ - public MouseZoom(Component c, int flags) { - super(c, flags); - } - - @Override - public void initialize() { - super.initialize(); - if ((flags & INVERT_INPUT) == INVERT_INPUT) { - z_factor *= -1; - invert = true; - } - } - - /** - * Return the y-axis movement multipler. - **/ - public double getFactor() { - return z_factor; - } - - /** - * Set the y-axis movement multipler with factor. - **/ - public void setFactor( double factor) { - z_factor = factor; - } - - - @Override - public void processStimulus (Enumeration criteria) { - WakeupCriterion wakeup; - AWTEvent[] events; - MouseEvent evt; -// int id; -// int dx, dy; - - while (criteria.hasMoreElements()) { - wakeup = (WakeupCriterion) criteria.nextElement(); - if (wakeup instanceof WakeupOnAWTEvent) { - events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); - if (events.length > 0) { - evt = (MouseEvent) events[events.length-1]; - doProcess(evt); - } - } - - else if (wakeup instanceof WakeupOnBehaviorPost) { - while (true) { - synchronized (mouseq) { - if (mouseq.isEmpty()) break; - evt = (MouseEvent)mouseq.remove(0); - // consolodate MOUSE_DRAG events - while((evt.getID() == MouseEvent.MOUSE_DRAGGED) && - !mouseq.isEmpty() && - (((MouseEvent)mouseq.get(0)).getID() == - MouseEvent.MOUSE_DRAGGED)) { - evt = (MouseEvent)mouseq.remove(0); - } - } - doProcess(evt); - } - } - - } - wakeupOn (mouseCriterion); - } - - void doProcess(MouseEvent evt) { - int id; - int dx, dy; - - processMouseEvent(evt); - - if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || - ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))){ - id = evt.getID(); - if ((id == MouseEvent.MOUSE_DRAGGED) && - evt.isAltDown() && !evt.isMetaDown()){ - - x = evt.getX(); - y = evt.getY(); - - dx = x - x_last; - dy = y - y_last; - - if (!reset){ - transformGroup.getTransform(currXform); - - translation.z = dy*z_factor; - - transformX.set(translation); - - if (invert) { - currXform.mul(currXform, transformX); - } else { - currXform.mul(transformX, currXform); - } - - transformGroup.setTransform(currXform); - - transformChanged( currXform ); - - if (callback!=null) - callback.transformChanged( MouseBehaviorCallback.ZOOM, - currXform ); - - } - else { - reset = false; - } - - x_last = x; - y_last = y; - } - else if (id == MouseEvent.MOUSE_PRESSED) { - x_last = evt.getX(); - y_last = evt.getY(); - } - } - } - - - /** - * Users can overload this method which is called every time - * the Behavior updates the transform - * - * Default implementation does nothing - */ - public void transformChanged( Transform3D transform ) { - } - - /** - * The transformChanged method in the callback class will - * be called every time the transform is updated - */ - public void setupCallback( MouseBehaviorCallback callback ) { - this.callback = callback; - } -} - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/package.html b/src/classes/share/com/sun/j3d/utils/behaviors/mouse/package.html deleted file mode 100644 index d943a49..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/mouse/package.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - -- * - * MouseRotate behavior = new MouseRotate(); - * behavior.setTransformGroup(objTrans); - * objTrans.addChild(behavior); - * behavior.setSchedulingBounds(bounds); - * - *
Provides mouse navigation utility classes.
- - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/picking/Intersect.java b/src/classes/share/com/sun/j3d/utils/behaviors/picking/Intersect.java deleted file mode 100644 index 6df1e7e..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/picking/Intersect.java +++ /dev/null @@ -1,1297 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.picking; - -import javax.media.j3d.PickPoint; -import javax.media.j3d.PickRay; -import javax.media.j3d.PickSegment; -import javax.vecmath.Point3d; -import javax.vecmath.Point3f; -import javax.vecmath.Tuple3d; -import javax.vecmath.Vector3d; - -import com.sun.j3d.internal.J3dUtilsI18N; - -/* - * Contains static methods to aid in the intersection test between - * various PickShape classes and geometry primitives (such as quad, - * triangle, line and point). - */ - - -/** - * @deprecated As of Java 3D version 1.2, this class is no - * longer needed - */ - -public class Intersect -{ - - /** - * Determines if thePickRay
and quadrilateral
- * objects intersect.
- * The quadrilateral is defined as coordinates[index]
to
- * coordinates[index+3]
.
- *
- * @param ray The ray to use in the intersection test.
- * @param coordinates An array holding the quadrilateral data.
- * @param index An array index that designates the starting position
- * in the array of the quadrilateral to test.
- * @param dist On return dist[0] will be set to the distance between ray's
- * origin and the point of intersection, if it exists.
- * The dist array should be allocated by the user.
- * @return true
if the ray intersects the quad,
- * false
if the ray does not intersect the object.
- */
- public static boolean rayAndQuad( PickRay ray, Point3d coordinates[],
- int index, double dist[] ) {
-
- if((coordinates.length - index) < 4)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect0"));
-
- Point3d pnts[] = new Point3d[4];
-
- for(int i=0; i<4; i++)
- pnts[i] = coordinates[index+i];
-
- return rayAndPoly(pnts, ray, dist);
-
- }
-
- /**
- * Return true if triangle intersects with ray and the distance, from
- * the origin of ray to the intersection point, is stored in dist[0].
- * The triangle is defined by coordinates[index] to coordinates[index+2]
- * coordinates[index+2]
.
- *
- * @param ray The ray to use in the intersection test.
- * @param coordinates An array holding the triangle data.
- * @param index An array index that designates the starting position
- * in the array of the triangle to test.
- * @param dist On return dist[0] will be set to the distance between ray's origin and the
- * point of intersection, if it exists. The dist array should be
- * allocated by the user.
- * @return true
if the ray intersects the triangle,
- * false
if the ray does not intersect the object.
- */
- public static boolean rayAndTriangle( PickRay ray, Point3d coordinates[],
- int index, double dist[] ) {
-
- if((coordinates.length - index) < 3)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect1"));
-
- Point3d pnts[] = new Point3d[3];
-
- for(int i=0; i<3; i++)
- pnts[i] = coordinates[index+i];
-
- return rayAndPoly(pnts, ray, dist);
-
- }
-
- /**
- * Return true if triangle intersects with ray and the distance, from
- * the origin of ray to the intersection point, is stored in dist[0].
- * The triangle is defined by coordinates[index] to coordinates[index+2]
- *
- * @param ray The ray that is used in intersection test.
- * @param coordinates an array of vertices.
- * @param index the vertex index
- * @param dist On return dist[0] will be set to the distance between ray's origin and the point intersection, if
- * exist.
- * @return true if ray intersects triangle, else return false.
- */
-
- public static boolean rayAndTriangle( PickRay ray, Point3f coordinates[],
- int index, double dist[] ) {
-
- if((coordinates.length - index) < 3)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect1"));
-
- Point3d pnts[] = new Point3d[3];
-
- for(int i=0; i<3; i++)
- pnts[i] = new Point3d(coordinates[index+i]);
-
- return rayAndPoly(pnts, ray, dist);
-
- }
-
-
- /**
- * Caluates the intersection between a PickSegment
- * object and a quadrilateral.
- * The quad is defined as coordinates[index] to coordinates[index+3]
- *
- * @param segment The segment to use in the intersection test.
- * @param coordinates An array holding the quadrilateral data.
- * @param index An array index that designates the starting position
- * in the array of the quadrilateral to test.
- * @param dist On return dist[0] will be set to the distance between the start of the segment
- * and the point of intersection, if it exists. The dist array
- * should be allocated by the user.
- * @return true
if the segment intersects the quad,
- * false
if the segment does not intersect the object.
- */
- public static boolean segmentAndQuad( PickSegment segment,
- Point3d coordinates[],
- int index, double dist[] ) {
- if((coordinates.length - index) < 4)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect3"));
-
- Point3d pnts[] = new Point3d[4];
-
- for(int i=0; i<4; i++)
- pnts[i] = coordinates[index+i];
-
- return segmentAndPoly(pnts, segment, dist);
-
- }
-
- /**
- * Return true if quad intersects with segment and the distance, from
- * the start of segment to the intersection point, is stored in dist[0].
- * The quad is defined by coordinates[index] to coordinates[index+3]
- *
- * @param segment The segment that is used in intersection test.
- * @param coordinates an array of vertices.
- * @param index the vertex index
- * @param dist On return dist[0] will be set to the distance between segment's start and the point
- * intersection, if exist.
- * @return true if segment intersects quad, else return false.
- */
-
- public static boolean segmentAndQuad( PickSegment segment, Point3f coordinates[],
- int index, double dist[] ) {
- if((coordinates.length - index) < 4)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect3"));
-
- Point3d pnts[] = new Point3d[4];
-
- for(int i=0; i<4; i++)
- pnts[i] = new Point3d(coordinates[index+i]);
-
- return segmentAndPoly(pnts, segment, dist);
-
- }
-
- /**
- * Caluates the intersection between a PickSegment
- * object and a triangle.
- * The triangle is defined as coordinates[index] to coordinates[index+2]
- *
- * @param segment The segment to use in the intersection test.
- * @param coordinates An array holding the triangle data.
- * @param index An array index that designates the starting position
- * in the array of the triangle to test.
- * @param dist On return dist[0] contains the distance between the start of the segment
- * and the point of intersection, if it exists. The dist array
- * should be allocated by the user.
- * @return true
if the segment intersects the triangle,
- * false
if the segment does not intersect the object.
- */
- public static boolean segmentAndTriangle( PickSegment segment,
- Point3d coordinates[],
- int index,
- double dist[] ) {
- if((coordinates.length - index) < 3)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect5"));
-
- Point3d pnts[] = new Point3d[3];
-
- for(int i=0; i<3; i++)
- pnts[i] = coordinates[index+i];
-
- return segmentAndPoly(pnts, segment, dist);
-
- }
-
- /**
- * Return true if triangle intersects with segment and the distance, from
- * the start of segment to the intersection point, is stored in dist[0].
- * The triangle is defined by coordinates[index] to coordinates[index+2]
- *
- * @param segment The segment that is used in intersection test.
- * @param coordinates an array of vertices.
- * @param index the vertex index
- * @param dist On return dist[0] will be set to the distance between segment's start and the point
- * intersection, if exist.
- * @return true if segment intersects triangle, else return false.
- */
-
- public static boolean segmentAndTriangle( PickSegment segment,
- Point3f coordinates[], int index,
- double dist[] ) {
- if((coordinates.length - index) < 3)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect6"));
-
- Point3d pnts[] = new Point3d[3];
-
- for(int i=0; i<3; i++)
- pnts[i] = new Point3d(coordinates[index+i]);
-
- return segmentAndPoly(pnts, segment, dist);
-
- }
-
- /**
- * Caluates the intersection between a PickPoint
- * object and a quadrilateral.
- * The quad is defined as coordinates[index]
to
- * coordinates[index+3]
.
- *
- * @param point The point to use in the intersection test.
- * @param coordinates An array holding the quadrilateral data.
- * @param index An array index that designates the starting position
- * in the array of the quadrilateral to test.
- * @return true
if the point intersects the quad,
- * false
if the point does not intersect the object.
- */
- private static boolean pointAndQuad( PickPoint point,
- Point3d coordinates[],
- int index) {
-
- if((coordinates.length - index) < 4)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect7"));
-
- Point3d pnts[] = new Point3d[4];
-
- for(int i=0; i<4; i++)
- pnts[i] = coordinates[index+i];
-
- return pointAndPoly( pnts, point);
-
- }
-
- /**
- * Return true if quad intersects with point.
- * The triangle is defined by coordinates[index] to coordinates[index+3]
- *
- * @param point The point that is used in intersection test.
- * @param coordinates an array of vertices.
- * @param index the vertex index
- * @return true if point intersects quad, else return false.
- */
-
- private static boolean pointAndQuad( PickPoint point, Point3f coordinates[],
- int index) {
-
- if((coordinates.length - index) < 4)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect7"));
-
- Point3d pnts[] = new Point3d[4];
-
- for(int i=0; i<4; i++)
- pnts[i] = new Point3d(coordinates[index+i]);
-
- return pointAndPoly( pnts, point);
-
- }
-
- /**
- * Caluates the intersection between a PickPoint
- * object and a triangle.
- * The triangle is defined by coordinates[index]
to
- * coordinates[index+2]
.
- *
- * @param point The point to use in the intersection test.
- * @param coordinates An array holding the triangle data.
- * @param index An array index that designates the starting position
- * in the array of the triangle to test.
- * @return true
if the point intersects the triangle,
- * false
if the point does not intersect the object.
- */
- private static boolean pointAndTriangle( PickPoint point,
- Point3d coordinates[],
- int index) {
-
- if((coordinates.length - index) < 3)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect9"));
-
- Point3d pnts[] = new Point3d[3];
-
- for(int i=0; i<3; i++)
- pnts[i] = coordinates[index+i];
-
- return pointAndPoly( pnts, point);
-
- }
-
- /**
- * Return true if triangle intersects with point.
- * The triangle is defined by coordinates[index] to coordinates[index+2]
- *
- * @param point The point that is used in intersection test.
- * @param coordinates an array of vertices.
- * @param index the vertex index
- * @return true if point intersects triangle, else return false.
- */
-
- private static boolean pointAndTriangle( PickPoint point, Point3f coordinates[],
- int index) {
-
- if((coordinates.length - index) < 3)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect10"));
-
- Point3d pnts[] = new Point3d[3];
-
- for(int i=0; i<3; i++)
- pnts[i] = new Point3d(coordinates[index+i]);
-
- return pointAndPoly( pnts, point);
-
- }
-
- /**
- * Determines if the PickRay
and Point3d
- * objects intersect.
- *
- * @param ray The ray that is used in the intersection test.
- * @param pnt The point that is used in intersection test.
- * @param dist On return dist[0] will be set to the distance between ray's origin and the point
- * of intersection, if it exists. The dist array
- * should be allocated by the user.
- * @return true
if the ray intersects the point,
- * false
if the ray does not intersect the object.
- */
- public static boolean rayAndPoint( PickRay ray, Point3d pnt,
- double dist[] ) {
-
- Point3d origin = new Point3d();
- Vector3d direction = new Vector3d();
-
- ray.get(origin, direction);
-
- return rayAndPoint(pnt, origin, direction, dist);
- }
-
- /**
- * Return true if point intersects with ray and the distance, from
- * the origin of ray to the intersection point, is stored in dist[0].
- *
- * @param ray The ray that is used in intersection test.
- * @param pnt The point that is used in intersection test.
- * @param dist On return dist[0] contains the distance between ray's origin and the point
- * intersection, if exist.
- * @return true if ray intersects point, else return false.
- */
-
- public static boolean rayAndPoint( PickRay ray, Point3f pnt, double dist[] ) {
-
- Point3d origin = new Point3d();
- Vector3d direction = new Vector3d();
-
- ray.get(origin, direction);
-
- return rayAndPoint(new Point3d(pnt), origin, direction, dist);
- }
-
- /**
- * Determines if the PickSegment
and Point3d
- * objects intersect.
- *
- * @param segment The segment that is used in the intersection test.
- * @param pnt The point that is used in intersection test.
- * @param dist On return dist[0] contains the distance between segment's origin and the point
- * of intersection, if it exists. The dist array
- * should be allocated by the user.
- * @return true
if the segment intersects the point,
- * false
if the segment does not intersect the object.
- */
- public static boolean segmentAndPoint( PickSegment segment, Point3d pnt,
- double dist[] ) {
-
- Point3d start = new Point3d();
- Point3d end = new Point3d();
- Vector3d direction = new Vector3d();
-
- segment.get(start, end);
- direction.x = end.x - start.x;
- direction.y = end.y - start.y;
- direction.z = end.z - start.z;
-
- if((rayAndPoint(pnt, start, direction, dist)==true) && (dist[0] <= 1.0))
- return true;
-
- return false;
- }
-
- /**
- * Return true if point intersects with segment and the distance, from
- * the start of segment to the intersection point, is stored in dist[0].
- *
- * @param segment The segment that is used in intersection test.
- * @param pnt The point that is used in intersection test.
- * @param dist On return dist[0] contains the distance between segment's start and the point
- * intersection, if exist.
- * @return true if segment intersects point, else return false.
- */
-
- public static boolean segmentAndPoint( PickSegment segment, Point3f pnt,
- double dist[] ) {
-
- Point3d start = new Point3d();
- Point3d end = new Point3d();
- Vector3d direction = new Vector3d();
-
- segment.get(start, end);
- direction.x = end.x - start.x;
- direction.y = end.y - start.y;
- direction.z = end.z - start.z;
-
- if((rayAndPoint(new Point3d(pnt), start, direction, dist)==true)
- && (dist[0] <= 1.0))
- return true;
-
- return false;
- }
-
- /**
- * Determines if the PickPoint
and Point3d
- * objects intersect.
- *
- * @param point The PickPoint that is used in the intersection test.
- * @param pnt The Point3d that is used in intersection test.
- * @return true
if the PickPoint and Point3d objects
- * intersect, false
if the do not intersect.
- */
- public static boolean pointAndPoint( PickPoint point, Point3d pnt) {
-
- Point3d location = new Point3d();
-
- point.get(location);
-
- if ((location.x == pnt.x) && (location.y == pnt.y) &&
- (location.z == pnt.z))
- return true;
-
- return false;
- }
-
- /**
- * Return true if pnt intersects with point.
- *
- * @param point The point that is used in intersection test.
- * @param pnt The point that is used in intersection test.
- * @return true if point intersects pnt, else return false.
- */
-
- public static boolean pointAndPoint( PickPoint point, Point3f pnt) {
-
- Point3d location = new Point3d();
-
- point.get(location);
-
- if(((float) location.x == pnt.x) && ((float) location.y == pnt.y)
- && ((float) location.z == pnt.z))
- return true;
-
- return false;
- }
-
- /**
- * Determines if the PickRay
and Line
- * objects intersect.
- * The line is defined as coordinates[index]
to
- * coordinates[index+1]
.
- *
- * @param ray The ray that is used in the intersection test.
- * @param coordinates An array holding the line data.
- * @param dist On return dist[0] contains the distance between ray's origin and the point of
- * intersection, if it exists. The dist array
- * should be allocated by the user.
- * @return true
if the ray intersects the line,
- * false
if the ray does not intersect the object.
- */
- public static boolean rayAndLine(PickRay ray, Point3d coordinates[],
- int index,
- double dist[] ) {
- Point3d origin = new Point3d();
- Vector3d direction = new Vector3d();
-
- if((coordinates.length - index) < 2)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect11"));
-
- ray.get(origin, direction);
- Point3d start = coordinates[index++];
- Point3d end = coordinates[index];
-
- return lineAndRay( start, end, origin, direction, dist );
-
- }
-
- /**
- * Return true if line intersects with ray and the distance, from
- * the origin of ray to the intersection point, is stored in dist[0].
- * The line is defined by coordinates[index] to coordinates[index+1]
- *
- * @param ray The ray that is used in intersection test.
- * @param coordinates an array of vertices.
- * @param index the vertex index
- * @param dist On return dist[0] contains the distance between ray's origin and the point intersection, if
- * exist.
- * @return true if ray intersects line, else return false.
- */
-
- public static boolean rayAndLine(PickRay ray, Point3f coordinates[], int index,
- double dist[] ) {
- Point3d origin = new Point3d();
- Vector3d direction = new Vector3d();
-
- if((coordinates.length - index) < 2)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect11"));
-
- ray.get(origin, direction);
- Point3d start = new Point3d(coordinates[index++]);
- Point3d end = new Point3d(coordinates[index]);
-
- return lineAndRay( start, end, origin, direction, dist );
-
- }
-
- /**
- * Determines if the PickSegment
and Line
- * objects intersect.
- * The line is defined as coordinates[index]
to
- * coordinates[index+1]
.
- *
- * @param segment The segment that is used in the intersection test.
- * @param coordinates An array holding the line data.
- * @param dist On return dist[0] contains the distance between segment's origin and the point of
- * intersection, if it exists. The dist array
- * should be allocated by the user.
- * @return true
if the segment intersects the line,
- * false
if the segment does not intersect the object.
- */
- public static boolean segmentAndLine(PickSegment segment,
- Point3d coordinates[],
- int index, double dist[] ) {
-
- Point3d start = new Point3d();
- Point3d end = new Point3d();
- Vector3d direction = new Vector3d();
-
- if((coordinates.length - index) < 2)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect13"));
-
- segment.get(start, end);
- direction.x = end.x - start.x;
- direction.y = end.y - start.y;
- direction.z = end.z - start.z;
-
- Point3d startpnt = coordinates[index++];
- Point3d endpnt = coordinates[index];
-
- if(lineAndRay(startpnt, endpnt, start, direction, dist)==true)
- if(dist[0] <= 1.0)
- return true;
-
- return false;
- }
-
- /**
- * Return true if line intersects with segment and the distance, from
- * the start of segment to the intersection point, is stored in dist[0].
- * The line is defined by coordinates[index] to coordinates[index+1]
- *
- * @param segment The segment that is used in intersection test.
- * @param coordinates an array of vertices.
- * @param index the vertex index
- * @param dist On return dist[0] contains the distance between segment's start and the point
- * intersection, if exist.
- * @return true if segment intersects line, else return false.
- */
-
- public static boolean segmentAndLine(PickSegment segment, Point3f coordinates[],
- int index, double dist[] ) {
-
- Point3d start = new Point3d();
- Point3d end = new Point3d();
- Vector3d direction = new Vector3d();
-
- if((coordinates.length - index) < 2)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect13"));
-
- segment.get(start, end);
- direction.x = end.x - start.x;
- direction.y = end.y - start.y;
- direction.z = end.z - start.z;
-
- Point3d startpnt = new Point3d(coordinates[index++]);
- Point3d endpnt = new Point3d(coordinates[index]);
-
- if(lineAndRay(startpnt, endpnt, start, direction, dist)==true)
- if(dist[0] <= 1.0)
- return true;
-
- return false;
- }
-
- /**
- * Determines if the PickPoint
and Line
- * objects intersect.
- * The line is defined as coordinates[index]
to
- * coordinates[index+1]
.
- *
- * @param point The point that is used in the intersection test.
- * @param coordinates An array holding the line data.
- * @return true
if the the point intersects the line,
- * false
if the the point does not intersect the object.
- */
- public static boolean pointAndLine(PickPoint point, Point3d coordinates[],
- int index ) {
-
- if((coordinates.length - index) < 2)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect13"));
-
- double dist[] = new double[1];
- Point3d start = coordinates[index++];
- Point3d end = coordinates[index];
- Point3d location = new Point3d();
- Vector3d direction = new Vector3d();
-
- point.get(location);
- direction.x = end.x - start.x;
- direction.y = end.y - start.y;
- direction.z = end.z - start.z;
-
- if ((rayAndPoint(location, start, direction, dist)==true) &&
- (dist[0] <= 1.0))
- return true;
-
- return false;
-
- }
-
- /**
- * Return true if line intersects with point.
- * The line is defined by coordinates[index] to coordinates[index+1]
- *
- * @param point The point that is used in intersection test.
- * @param coordinates an array of vertices.
- * @param index the vertex index
- * @return true if point intersects line, else return false.
- */
-
- public static boolean pointAndLine(PickPoint point, Point3f coordinates[],
- int index ) {
-
- if((coordinates.length - index) < 2)
- throw new RuntimeException(J3dUtilsI18N.getString("Intersect13"));
-
- double dist[] = new double[1];
- Point3d start = new Point3d(coordinates[index++]);
- Point3d end = new Point3d(coordinates[index]);
- Point3d location = new Point3d();
- Vector3d direction = new Vector3d();
-
- point.get(location);
- direction.x = end.x - start.x;
- direction.y = end.y - start.y;
- direction.z = end.z - start.z;
-
- if((rayAndPoint(location, start, direction, dist)==true) && (dist[0] <= 1.0))
- return true;
-
- return false;
-
- }
-
- /**
- * Return true if point is on the inside of halfspace test. The
- * halfspace is
- * partition by the plane of triangle or quad.
- * */
-
- private static boolean pointAndPoly( Point3d coordinates[], PickPoint point) {
-
- Vector3d vec0 = new Vector3d(); // Edge vector from point 0 to point 1;
- Vector3d vec1 = new Vector3d(); // Edge vector from point 0 to point 2 or 3;
- Vector3d pNrm = new Vector3d();
- double absNrmX, absNrmY, absNrmZ, pD = 0.0;
- Vector3d tempV3d = new Vector3d();
- double pNrmDotrDir = 0.0;
-
- double tempD;
-
- int i, j;
-
- // Compute plane normal.
- for(i=0; icom.sun.j3d.utils.picking.PickCanvas
- *
- * @see com.sun.j3d.utils.picking.PickCanvas
- */
-
-public class PickObject extends Object {
-
- // Have to rethink what to support. Is this complete.
-
- /**
- * A flag to indicate to the pickNode method to return a
- * Shape3D
node from
- * a given SceneGraphPath
.
- *
- * @see PickObject#pickNode
- */
- public static final int SHAPE3D = 0x1;
-
- /**
- * A flag to indicate to the pickNode method to return a
- * Morph
node from
- * a given SceneGraphPath
.
- *
- * @see PickObject#pickNode
- */
- public static final int MORPH = 0x2;
-
- /**
- * A flag to indicate to the pickNode method to return a
- * Primitive
node
- * from a given SceneGraphPath
.
- *
- * @see PickObject#pickNode
- */
- public static final int PRIMITIVE = 0x4;
-
- /**
- * A flag to indicate to the pickNode method to return a
- * Link
node from
- * a given SceneGraphPath
.
- *
- * @see PickObject#pickNode
- */
- public static final int LINK = 0x8;
-
- /**
- * A flag to indicate to the pickNode method to return a
- * Group
node from
- * a given SceneGraphPath
.
- *
- * @see PickObject#pickNode
- */
- public static final int GROUP = 0x10;
-
- /**
- * A flag to indicate to the pickNode method to return a
- * TransformGroup
- * node from a given SceneGraphPath
.
- *
- * @see PickObject#pickNode
- */
- public static final int TRANSFORM_GROUP = 0x20;
-
- /**
- * A flag to indicate to the pickNode method to return a
- * BranchGroup
- * node from a given SceneGraphPath
.
- *
- * @see PickObject#pickNode
- */
- public static final int BRANCH_GROUP = 0x40;
-
- /**
- * A flag to indicate to the pickNode method to return a
- * Switch
node from
- * a given SceneGraphPath
.
- *
- * @see PickObject#pickNode
- */
- public static final int SWITCH = 0x80;
-
-
- /**
- * Set this flag if you want to pick by geometry.
- */
- public static final int USE_GEOMETRY = 0x100;
-
-
- /**
- * Set this flag if you want to pick by bounds.
- */
- public static final int USE_BOUNDS = 0x200;
-
- BranchGroup pickRoot;
- Canvas3D canvas;
- Point3d origin = new Point3d();
- Vector3d direction = new Vector3d();
- PickRay pickRay = new PickRay();
- SceneGraphPath sceneGraphPath = null;
- SceneGraphPath sceneGraphPathArr[] = null;
- int pickBy; // To pick by Bounds or Geometry.
-
- static final boolean debug = false;
-
- /**
- * Creates a PickObject.
- * @param c Current J3D canvas.
- * @param root The portion of the scenegraph for which picking is to occur
- * on. It has to be a BranchGroup
.
- *
- * @see BranchGroup
- * @see Canvas3D
- */
- public PickObject(Canvas3D c, BranchGroup root)
- {
- pickRoot = root;
- canvas = c;
- }
-
- /**
- * Creates a PickRay that starts at the viewer position and points into
- * the scene in the direction of (xpos, ypos) specified in window space.
- *
- * @param xpos The value along the x-axis.
- * @param ypos The value along the y-axis.
- * @return A PickShape object that is the constructed PickRay.
- */
- public PickShape generatePickRay(int xpos, int ypos)
- {
-
- Transform3D motion=new Transform3D();
- Point3d eyePosn = new Point3d();
- Point3d mousePosn = new Point3d();
- Vector3d mouseVec=new Vector3d();
-
- canvas.getCenterEyeInImagePlate(eyePosn);
- canvas.getPixelLocationInImagePlate(xpos,ypos,mousePosn);
- if (canvas.getView().getProjectionPolicy() ==
- View.PARALLEL_PROJECTION) {
- // Correct for the parallel projection: keep the eye's z
- // coordinate, but make x,y be the same as the mouse, this
- // simulates the eye being at "infinity"
- eyePosn.x = mousePosn.x;
- eyePosn.y = mousePosn.y;
- }
-
- canvas.getImagePlateToVworld(motion);
-
- if (debug) {
- System.out.println("mouse position " + xpos + " " + ypos);
- System.out.println("before, mouse " + mousePosn + " eye " + eyePosn);
- }
-
- motion.transform(eyePosn);
- motion.transform(mousePosn);
- mouseVec.sub(mousePosn, eyePosn);
- mouseVec.normalize();
-
- if (debug) {
- System.out.println(motion + "\n");
- System.out.println("after, mouse " + mousePosn + " eye " + eyePosn +
- " mouseVec " + mouseVec);
- }
-
- pickRay.set(eyePosn, mouseVec);
-
- return (PickShape) pickRay;
-
- }
-
- /**
- * Returns an array referencing all the items that are pickable below the
- * BranchGroup
(specified in the PickObject constructor) that
- * intersect with a ray that starts at the
- * viewer position and points into the scene in the direction of (xpos, ypos)
- * specified in window space. The resultant array is unordered.
- *
- * @param xpos The value along the x-axis.
- * @param ypos The value along the y-axis.
- * @return The array of SceneGraphPath objects that contain Objects that
- * were picked
- * If no pickable object is found null
is returned..
- *
- * @see SceneGraphPath
- */
- public SceneGraphPath[] pickAll(int xpos, int ypos)
- {
- pickRay = (PickRay) generatePickRay(xpos, ypos);
- sceneGraphPathArr = pickRoot.pickAll(pickRay);
- return sceneGraphPathArr;
- }
-
- /**
- * Returns a sorted array of references to all the Pickable items below the
- * BranchGroup
(specified in the PickObject constructor) that
- * intersect with the ray that starts at the viewer
- * position and points into the scene in the direction of (xpos, ypos)
- * in the window space.
- * Element [0] references the item closest to viewer.
- *
- * @param xpos The value along the x-axis.
- * @param ypos The value along the y-axis.
- * @return A sorted arrayof SceneGraphPath objects that contain Objects that
- * were picked. The array is sorted from closest to farthest from the
- * viewer
- * If no pickable object is found null
is returned..
- *
- * @see SceneGraphPath
- */
- public SceneGraphPath[] pickAllSorted(int xpos, int ypos)
- {
- pickRay = (PickRay) generatePickRay(xpos, ypos);
- sceneGraphPathArr = pickRoot.pickAllSorted(pickRay);
- return sceneGraphPathArr;
- }
-
- /**
- * Returns a reference to any item that is Pickable below the specified
- * BranchGroup
(specified in the PickObject constructor) which
- * intersects with the ray that starts at the viewer
- * position and points into the scene in the direction of (xpos, ypos) in
- * window space.
- *
- * @param xpos The value along the x-axis.
- * @param ypos The value along the y-axis.
- * @return A SceneGraphPath of an object that was picked. This is not
- * guarenteed to return the same result for multiple picks
- * If no pickable object is found null
is returned..
- *
- * @see SceneGraphPath
- */
- public SceneGraphPath pickAny(int xpos, int ypos)
- {
- pickRay = (PickRay) generatePickRay(xpos, ypos);
- sceneGraphPath = pickRoot.pickAny(pickRay);
- return sceneGraphPath;
- }
-
- /**
- * Returns a reference to the item that is closest to the viewer and is
- * Pickable below the BranchGroup
(specified in the PickObject
- * constructor) which intersects with the ray that starts at
- * the viewer position and points into the scene in the direction of
- * (xpos, ypos) in the window space.
- *
- * @param xpos The value along the x-axis.
- * @param ypos The value along the y-axis.
- * @return A SceneGraphPath which contains the closest pickable object.
- * If no pickable object is found, null
is returned.
- *
- * @see SceneGraphPath
- */
- public SceneGraphPath pickClosest(int xpos, int ypos)
- {
- pickRay = (PickRay) generatePickRay(xpos, ypos);
- sceneGraphPath = pickRoot.pickClosest(pickRay);
- return sceneGraphPath;
- }
-
-
- /**
- * Returns an array referencing all the items that are pickable below the
- * BranchGroup
(specified in the PickObject constructor) that
- * intersect with a ray that starts at the
- * viewer position and points into the scene in the direction of (xpos, ypos)
- * specified in window space. The resultant array is unordered.
- *
- * @param xpos The value along the x-axis.
- * @param ypos The value along the y-axis.
- * @param flag Specifys picking by Geometry or Bounds.
- * @return The array of SceneGraphPath objects that contain Objects that
- * were picked
- * If no pickable object is found null
is returned..
- *
- * @see SceneGraphPath
- */
- public SceneGraphPath[] pickAll(int xpos, int ypos, int flag)
- {
-
- if(flag == USE_BOUNDS) {
- return pickAll(xpos, ypos);
- }
- else if(flag == USE_GEOMETRY) {
- return pickGeomAll(xpos, ypos);
- }
- else
- return null;
- }
-
- /**
- * Returns a sorted array of references to all the Pickable items below the
- * BranchGroup
(specified in the PickObject constructor) that
- * intersect with the ray that starts at the viewer
- * position and points into the scene in the direction of (xpos, ypos)
- * in the window space.
- * Element [0] references the item closest to viewer.
- *
- * @param xpos The value along the x-axis.
- * @param ypos The value along the y-axis.
- * @param flag Specifys picking by Geometry or Bounds.
- * @return A sorted arrayof SceneGraphPath objects that contain Objects that
- * were picked. The array is sorted from closest to farthest from the
- * viewer
- * If no pickable object is found null
is returned..
- *
- * @see SceneGraphPath
- */
- public SceneGraphPath[] pickAllSorted(int xpos, int ypos, int flag)
- {
-
- if(flag == USE_BOUNDS) {
- return pickAllSorted(xpos, ypos);
- }
- else if(flag == USE_GEOMETRY) {
- return pickGeomAllSorted(xpos, ypos);
- }
- else
- return null;
-
- }
-
- /**
- * Returns a reference to any item that is Pickable below the specified
- * BranchGroup
(specified in the PickObject constructor) which
- * intersects with the ray that starts at the viewer
- * position and points into the scene in the direction of (xpos, ypos) in
- * window space.
- *
- * @param xpos The value along the x-axis.
- * @param ypos The value along the y-axis.
- * @param flag Specifys picking by Geometry or Bounds.
- * @return A SceneGraphPath of an object that was picked. This is not
- * guarenteed to return the same result for multiple picks
- * If no pickable object is found null
is returned..
- *
- * @see SceneGraphPath
- */
- public SceneGraphPath pickAny(int xpos, int ypos, int flag)
- {
-
- if(flag == USE_BOUNDS) {
- return pickAny(xpos, ypos);
- }
- else if(flag == USE_GEOMETRY) {
- return pickGeomAny(xpos, ypos);
- }
- else
- return null;
- }
-
- /**
- * Returns a reference to the item that is closest to the viewer and is
- * Pickable below the BranchGroup
(specified in the PickObject
- * constructor) which intersects with the ray that starts at
- * the viewer position and points into the scene in the direction of
- * (xpos, ypos) in the window space.
- *
- * @param xpos The value along the x-axis.
- * @param ypos The value along the y-axis.
- * @param flag Specifys picking by Geometry or Bounds.
- * @return A SceneGraphPath which contains the closest pickable object.
- * If no pickable object is found, null
is returned.
- *
- * @see SceneGraphPath
- */
- public SceneGraphPath pickClosest(int xpos, int ypos, int flag)
- {
-
- if(flag == USE_BOUNDS) {
- return pickClosest(xpos, ypos);
- }
- else if(flag == USE_GEOMETRY) {
- return pickGeomClosest(xpos, ypos);
- }
- else
- return null;
- }
-
- private SceneGraphPath[] pickGeomAll(int xpos, int ypos)
- {
- Node obj;
- int i, cnt=0;
-
- pickRay = (PickRay) generatePickRay(xpos, ypos);
- sceneGraphPathArr = pickRoot.pickAll(pickRay);
-
- if(sceneGraphPathArr == null)
- return null;
-
- boolean found[] = new boolean[sceneGraphPathArr.length];
-
- for(i=0; ioccurrence
- * of a Node that is of the specified type.
- *
- * @param sgPath the SceneGraphPath to be traversed.
- * @param flags the Node types interested.
- * @param occurrence the occurrence of a Node that
- * matches the specified type to return. An occurrence
of
- * 1 means to return the first occurrence of that object type (the object
- * closest to the Locale).
- * @return the nth occurrence
of a Node
- * of type flags
, starting from the Locale. If no pickable object is
- * found, null
is returned.
- */
- public Node pickNode(SceneGraphPath sgPath, int flags, int occurrence)
- {
- int curCnt=0;
-
- if (sgPath != null) {
- Node pickedNode = sgPath.getObject();
-
- // Shape3D and Morph are leaf nodes and have no children. It doesn't
- // make sense to do occurrence check here. We'll just return it for now.
- if ((pickedNode instanceof Shape3D) && ((flags & SHAPE3D) != 0)){
- if (debug) System.out.println("Shape3D found");
- return pickedNode;
- } else if ((pickedNode instanceof Morph) && ((flags & MORPH) != 0)){
- if (debug) System.out.println("Morph found");
- return pickedNode;
- }
- else {
- for (int j = 0; j < sgPath.nodeCount(); j++){
- pickedNode = sgPath.getNode(j);
- if (debug) System.out.println("looking at node " + pickedNode);
-
- if ((pickedNode instanceof Group) && ((flags & GROUP) != 0)){
- if (debug) System.out.println("Group found");
- curCnt++;
- if(curCnt == occurrence)
- return pickedNode;
- }
- else if ((pickedNode instanceof BranchGroup) &&
- ((flags & BRANCH_GROUP) != 0)){
- if (debug) System.out.println("Branch group found");
- curCnt++;
- if(curCnt == occurrence)
- return pickedNode;
- }
- else if ((pickedNode instanceof TransformGroup) &&
- ((flags & TRANSFORM_GROUP) != 0)){
- if (debug) System.out.println("xform group found");
- curCnt++;
- if(curCnt == occurrence)
- return pickedNode;
- }
- else if ((pickedNode instanceof Primitive) &&
- ((flags & PRIMITIVE) != 0)){
- if (debug) System.out.println("Primitive found");
- curCnt++;
- if(curCnt == occurrence)
- return pickedNode;
- }
- else if ((pickedNode instanceof Link) && ((flags & LINK) != 0)){
- if (debug) System.out.println("Link found");
- curCnt++;
- if(curCnt == occurrence)
- return pickedNode;
- }
- }
-
- if (pickedNode == null)
- if (debug) System.out.println("ERROR: null SceneGraphPath");
- }
-
- }
-
- return null;
-
- }
-
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickRotateBehavior.java b/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickRotateBehavior.java
deleted file mode 100644
index 7e491e0..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickRotateBehavior.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.picking;
-
-import javax.media.j3d.Bounds;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-
-import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
-import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
-
-/*
- * A mouse behavior that allows user to pick and drag scene graph objects.
- * Common usage:
- * - * 1. Create your scene graph. - *
- * 2. Create this behavior with root and canvas. - *
- *
- *- * PickRotateBehavior behavior = new PickRotateBehavior(canvas, root, bounds); - * root.addChild(behavior); - *
- * The above behavior will monitor for any picking events on
- * the scene graph (below root node) and handle mouse drags on pick hits.
- * Note the root node can also be a subgraph node of the scene graph (rather
- * than the topmost).
- */
-
-/**
- * @deprecated As of Java 3D version 1.2, replaced by
- * com.sun.j3d.utils.picking.behaviors.PickRotateBehavior
- *
- * @see com.sun.j3d.utils.picking.behaviors.PickRotateBehavior
- */
-
-public class PickRotateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
- MouseRotate drag;
- int pickMode = PickObject.USE_BOUNDS;
- private PickingCallback callback=null;
- private TransformGroup currentTG;
-
- /**
- * Creates a pick/rotate behavior that waits for user mouse events for
- * the scene graph. This method has its pickMode set to BOUNDS picking.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- **/
-
- public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
- super(canvas, root, bounds);
- drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
- drag.setTransformGroup(currGrp);
- currGrp.addChild(drag);
- drag.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- }
-
- /**
- * Creates a pick/rotate behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- * @param pickMode specifys PickObject.USE_BOUNDS or PickObject.USE_GEOMETRY.
- * Note: If pickMode is set to PickObject.USE_GEOMETRY, all geometry object in
- * the scene graph that allows pickable must have its ALLOW_INTERSECT bit set.
- **/
-
- public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
- int pickMode){
- super(canvas, root, bounds);
- drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
- drag.setTransformGroup(currGrp);
- currGrp.addChild(drag);
- drag.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- this.pickMode = pickMode;
- }
-
- /**
- * Sets the pickMode component of this PickRotateBehavior to the value of
- * the passed pickMode.
- * @param pickMode the pickMode to be copied.
- **/
-
-
- public void setPickMode(int pickMode) {
- this.pickMode = pickMode;
- }
-
- /**
- * Return the pickMode component of this PickRotateBehavior.
- **/
-
- public int getPickMode() {
- return pickMode;
- }
-
- /**
- * Update the scene to manipulate any nodes. This is not meant to be
- * called by users. Behavior automatically calls this. You can call
- * this only if you know what you are doing.
- *
- * @param xpos Current mouse X pos.
- * @param ypos Current mouse Y pos.
- **/
- @Override
- public void updateScene(int xpos, int ypos){
- TransformGroup tg = null;
-
- if (!mevent.isMetaDown() && !mevent.isAltDown()){
-
- // tg = (TransformGroup) pickScene.pickNode(pickScene.pickClosest(xpos, ypos),
- // PickObject.TRANSFORM_GROUP);
-
- tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos, ypos,pickMode),
- PickObject.TRANSFORM_GROUP);
- // Make sure the selection exists and is movable.
- if ((tg != null) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
- drag.setTransformGroup(tg);
- drag.wakeup();
- currentTG = tg;
- } else if (callback!=null)
- callback.transformChanged( PickingCallback.NO_PICK, null );
- }
- }
-
- /**
- * Callback method from MouseRotate
- * This is used when the Picking callback is enabled
- */
- @Override
- public void transformChanged( int type, Transform3D transform ) {
- callback.transformChanged( PickingCallback.ROTATE, currentTG );
- }
-
- /**
- * Register the class @param callback to be called each
- * time the picked object moves
- */
- public void setupCallback( PickingCallback callback ) {
- this.callback = callback;
- if (callback==null)
- drag.setupCallback( null );
- else
- drag.setupCallback( this );
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickTranslateBehavior.java b/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickTranslateBehavior.java
deleted file mode 100644
index 89b307a..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickTranslateBehavior.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.picking;
-
-import javax.media.j3d.Bounds;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-
-import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
-import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
-import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
-
-// A mouse behavior that allows user to pick and translate scene graph objects.
-// Common usage: 1. Create your scene graph. 2. Create this behavior with
-// the root and canvas. See PickRotateBehavior for more details.
-
-/**
- * @deprecated As of Java 3D version 1.2, replaced by
- * com.sun.j3d.utils.picking.behaviors.PickTranslateBehavior
- *
- * @see com.sun.j3d.utils.picking.behaviors.PickTranslateBehavior
- */
-
-public class PickTranslateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
- MouseTranslate translate;
- int pickMode = PickObject.USE_BOUNDS;
- private PickingCallback callback = null;
- private TransformGroup currentTG;
-
- /**
- * Creates a pick/translate behavior that waits for user mouse events for
- * the scene graph. This method has its pickMode set to BOUNDS picking.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- **/
-
- public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
- super(canvas, root, bounds);
- translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
- translate.setTransformGroup(currGrp);
- currGrp.addChild(translate);
- translate.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- }
-
- /**
- * Creates a pick/translate behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- * @param pickMode specifys PickObject.USE_BOUNDS or PickObject.USE_GEOMETRY.
- * Note: If pickMode is set to PickObject.USE_GEOMETRY, all geometry object in
- * the scene graph that allows pickable must have its ALLOW_INTERSECT bit set.
- **/
-
- public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
- int pickMode){
- super(canvas, root, bounds);
- translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
- translate.setTransformGroup(currGrp);
- currGrp.addChild(translate);
- translate.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- this.pickMode = pickMode;
- }
-
- /**
- * Sets the pickMode component of this PickTranslateBehavior to the value of
- * the passed pickMode.
- * @param pickMode the pickMode to be copied.
- **/
-
- public void setPickMode(int pickMode) {
- this.pickMode = pickMode;
- }
-
- /**
- * Return the pickMode component of this PickTranslaeBehavior.
- **/
-
- public int getPickMode() {
- return pickMode;
- }
-
- /**
- * Update the scene to manipulate any nodes. This is not meant to be
- * called by users. Behavior automatically calls this. You can call
- * this only if you know what you are doing.
- *
- * @param xpos Current mouse X pos.
- * @param ypos Current mouse Y pos.
- **/
- @Override
- public void updateScene(int xpos, int ypos){
- TransformGroup tg = null;
-
- if (!mevent.isAltDown() && mevent.isMetaDown()){
-
- tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos, ypos, pickMode),
- PickObject.TRANSFORM_GROUP);
- //Check for valid selection.
- if ((tg != null) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
-
- translate.setTransformGroup(tg);
- translate.wakeup();
- currentTG = tg;
- } else if (callback!=null)
- callback.transformChanged( PickingCallback.NO_PICK, null );
- }
-
- }
-
- /**
- * Callback method from MouseTranslate
- * This is used when the Picking callback is enabled
- */
- @Override
- public void transformChanged( int type, Transform3D transform ) {
- callback.transformChanged( PickingCallback.TRANSLATE, currentTG );
- }
-
- /**
- * Register the class @param callback to be called each
- * time the picked object moves
- */
- public void setupCallback( PickingCallback callback ) {
- this.callback = callback;
- if (callback==null)
- translate.setupCallback( null );
- else
- translate.setupCallback( this );
- }
-
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickZoomBehavior.java b/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickZoomBehavior.java
deleted file mode 100644
index c405451..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickZoomBehavior.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.picking;
-
-import javax.media.j3d.Bounds;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-
-import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
-import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
-import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
-
-
-// A mouse behavior that allows user to pick and zoom scene graph objects.
-// Common usage: 1. Create your scene graph. 2. Create this behavior with
-// the root and canvas. See PickRotateBehavior for more details.
-
-/**
- * @deprecated As of Java 3D version 1.2, replaced by
- * com.sun.j3d.utils.picking.behaviors.PickZoomBehavior
- *
- * @see com.sun.j3d.utils.picking.behaviors.PickZoomBehavior
- */
-
-public class PickZoomBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
- MouseZoom zoom;
- int pickMode = PickObject.USE_BOUNDS;
- private PickingCallback callback = null;
- private TransformGroup currentTG;
-
- /**
- * Creates a pick/zoom behavior that waits for user mouse events for
- * the scene graph. This method has its pickMode set to BOUNDS picking.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- **/
-
- public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
- super(canvas, root, bounds);
- zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
- zoom.setTransformGroup(currGrp);
- currGrp.addChild(zoom);
- zoom.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- }
-
- /**
- * Creates a pick/zoom behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- * @param pickMode specifys PickObject.USE_BOUNDS or PickObject.USE_GEOMETRY.
- * Note: If pickMode is set to PickObject.USE_GEOMETRY, all geometry object in
- * the scene graph that allows pickable must have its ALLOW_INTERSECT bit set.
- **/
-
- public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
- int pickMode){
- super(canvas, root, bounds);
- zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
- zoom.setTransformGroup(currGrp);
- currGrp.addChild(zoom);
- zoom.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- this.pickMode = pickMode;
- }
-
- /**
- * Sets the pickMode component of this PickZoomBehavior to the value of
- * the passed pickMode.
- * @param pickMode the pickMode to be copied.
- **/
-
- public void setPickMode(int pickMode) {
- this.pickMode = pickMode;
- }
-
-
- /**
- * Return the pickMode component of this PickZoomBehavior.
- **/
-
- public int getPickMode() {
- return pickMode;
- }
-
-
- /**
- * Update the scene to manipulate any nodes. This is not meant to be
- * called by users. Behavior automatically calls this. You can call
- * this only if you know what you are doing.
- *
- * @param xpos Current mouse X pos.
- * @param ypos Current mouse Y pos.
- **/
-
- @Override
- public void updateScene(int xpos, int ypos){
- TransformGroup tg = null;
-
- if (mevent.isAltDown() && !mevent.isMetaDown()){
-
- tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos, ypos, pickMode),
- PickObject.TRANSFORM_GROUP);
-
- // Check for valid selection
- if ((tg != null) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
- zoom.setTransformGroup(tg);
- zoom.wakeup();
- currentTG = tg;
- } else if (callback!=null)
- callback.transformChanged( PickingCallback.NO_PICK, null );
- }
- }
-
- /**
- * Callback method from MouseZoom
- * This is used when the Picking callback is enabled
- */
- @Override
- public void transformChanged( int type, Transform3D transform ) {
- callback.transformChanged( PickingCallback.ZOOM, currentTG );
- }
-
- /**
- * Register the class @param callback to be called each
- * time the picked object moves
- */
- public void setupCallback( PickingCallback callback ) {
- this.callback = callback;
- if (callback==null)
- zoom.setupCallback( null );
- else
- zoom.setupCallback( this );
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickingCallback.java b/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickingCallback.java
deleted file mode 100644
index f2b625e..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/picking/PickingCallback.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.picking;
-
-import javax.media.j3d.TransformGroup;
-
-/**
- * @deprecated As of Java 3D version 1.2, replaced by
- * com.sun.j3d.utils.picking.behaviors.PickingCallback
- *
- * @see com.sun.j3d.utils.picking.behaviors.PickingCallback
- */
-
-public interface PickingCallback {
-
- public final static int ROTATE=0;
- public final static int TRANSLATE=1;
- public final static int ZOOM=2;
-
- /**
- * The user made a selection but nothing was
- * actually picked
- */
- public final static int NO_PICK=3;
-
- /**
- * Called by the Pick Behavior with which this callback
- * is registered each time the Picked object is moved
- */
- public void transformChanged( int type, TransformGroup tg );
-}
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/picking/package.html b/src/classes/share/com/sun/j3d/utils/behaviors/picking/package.html
deleted file mode 100644
index b5d0b77..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/picking/package.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
Deprecated: Use com.sun.j3d.utils.pickfast.behaviors
-instead.
- * The default echo is a solid 6-pointed star where each point is aligned
- * with the axes of the local coordinate system of the sensor, and with
- * the center of the star at the location of the sensor hotspot.
- *
- * @param sensor a 6 degree of freedom Sensor which generates position
- * and orientation relative to the tracker base.
- * @param size the physical width of the echo in centimeters.
- * @param enableLighting a boolean indicating whether the echo geometry
- * should have lighting enabled.
- */
- public Mouse6DPointerBehavior(Sensor sensor, double size,
- boolean enableLighting) {
-
- this.sensor = sensor ;
- echoTransformGroup = new TransformGroup() ;
- echoTransformGroup.setCapability
- (TransformGroup.ALLOW_TRANSFORM_WRITE) ;
-
- Point3d hotspot = new Point3d() ;
- sensor.getHotspot(hotspot) ;
-
- Transform3D t3d = new Transform3D() ;
- Vector3f v3f = new Vector3f(hotspot) ;
- t3d.set(v3f) ;
-
- Shape3D echo =
- new SensorGnomonEcho(t3d, 0.001*size, 0.005*size, enableLighting) ;
- echoTransformGroup.addChild(echo) ;
-
- eventAgent = new SensorEventAgent(this) ;
- eventAgent.addSensorReadListener(sensor, new EchoReadListener()) ;
- }
-
- /**
- * Constructs the behavior with an echo parented by the specified
- * TransformGroup.
- *
- * @param sensor a 6 degree of freedom Sensor which generates position
- * and orientation relative to the tracker base.
- * @param tg a TransformGroup with a child defining the visible echo
- * which will track the Sensor position and orientation; the Transform3D
- * associated with the TransformGroup will be updated in order to effect
- * the behavior, so it must have the ALLOW_TRANSFORM_WRITE capability
- * set before the scene graph is set live
- */
- public Mouse6DPointerBehavior(Sensor sensor, TransformGroup tg) {
- this.sensor = sensor ;
- echoTransformGroup = tg ;
- eventAgent = new SensorEventAgent(this) ;
- eventAgent.addSensorReadListener(sensor, new EchoReadListener()) ;
- }
-
- /**
- * Gets the sensor used by this behavior.
- *
- * @return the sensor used by this behavior
- */
- public Sensor getSensor() {
- return sensor ;
- }
-
- /**
- * Gets the echo used by this behavior.
- *
- * @return the TransformGroup parenting this behavior's echo geometry
- */
- public TransformGroup getEcho() {
- return echoTransformGroup ;
- }
-
- /**
- * Gets the SensorEventAgent used by this behavior. This can be used to
- * add customized event bindings to this behavior.
- *
- * @return the SensorEventAgent
- */
- public SensorEventAgent getSensorEventAgent() {
- return eventAgent ;
- }
-
- /**
- * Initializes the behavior.
- * NOTE: Applications should not call this method. It is called by the
- * Java 3D behavior scheduler.
- */
- @Override
- public void initialize() {
- wakeupOn(conditions) ;
- }
-
- /**
- * Processes a stimulus meant for this behavior.
- * NOTE: Applications should not call this method. It is called by the
- * Java 3D behavior scheduler.
- */
- @Override
- public void processStimulus(Enumeration criteria) {
- eventAgent.dispatchEvents() ;
- wakeupOn(conditions) ;
- }
-
- /**
- * This member class updates the echo transform in response to sensor
- * reads.
- */
- public class EchoReadListener implements SensorReadListener {
- private Transform3D t3d = new Transform3D() ;
-
- @Override
- public void read(SensorEvent e) {
- // Get the Transform3D that transforms points from local sensor
- // coordinates to virtual world coordinates, based on the primary
- // view associated with this Behavior. This view is defined to be
- // the first View attached to a live ViewPlatform.
- //
- // Note that this will display frame lag if another behavior such
- // as OrbitBehavior is used to manipulate the view transform while
- // the echo is visible. In order to eliminate frame lag the
- // behavior driving the view transform must also compute the echo
- // transform as well. See the WandViewBehavior utility for the
- // appropriate techniques.
- getView().getSensorToVworld(e.getSensor(), t3d) ;
- echoTransformGroup.setTransform(t3d) ;
- }
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorBeamEcho.java b/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorBeamEcho.java
deleted file mode 100644
index 7a98660..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorBeamEcho.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.sensor ;
-
-import javax.media.j3d.Appearance;
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.Material;
-import javax.media.j3d.Shape3D;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransparencyAttributes;
-import javax.media.j3d.TriangleStripArray;
-import javax.vecmath.AxisAngle4f;
-import javax.vecmath.Point3d;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3f;
-
-/**
- * A Shape3D representing a beam pointing from the origin of a
- * sensor's local coordinate system to its hotspot.
- *
- * @since Java 3D 1.3
- */
-public class SensorBeamEcho extends Shape3D {
- /**
- * Creates a SensorBeamEcho. Read and write capabilities are granted
- * for the Appearance, Material, TransparencyAttributes, and
- * TransparencyAttributes mode and value.
- *
- * @param hotspot location of the sensor's hotspot in the sensor's
- * local coordinate system; this must not be (0, 0, 0)
- * @param baseWidth width of the beam in meters
- * @param enableLighting boolean indicating whether normals should be
- * generated and lighting enabled
- * @exception IllegalArgumentException if hotspot is (0, 0, 0)
- */
- public SensorBeamEcho(Point3d hotspot, double baseWidth,
- boolean enableLighting) {
- super() ;
-
- if (hotspot.distance(new Point3d()) == 0.0)
- throw new IllegalArgumentException
- ("\nBeam echo can't have hotspot at origin") ;
-
- Vector3f axis = new Vector3f((float)hotspot.x,
- (float)hotspot.y,
- (float)hotspot.z) ;
-
- Vector3f axis1 = new Vector3f() ;
- axis1.normalize(axis) ;
-
- // Choose an arbitrary vector normal to the beam axis.
- Vector3f normal = new Vector3f(0.0f, 1.0f, 0.0f) ;
- normal.cross(axis1, normal) ;
- if (normal.lengthSquared() < 0.5f) {
- normal.set(0.0f, 0.0f, 1.0f) ;
- normal.cross(axis1, normal) ;
- }
- normal.normalize() ;
-
- // Create cap vertices and normals.
- int divisions = 18 ;
- Point3f[] cap0 = new Point3f[divisions] ;
- Point3f[] cap1 = new Point3f[divisions] ;
- Vector3f[] capNormals = new Vector3f[divisions] ;
- Vector3f cap0Normal = new Vector3f(axis1) ;
- Vector3f cap1Normal = new Vector3f(axis1) ;
- cap0Normal.negate() ;
-
- AxisAngle4f aa4f = new AxisAngle4f
- (axis1, -(float)Math.PI/((float)divisions/2.0f)) ;
- Transform3D t3d = new Transform3D() ;
- t3d.set(aa4f) ;
-
- float halfWidth = (float)baseWidth / 2.0f ;
- for (int i = 0 ; i < divisions ; i++) {
- capNormals[i] = new Vector3f(normal) ;
- cap0[i] = new Point3f(normal) ;
- cap0[i].scale(halfWidth) ;
- cap1[i] = new Point3f(cap0[i]) ;
- cap1[i].add(axis) ;
- t3d.transform(normal) ;
- }
-
- // The beam cylinder is created with 3 triangle strips. The first
- // strip contains the side facets (2 + 2*divisions vertices), and
- // the other two strips are the caps (divisions vertices each).
- int vertexCount = 2 + (4 * divisions) ;
- Point3f[] vertices = new Point3f[vertexCount] ;
- Vector3f[] normals = new Vector3f[vertexCount] ;
-
- // Side facets.
- for (int i = 0 ; i < divisions ; i++) {
- vertices[i*2] = cap0[i] ;
- vertices[(i*2) + 1] = cap1[i] ;
-
- normals[i*2] = capNormals[i] ;
- normals[(i*2) + 1] = capNormals[i] ;
- }
-
- vertices[divisions*2] = cap0[0] ;
- vertices[(divisions*2) + 1] = cap1[0] ;
-
- normals[divisions*2] = capNormals[0] ;
- normals[(divisions*2) + 1] = capNormals[0] ;
-
- // Strips for caps created by criss-crossing the interior.
- int v = (divisions+1) * 2 ;
- vertices[v] = cap0[0] ;
- normals[v++] = cap0Normal ;
-
- int j = 1 ;
- int k = divisions - 1 ;
- while (j <= k) {
- vertices[v] = cap0[j++] ;
- normals[v++] = cap0Normal ;
- if (j > k) break ;
- vertices[v] = cap0[k--] ;
- normals[v++] = cap0Normal ;
- }
-
- vertices[v] = cap1[0] ;
- normals[v++] = cap1Normal ;
-
- j = 1 ;
- k = divisions - 1 ;
- while (j <= k) {
- vertices[v] = cap1[k--] ;
- normals[v++] = cap1Normal ;
- if (j > k) break ;
- vertices[v] = cap1[j++] ;
- normals[v++] = cap1Normal ;
- }
-
- // Create the TriangleStripArray.
- int vertexFormat ;
- Material m = new Material() ;
- m.setCapability(Material.ALLOW_COMPONENT_READ) ;
- m.setCapability(Material.ALLOW_COMPONENT_WRITE) ;
-
- if (enableLighting) {
- vertexFormat =
- GeometryArray.COORDINATES | GeometryArray.NORMALS ;
- m.setLightingEnable(true) ;
- }
- else {
- vertexFormat = GeometryArray.COORDINATES ;
- m.setLightingEnable(false) ;
- }
-
- int[] stripCounts = new int[3] ;
- stripCounts[0] = 2 + (2 * divisions) ;
- stripCounts[1] = divisions ;
- stripCounts[2] = divisions ;
-
- TriangleStripArray tsa =
- new TriangleStripArray(vertexCount,
- vertexFormat, stripCounts) ;
-
- tsa.setCoordinates(0, vertices) ;
- if (enableLighting)
- tsa.setNormals(0, normals) ;
-
- Appearance a = new Appearance() ;
- a.setMaterial(m) ;
- a.setCapability(Appearance.ALLOW_MATERIAL_READ) ;
- a.setCapability(Appearance.ALLOW_MATERIAL_WRITE) ;
-
- TransparencyAttributes ta = new TransparencyAttributes() ;
- ta.setCapability(TransparencyAttributes.ALLOW_MODE_READ) ;
- ta.setCapability(TransparencyAttributes.ALLOW_MODE_WRITE) ;
- ta.setCapability(TransparencyAttributes.ALLOW_VALUE_READ) ;
- ta.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE) ;
- ta.setCapability
- (TransparencyAttributes.ALLOW_BLEND_FUNCTION_READ) ;
- ta.setCapability
- (TransparencyAttributes.ALLOW_BLEND_FUNCTION_WRITE) ;
-
- a.setTransparencyAttributes(ta) ;
- a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_READ) ;
- a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE) ;
-
- setGeometry(tsa) ;
- setAppearance(a) ;
-
- setCapability(ALLOW_APPEARANCE_READ) ;
- setCapability(ALLOW_APPEARANCE_WRITE) ;
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorButtonListener.java b/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorButtonListener.java
deleted file mode 100644
index 0b54985..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorButtonListener.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.sensor ;
-
-/**
- * This defines the interface for handling a sensor's button events in
- * conjunction with a SensorEventAgent
instance.
- *
- * The events passed to this listener's methods are ephemeral; they
- * are only valid until the listener has returned. If a listener needs to
- * retain the event it must be copied using the
- * SensorEvent(SensorEvent)
constructor.
- *
- * @see SensorEvent
- * @see SensorEventAgent
- * @see SensorReadListener
- * @since Java 3D 1.3
- */
-public interface SensorButtonListener {
- /**
- * This method is called when a sensor's button is pressed.
- *
- * @param e the sensor event
- */
- public void pressed(SensorEvent e) ;
-
- /**
- * This method is called when a sensor's button is released.
- *
- * @param e the sensor event
- */
- public void released(SensorEvent e) ;
-
- /**
- * This method is called with each invocation of the
- * dispatchEvents
method of SensorEventAgent
- * if any button bound to the listener is down and has not changed
- * state since the last invocation. The sensor value has not
- * necessarily changed from the last drag event.
- *
- * @param e the sensor event
- */
- public void dragged(SensorEvent e) ;
-
- /**
- * This method is currently not used by SensorEventAgent
,
- * but is included here for future possible development. Its
- * implementations should remain empty for the present.
- */
- public void clicked(SensorEvent e) ;
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEvent.java b/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEvent.java
deleted file mode 100644
index 980cda3..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEvent.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.sensor ;
-
-import javax.media.j3d.Sensor;
-import javax.media.j3d.Transform3D;
-
-/**
- * This class defines the event object that is created by a
- * SensorEventAgent
and passed to registered
- * SensorReadListener
and SensorButtonListener
- * implementations.
- *
- * The events passed to the listeners are ephemeral; they are only
- * valid until the listener has returned. This is done to avoid
- * allocating large numbers of mostly temporary objects, especially for
- * behaviors that wake up every frame. If a listener needs to retain the
- * event it must be copied using the SensorEvent(SensorEvent)
- * constructor.
- *
- * @see SensorEventAgent
- * @see SensorButtonListener
- * @see SensorReadListener
- * @since Java 3D 1.3
- */
-public class SensorEvent {
- /**
- * A button pressed event.
- */
- public static final int PRESSED = 1 ;
-
- /**
- * A button released event.
- */
- public static final int RELEASED = 2 ;
-
- /**
- * A button dragged event.
- */
- public static final int DRAGGED = 3 ;
-
- /**
- * A sensor read event.
- */
- public static final int READ = 4 ;
-
- /**
- * The value that is returned by getButton
when no
- * buttons have changed state.
- */
- public static final int NOBUTTON = -1 ;
-
- private int id = 0 ;
- private Object source = null ;
- private Sensor sensor = null ;
- private int button = NOBUTTON ;
- private int[] buttonState = null ;
- private Transform3D sensorRead = null ;
- private long time = 0 ;
- private long lastTime = 0 ;
- private boolean ephemeral = false ;
-
- /**
- * Creates a new SensorEvent
.
- *
- * @param source a reference to the originating object which
- * instantiated the SensorEventAgent
, usually a
- * Behavior
; may be null
- * @param id event type
- * @param sensor a reference to the provoking sensor
- * @param sensorRead the sensor's read value at the time of the event
- * @param buttonState the state of the sensor's buttons at the time of
- * the event, where a 1 in the array indicates that the button at that
- * index is down, and a 0 indicates that button is up; may be null
- * @param button index of the button that changed state, from 0 to
- * (buttonCount - 1)
, or the value NOBUTTON
- * @param time the time in nanoseconds at which the
- * dispatchEvents
method of
- * SensorEventAgent
was called to generate this event,
- * usually from the processStimulus
method of a Behavior
- * @param lastTime the time in nanoseconds at which the
- * dispatchEvents
method of
- * SensorEventAgent
was last called to generate
- * events, usually from the processStimulus
method of a
- * Behavior
; may be used to measure frame time in
- * behaviors that wake up every frame
- */
- public SensorEvent(Object source, int id, Sensor sensor,
- Transform3D sensorRead, int[] buttonState,
- int button, long time, long lastTime) {
-
- this.source = source ;
- this.id = id ;
- this.sensor = sensor ;
- this.button = button ;
- this.time = time ;
- this.lastTime = lastTime ;
- if (sensorRead == null)
- throw new NullPointerException("sensorRead can't be null") ;
- this.sensorRead = new Transform3D(sensorRead) ;
- if (buttonState != null) {
- this.buttonState = new int[buttonState.length] ;
- for (int i = 0 ; i < buttonState.length ; i++)
- this.buttonState[i] = buttonState[i] ;
- }
- this.ephemeral = false ;
- }
-
- /**
- * Creates a new ephemeral SensorEvent
. In order
- * to avoid creating large numbers of sensor event objects, the events
- * passed to the button and read listeners by the
- * dispatchEvents
method of SensorEventAgent
- * are valid only until the listener returns. If the event needs to
- * be retained then they must be copied with the
- * SensorEvent(SensorEvent)
constructor.
- */
- public SensorEvent() {
- this.ephemeral = true ;
- }
-
- /**
- * Creates a copy of the given SensorEvent
. Listeners
- * must use this constructor to copy events that need to be retained.
- * NOTE: The Sensor
and Object
references
- * returned by getSensor
and getSource
- * remain references to the original objects.
- *
- * @param e the event to be copied
- */
- public SensorEvent(SensorEvent e) {
- this.source = e.source ;
- this.id = e.id ;
- this.sensor = e.sensor ;
- this.button = e.button ;
- this.time = e.time ;
- this.lastTime = e.lastTime ;
- if (e.sensorRead == null)
- throw new NullPointerException("sensorRead can't be null") ;
- this.sensorRead = new Transform3D(e.sensorRead) ;
- if (e.buttonState != null) {
- this.buttonState = new int[e.buttonState.length] ;
- for (int i = 0 ; i < e.buttonState.length ; i++)
- this.buttonState[i] = e.buttonState[i] ;
- }
- this.ephemeral = false ;
- }
-
- /**
- * Sets the fields of an ephemeral event. No objects are copied. An
- * IllegalStateException
will be thrown if this event
- * is not ephemeral.
- *
- * @param source a reference to the originating object which
- * instantiated the SensorEventAgent
, usually a
- * Behavior
; may be null
- * @param id event type
- * @param sensor a reference to the provoking sensor
- * @param sensorRead the sensor's read value at the time of the event
- * @param buttonState the state of the sensor's buttons at the time of
- * the event; a 1 in the array indicates that the button at that
- * index is down, while a 0 indicates that button is up
- * @param button index of the button that changed state, from 0 to
- * (buttonCount - 1)
, or the value NOBUTTON
- * @param time the time in nanoseconds at which the
- * dispatchEvents
method of
- * SensorEventAgent
was called to generate this event,
- * usually from the processStimulus
method of a Behavior
- * @param lastTime the time in nanoseconds at which the
- * dispatchEvents
method of
- * SensorEventAgent
was last called to generate
- * events, usually from the processStimulus
method of a
- * Behavior
; may be used to measure frame time in
- * behaviors that wake up every frame
- */
- public void set(Object source, int id, Sensor sensor,
- Transform3D sensorRead, int[] buttonState,
- int button, long time, long lastTime) {
-
- if (!ephemeral)
- throw new IllegalStateException
- ("Can't set the fields of non-ephemeral events") ;
-
- this.source = source ;
- this.id = id ;
- this.sensor = sensor ;
- if (sensorRead == null)
- throw new NullPointerException("sensorRead can't be null") ;
- this.sensorRead = sensorRead ;
- this.buttonState = buttonState ;
- this.button = button ;
- this.time = time ;
- this.lastTime = lastTime ;
- }
-
- /**
- * Gets a reference to the originating object which instantiated the
- * SensorEventAgent
, usually a Behavior
; may
- * be null.
- * @return the originating object
- */
- public Object getSource() {
- return source ;
- }
-
- /**
- * Gets the event type.
- * @return the event id
- */
- public int getID() {
- return id ;
- }
-
-
- /**
- * Gets a reference to the provoking sensor.
- * @return the provoking sensor
- */
- public Sensor getSensor() {
- return sensor ;
- }
-
- /**
- * Gets the time in nanoseconds at which the
- * dispatchEvents
method of SensorEventAgent
- * was called to generate this event, usually from the
- * processStimulus
method of a Behavior
.
- * @return time in nanoseconds
- */
- public long getTime() {
- return time ;
- }
-
- /**
- * Gets the time in nanoseconds at which the
- * dispatchEvents
method of SensorEventAgent
- * was last called to generate events, usually from the
- * processStimulus
method of a Behavior
; may
- * be used to measure frame time in behaviors that wake up every
- * frame.
- * @return last time in nanoseconds
- */
- public long getLastTime() {
- return lastTime ;
- }
-
- /**
- * Copies the sensor's read value at the time of the event into the
- * given Transform3D
.
- *
- * @param t the transform to receive the sensor read
- */
- public void getSensorRead(Transform3D t) {
- t.set(sensorRead) ;
- }
-
- /**
- * Gets the index of the button that changed state when passed to a
- * pressed
or released
callback. The index
- * may range from 0 to (sensor.getSensorButtonCount() -
- * 1)
. The value returned is NOBUTTON
for events
- * passed to a read
or dragged
callback.
- * @return the button index
- */
- public int getButton() {
- return button ;
- }
-
- /**
- * Copies the state of the sensor's buttons at the time of the event
- * into the given array. A 1 in the array indicates that the button
- * at that index is down, while a 0 indicates that button is up.
- * @param buttonState the state of the sensor buttons
- */
- public void getButtonState(int[] buttonState) {
- if (buttonState.length != this.buttonState.length)
- throw new ArrayIndexOutOfBoundsException
- ("buttonState array is the wrong length") ;
-
- for (int i = 0 ; i < buttonState.length ; i++)
- buttonState[i] = this.buttonState[i] ;
- }
-
- /**
- * Returns true if this event is ephemeral and is valid only
- * until the listener returns. A copy of the event can be created by
- * passing it to the SensorEvent(SensorEvent)
- * constructor.
- */
- public boolean isEphemeral() {
- return ephemeral ;
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEventAgent.java b/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEventAgent.java
deleted file mode 100644
index dac15e3..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorEventAgent.java
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.sensor ;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.media.j3d.Sensor;
-import javax.media.j3d.Transform3D;
-
-import com.sun.j3d.utils.timer.J3DTimer;
-
-/**
- * This class works in conjunction with the SensorButtonListener
- * and SensorReadListener
interfaces to support an event-driven
- * model of sensor interaction. Java 3D defines sensors as delivering
- * continuous input data which must be polled to retrieve their values, but in
- * practice it is often convenient to structure application code to respond to
- * events such as button state transitions.
- *
- * Listeners registered with this class are invoked when its
- * dispatchEvents
method is called. This is usually called from
- * the processStimulus
method of a Behavior
, but may
- * also be called directly from the pollAndProcessInput
method of
- * an event-driven implementation of InputDevice
. In either case
- * the device is still polled by the Java 3D input device scheduling thread to
- * get its current values; however, in the former, dispatchEvents
- * is called from the behavior scheduler thread regardless of whether any new
- * events are available, while in the latter, the InputDevice
- * implementation may choose to call dispatchEvents
only if new
- * events are actually generated.
- *
- * Button events are generated by changes in sensor button state, from pressed
- * to released and vice versa. Button state changes are examined with each
- * invocation of the dispatchEvents
method. Events are
- * distributed to interested parties through the button listener interface
- * using the pressed
and released
callbacks.
- *
- * The dragged
method is not necessarily called in response to a
- * motion event generated by a sensor. dispatchEvents
will call
- * dragged
whenever any button assigned to the listener is down
- * and has not changed state since the last time it was called. If
- * dispatchEvents
is called in the processStimulus
- * of a Behavior
, then dragged
may be called even if
- * the sensor value has not changed. This is as a consequence of the core
- * Java 3D API definition of sensors as continuous devices.
- *
- * Like dragged
, the read
method of
- * SensorReadListener
is not necessarily invoked in response to a
- * real event. It is called by dispatchEvents
whenever a button
- * listener has not been called for that sensor. This usually means that no
- * buttons are down, but clients are free to leave a button listener null, or
- * to explicitly bind a null button listener to a button so that button's
- * events are ignored. The sensor value has not necessarily changed since the
- * last read
callback.
- *
- * A mutual exclusion policy can be applied between button
- * listeners when they are grouped in an array mapped to the sensor's
- * buttons. If multiple sensor buttons are held down at the same time,
- * then a listener in the array is invoked only for the button that was
- * depressed first. The read
callback is separated from the
- * pressed
, released
, and dragged
- * callbacks in a separate interface in order to support this policy.
- *
- * The events passed to the listeners are ephemeral; they are only
- * valid until the listener has returned. This is done to avoid
- * allocating large numbers of mostly temporary objects, especially for
- * behaviors that wake up every frame. If a listener needs to retain the
- * event it must be copied using the SensorEvent(SensorEvent)
- * constructor.
- *
- * It is safe to add and remove listeners in response to a callback.
- *
- * @see SensorEvent
- * @see SensorButtonListener
- * @see SensorReadListener
- * @since Java 3D 1.3
- */
-public class SensorEventAgent {
- private long t0 = 0 ;
- private Object source = null ;
- private SensorEvent e = new SensorEvent() ;
-
- // List of SensorBinding objects and corresponding array.
- private List bindingsList = new ArrayList() ;
- private SensorBinding[] bindings = new SensorBinding[0] ;
-
- // Indicates that lists must be converted to arrays. Need to do this
- // to allow listeners to add and remove themselves or other listeners
- // safely during event dispatch.
- private boolean listsDirty = false ;
-
- /**
- * Create a SensorEventAgent
to generate and dispatch
- * sensor events to registered listeners.
- *
- * @param source reference to the originating object for inclusion in
- * generated SensorEvents
; intended to refer to the
- * instantiating Behavior but may be any reference, or null
- */
- public SensorEventAgent(Object source) {
- this.source = source ;
- }
-
- /**
- * This class contains all the button and read listeners registered
- * with a sensor.
- */
- private static class SensorBinding {
- Sensor sensor = null ;
- int[] buttons = null ;
- Transform3D read = null ;
-
- // List of SensorButtonBinding objects and corresponding array.
- List buttonBindingsList = new ArrayList() ;
- SensorButtonBinding[] buttonBindings = new SensorButtonBinding[0] ;
-
- // List of SensorReadListener objects and corresponding array.
- List readBindingsList = new ArrayList() ;
- SensorReadListener[] readBindings = new SensorReadListener[0] ;
-
- SensorBinding(Sensor sensor) {
- this.sensor = sensor ;
- buttons = new int[sensor.getSensorButtonCount()] ;
- read = new Transform3D() ;
- }
-
- void updateArrays() {
- buttonBindings =
- (SensorButtonBinding[])buttonBindingsList.toArray
- (new SensorButtonBinding[buttonBindingsList.size()]) ;
- readBindings =
- (SensorReadListener[])readBindingsList.toArray
- (new SensorReadListener[readBindingsList.size()]) ;
- }
-
- @Override
- public String toString() {
- String s = new String() ;
- s = "sensor " + sensor + "\nbutton listener arrays:\n" ;
- for (int i = 0 ; i < buttonBindingsList.size() ; i++)
- s = s + ((SensorButtonBinding)buttonBindingsList.get(i)) ;
- s = s + "read listeners:\n" ;
- for (int i = 0 ; i < readBindingsList.size() ; i++)
- s = s + " " +
- ((SensorReadListener)readBindingsList.get(i)) + "\n" ;
- return s ;
- }
- }
-
- /**
- * This class contains an array of SensorButtonListener
- * implementations, one for each sensor button. This array is used to
- * support a mutual exclusion callback policy. There may be multiple
- * instances of this class associated with a single sensor.
- */
- private static class SensorButtonBinding {
- int buttonsHandled = 0 ;
- boolean[] prevButtons = null ;
- boolean multiButton = false ;
- SensorButtonListener[] listeners = null ;
-
- SensorButtonBinding(SensorButtonListener[] listeners,
- boolean multiButtonEnable) {
-
- prevButtons = new boolean[listeners.length] ;
- this.listeners = new SensorButtonListener[listeners.length] ;
-
- for (int i = 0 ; i < listeners.length ; i++) {
- prevButtons[i] = false ;
- this.listeners[i] = listeners[i] ;
- }
-
- this.multiButton = multiButtonEnable ;
- }
-
- @Override
- public String toString() {
- String s = new String() ;
- s = " length " + listeners.length +
- ", mutual exclusion " + (!multiButton) + "\n" ;
- for (int i = 0 ; i < listeners.length ; i++)
- s = s + " " +
- (listeners[i] == null?
- "null" : listeners[i].toString()) + "\n" ;
- return s ;
- }
- }
-
- /**
- * Look up the sensor listeners bound to the given sensor.
- */
- private SensorBinding getSensorBinding(Sensor sensor) {
- for (int i = 0 ; i < bindingsList.size() ; i++) {
- SensorBinding sb = (SensorBinding)bindingsList.get(i) ;
- if (sb.sensor == sensor)
- return sb ;
- }
- return null ;
- }
-
- /**
- * Creates a binding of the specified sensor button to the given
- * SensorButtonListener
implementation.
- *
- * @param sensor the sensor with the button to be bound
- * @param button the index of the button to be bound on the specified
- * sensor; may range from 0 to
- * (sensor.getSensorButtonCount() - 1)
- * @param buttonListener the SensorButtonListener
- * implementation that will be invoked for the sensor's button
- */
- public synchronized void addSensorButtonListener
- (Sensor sensor, int button, SensorButtonListener buttonListener) {
-
- if (sensor == null)
- throw new NullPointerException("\nsensor is null") ;
-
- if (button >= sensor.getSensorButtonCount())
- throw new ArrayIndexOutOfBoundsException
- ("\nbutton " + button + " >= sensor button count " +
- sensor.getSensorButtonCount()) ;
-
- SensorBinding sb = getSensorBinding(sensor) ;
- if (sb == null) {
- sb = new SensorBinding(sensor) ;
- bindingsList.add(sb) ;
- }
-
- SensorButtonListener[] listeners =
- new SensorButtonListener[sb.buttons.length] ;
-
- // Assign only the specified button; others remain null.
- listeners[button] = buttonListener ;
- SensorButtonBinding sbb =
- new SensorButtonBinding(listeners, true) ;
-
- sb.buttonBindingsList.add(sbb) ;
- listsDirty = true ;
- }
-
- /**
- * Creates a binding from all the buttons on the specified sensor to
- * the given SensorButtonListener
implementation. If
- * multiple sensor buttons are held down at the same time, the press
- * and release callbacks are called for each button in the order that
- * they occur. This allows actions to be bound to combinations of
- * button presses, but is also convenient for listeners that don't
- * care which button was pressed.
- *
- * @param sensor the sensor to be bound
- * @param buttonListener the SensorButtonListener
- * implementation that will be called for all button events
- */
- public synchronized void addSensorButtonListener
- (Sensor sensor, SensorButtonListener buttonListener) {
-
- if (sensor == null)
- throw new NullPointerException("\nsensor is null") ;
-
- SensorBinding sb = getSensorBinding(sensor) ;
- if (sb == null) {
- sb = new SensorBinding(sensor) ;
- bindingsList.add(sb) ;
- }
-
- SensorButtonListener[] listeners =
- new SensorButtonListener[sb.buttons.length] ;
-
- // All buttons are bound to the same listener.
- for (int i = 0 ; i < sb.buttons.length ; i++)
- listeners[i] = buttonListener ;
-
- SensorButtonBinding sbb =
- new SensorButtonBinding(listeners, true) ;
-
- sb.buttonBindingsList.add(sbb) ;
- listsDirty = true ;
- }
-
- /**
- * Creates a binding of the specified sensor to the given array of
- * SensorButtonListener
implementations. The array index
- * of the listener indicates the index of the sensor button to which
- * it will be bound.
- *
- * This method enforces a mutually exclusive callback policy
- * among the listeners specified in the array. If multiple sensor
- * buttons are held down at the same time, callbacks are invoked only
- * for the button that was depressed first.
- *
- * @param sensor the sensor to be bound
- * @param buttonListeners array of implementations of
- * SensorButtonListener
; array entries may be null or
- * duplicates but the array length must equal the sensor's button
- * count
- */
- public synchronized void addSensorButtonListeners
- (Sensor sensor, SensorButtonListener[] buttonListeners) {
-
- if (sensor == null)
- throw new NullPointerException("\nsensor is null") ;
-
- SensorBinding sb = getSensorBinding(sensor) ;
- if (sb == null) {
- sb = new SensorBinding(sensor) ;
- bindingsList.add(sb) ;
- }
-
- if (sb.buttons.length != buttonListeners.length)
- throw new IllegalArgumentException
- ("\nbuttonListeners length " + buttonListeners.length +
- " must equal sensor button count " + sb.buttons.length) ;
-
- SensorButtonBinding sbb =
- new SensorButtonBinding(buttonListeners, false) ;
-
- sb.buttonBindingsList.add(sbb) ;
- listsDirty = true ;
- }
-
- /**
- * Gets the SensorButtonListener
implementations bound to
- * the given sensor and button.
- *
- * @param sensor the sensor of interest
- * @param button the button of interest
- * @return array of SensorButtonListener
implementations
- * bound to the given sensor and button, or null
- */
- public SensorButtonListener[] getSensorButtonListeners(Sensor sensor,
- int button) {
- if (sensor == null)
- throw new NullPointerException("\nsensor is null") ;
-
- if (button >= sensor.getSensorButtonCount())
- throw new ArrayIndexOutOfBoundsException
- ("\nbutton " + button + " >= sensor button count " +
- sensor.getSensorButtonCount()) ;
-
- SensorBinding sb = getSensorBinding(sensor) ;
- if (sb == null)
- return null ;
-
- ArrayList listeners = new ArrayList() ;
- for (int i = 0 ; i < sb.buttonBindingsList.size() ; i++) {
- SensorButtonBinding sbb =
- (SensorButtonBinding)sb.buttonBindingsList.get(i) ;
-
- if (sbb.listeners[button] != null)
- listeners.add(sbb.listeners[button]) ;
- }
-
- if (listeners.size() == 0)
- return null ;
- else
- return (SensorButtonListener[])listeners.toArray
- (new SensorButtonListener[listeners.size()]) ;
- }
-
- /**
- * Remove the SensorButtonListener from the given SensorBinding.
- */
- private void removeSensorButtonListener
- (SensorBinding sb, SensorButtonListener listener) {
-
- Iterator i = sb.buttonBindingsList.iterator() ;
- while (i.hasNext()) {
- int instanceCount = 0 ;
- SensorButtonBinding sbb = (SensorButtonBinding)i.next() ;
-
- for (int j = 0 ; j < sbb.listeners.length ; j++) {
- if (sbb.listeners[j] == listener)
- sbb.listeners[j] = null ;
- else if (sbb.listeners[j] != null)
- instanceCount++ ;
- }
- if (instanceCount == 0) {
- i.remove() ;
- }
- }
- listsDirty = true ;
- }
-
- /**
- * Remove the given SensorButtonListener
binding from the
- * specified sensor.
- *
- * @param sensor the sensor from which to remove the listener
- * @param listener the listener to be removed
- */
- public synchronized void removeSensorButtonListener
- (Sensor sensor, SensorButtonListener listener) {
-
- if (sensor == null)
- throw new NullPointerException("\nsensor is null") ;
-
- SensorBinding sb = getSensorBinding(sensor) ;
- if (sb == null)
- return ;
-
- removeSensorButtonListener(sb, listener) ;
- if (sb.buttonBindingsList.size() == 0 &&
- sb.readBindingsList.size() == 0)
- removeSensorBinding(sensor) ;
-
- listsDirty = true ;
- }
-
- /**
- * Remove the given SensorButtonListener
from all sensors.
- *
- * @param listener the listener to remove
- */
- public synchronized void removeSensorButtonListener
- (SensorButtonListener listener) {
-
- Iterator i = bindingsList.iterator() ;
- while (i.hasNext()) {
- SensorBinding sb = (SensorBinding)i.next() ;
- removeSensorButtonListener(sb, listener) ;
-
- if (sb.buttonBindingsList.size() == 0 &&
- sb.readBindingsList.size() == 0) {
- i.remove() ;
- }
- }
- listsDirty = true ;
- }
-
- /**
- * Creates a binding of the specified sensor to the given
- * SensorReadListener
. The read listener is invoked
- * every time dispatchEvents
is called and a button
- * listener is not invoked.
- *
- * @param sensor the sensor to be bound
- * @param readListener the SensorReadListener
- * implementation
- */
- public synchronized void addSensorReadListener
- (Sensor sensor, SensorReadListener readListener) {
-
- if (sensor == null)
- throw new NullPointerException("\nsensor is null") ;
-
- SensorBinding sb = getSensorBinding(sensor) ;
- if (sb == null) {
- sb = new SensorBinding(sensor) ;
- bindingsList.add(sb) ;
- }
- sb.readBindingsList.add(readListener) ;
- listsDirty = true ;
- }
-
- /**
- * Gets the SensorReadListeners
bound to the specified
- * sensor.
- *
- * @param sensor the sensor of interest
- * @return array of SensorReadListeners
bound to the
- * given sensor, or null
- */
- public SensorReadListener[] getSensorReadListeners(Sensor sensor) {
- if (sensor == null)
- throw new NullPointerException("\nsensor is null") ;
-
- SensorBinding sb = getSensorBinding(sensor) ;
- if (sb == null)
- return null ;
- else if (sb.readBindingsList.size() == 0)
- return null ;
- else
- return (SensorReadListener[])sb.readBindingsList.toArray
- (new SensorReadListener[sb.readBindingsList.size()]) ;
- }
-
- /**
- * Remove the SensorReadListener from the given SensorBinding.
- */
- private void removeSensorReadListener
- (SensorBinding sb, SensorReadListener listener) {
-
- Iterator i = sb.readBindingsList.iterator() ;
- while (i.hasNext()) {
- if (((SensorReadListener)i.next()) == listener)
- i.remove() ;
- }
- listsDirty = true ;
- }
-
- /**
- * Remove the given SensorReadListener
binding from the
- * specified sensor.
- *
- * @param sensor the sensor from which to remove the listener
- * @param listener the listener to be removed
- */
- public synchronized void removeSensorReadListener
- (Sensor sensor, SensorReadListener listener) {
-
- if (sensor == null)
- throw new NullPointerException("\nsensor is null") ;
-
- SensorBinding sb = getSensorBinding(sensor) ;
- if (sb == null)
- return ;
-
- removeSensorReadListener(sb, listener) ;
- if (sb.buttonBindingsList.size() == 0 &&
- sb.readBindingsList.size() == 0)
- removeSensorBinding(sensor) ;
-
- listsDirty = true ;
- }
-
- /**
- * Remove the given SensorReadListener
from all sensors.
- *
- * @param listener the listener to remove
- */
- public synchronized void removeSensorReadListener
- (SensorReadListener listener) {
-
- Iterator i = bindingsList.iterator() ;
- while (i.hasNext()) {
- SensorBinding sb = (SensorBinding)i.next() ;
- removeSensorReadListener(sb, listener) ;
-
- if (sb.buttonBindingsList.size() == 0 &&
- sb.readBindingsList.size() == 0) {
- i.remove() ;
- }
- }
- listsDirty = true ;
- }
-
- /**
- * Remove all sensor listeners bound to the given sensor.
- */
- public synchronized void removeSensorBinding(Sensor sensor) {
- Iterator i = bindingsList.iterator() ;
- while (i.hasNext()) {
- SensorBinding sb = (SensorBinding)i.next() ;
- if (sb.sensor == sensor) {
- i.remove() ;
- break ;
- }
- }
- listsDirty = true ;
- }
-
- /**
- * Returns an array of references to all sensors that have been bound
- * to listeners.
- * @return an array of sensors, or null if no sensors have been bound
- */
- public Sensor[] getSensors() {
- if (bindingsList.size() == 0)
- return null ;
-
- Sensor[] s = new Sensor[bindingsList.size()] ;
- for (int i = 0 ; i < bindingsList.size() ; i++)
- s[i] = ((SensorBinding)bindingsList.get(i)).sensor ;
-
- return s ;
- }
-
- /**
- * Copies binding lists to arrays for event dispatch. This allows
- * listeners to add or remove themselves or other listeners safely.
- */
- private synchronized void updateArrays() {
- bindings = (SensorBinding[])bindingsList.toArray
- (new SensorBinding[bindingsList.size()]) ;
-
- for (int i = 0 ; i < bindings.length ; i++) {
- bindings[i].updateArrays() ;
- }
- }
-
- /**
- * Reads all sensor button state and dispatches events to registered
- * button and read listeners. This method is intended to be called from
- * the processStimulus
implementation of a
- * Behavior
or the pollAndProcessInput
method of
- * an event-driven implementation of InputDevice
.
- */
- public void dispatchEvents() {
- long t1 = t0 ;
- t0 = J3DTimer.getValue() ;
-
- if (listsDirty) {
- updateArrays() ;
- listsDirty = false ;
- }
-
- // Loop through all sensor bindings.
- for (int k = 0 ; k < bindings.length ; k++) {
- SensorBinding sb = bindings[k] ;
- Sensor s = sb.sensor ;
- Transform3D read = sb.read ;
- int[] buttons = sb.buttons ;
- int dragButton = 0 ;
- boolean callReadListeners = true ;
- boolean callDraggedListener = false ;
-
- // Get this sensor's readings.
- s.getRead(read) ;
- s.lastButtons(buttons) ;
-
- // Dispatch button listeners.
- for (int j = 0 ; j < sb.buttonBindings.length ; j++) {
- SensorButtonBinding sbb = sb.buttonBindings[j] ;
- for (int i = 0 ; i < buttons.length ; i++) {
- if (sbb.listeners[i] == null)
- continue ;
-
- // Check for button release.
- if (sbb.prevButtons[i]) {
- if (buttons[i] == 0) {
- e.set(source, SensorEvent.RELEASED, s, read,
- buttons, i, t0, t1) ;
- sbb.listeners[i].released(e) ;
- sbb.prevButtons[i] = false ;
- sbb.buttonsHandled-- ;
- }
- else {
- callDraggedListener = true ;
- dragButton = i ;
- }
- callReadListeners = false ;
- }
- // Check for button press.
- // Ignore multiple button presses if not enabled;
- // otherwise, one listener is bound to all buttons.
- else if (buttons[i] == 1) {
- if (sbb.buttonsHandled == 0 || sbb.multiButton) {
- e.set(source, SensorEvent.PRESSED, s, read,
- buttons, i, t0, t1) ;
- sbb.listeners[i].pressed(e) ;
- sbb.prevButtons[i] = true ;
- sbb.buttonsHandled++ ;
- callReadListeners = false ;
- }
- }
- }
- if (callDraggedListener) {
- // One drag event even if multiple buttons down.
- // Called after all pressed() and released() calls.
- e.set(source, SensorEvent.DRAGGED, s, read, buttons,
- SensorEvent.NOBUTTON, t0, t1) ;
- sbb.listeners[dragButton].dragged(e) ;
- }
- }
- // Dispatch read listeners.
- if (callReadListeners) {
- e.set(source, SensorEvent.READ, s, read,
- buttons, SensorEvent.NOBUTTON, t0, t1) ;
- for (int r = 0 ; r < sb.readBindings.length ; r++) {
- sb.readBindings[r].read(e) ;
- }
- }
- }
- }
-
- @Override
- public String toString() {
- String s = "SensorEventAgent@" + Integer.toHexString(hashCode()) ;
- s += "\nsensor bindings:\n\n" ;
- for (int i = 0 ; i < bindingsList.size() ; i++) {
- s += ((SensorBinding)bindingsList.get(i)).toString() + "\n" ;
- }
- return s ;
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorGnomonEcho.java b/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorGnomonEcho.java
deleted file mode 100644
index 90ba7cf..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorGnomonEcho.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.sensor ;
-
-import javax.media.j3d.Appearance;
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.Material;
-import javax.media.j3d.Shape3D;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransparencyAttributes;
-import javax.media.j3d.TriangleArray;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3f;
-
-/**
- * A Shape3D representing a gnomon pointing along each coordinate
- * axis. The base of the gnomon is a cube, and the coordinate axes are
- * represented by pyramids attached to each face of the cube.
- *
- * @since Java 3D 1.3
- */
-public class SensorGnomonEcho extends Shape3D {
- /**
- * Constructs a SensorGnomonEcho. Read and write capabilities are
- * granted for the Appearance, Material, TransparencyAttributes,
- * and TransparencyAttributes mode and value.
- *
- * @param transform translation and/or rotation to apply to the gnomon
- * geometry; this should be the position and orientation of the sensor
- * hotspot in the sensor's local coordinate system
- * @param baseWidth width of each edge of the base cube in meters
- * @param axisLength distance in meters from the gnomon center to
- * the apex of the pyramid attached to each face of the base cube
- * @param enableLighting boolean indicating whether normals should be
- * generated and lighting enabled
- */
- public SensorGnomonEcho(Transform3D transform,
- double baseWidth,
- double axisLength,
- boolean enableLighting) {
- super() ;
-
- int FRONT = 0 ;
- int BACK = 1 ;
- int LEFT = 2 ;
- int RIGHT = 3 ;
- int TOP = 4 ;
- int BOTTOM = 5 ;
- Point3f[] axes = new Point3f[6] ;
- float length = (float)axisLength ;
-
- axes[FRONT] = new Point3f(0f, 0f, length) ;
- axes[BACK] = new Point3f(0f, 0f, -length) ;
- axes[LEFT] = new Point3f(-length, 0f, 0f) ;
- axes[RIGHT] = new Point3f( length, 0f, 0f) ;
- axes[TOP] = new Point3f(0f, length, 0f) ;
- axes[BOTTOM] = new Point3f(0f, -length, 0f) ;
-
- if (transform != null)
- for (int i = FRONT ; i <= BOTTOM ; i++)
- transform.transform(axes[i]) ;
-
- float offset = (float)baseWidth / 2.0f ;
- Point3f[][] cube = new Point3f[6][4] ;
-
- cube[FRONT][0] = new Point3f(-offset, -offset, offset) ;
- cube[FRONT][1] = new Point3f( offset, -offset, offset) ;
- cube[FRONT][2] = new Point3f( offset, offset, offset) ;
- cube[FRONT][3] = new Point3f(-offset, offset, offset) ;
-
- cube[BACK][0] = new Point3f( offset, -offset, -offset) ;
- cube[BACK][1] = new Point3f(-offset, -offset, -offset) ;
- cube[BACK][2] = new Point3f(-offset, offset, -offset) ;
- cube[BACK][3] = new Point3f( offset, offset, -offset) ;
-
- if (transform != null)
- for (int i = FRONT ; i <= BACK ; i++)
- for (int j = 0 ; j < 4 ; j++)
- transform.transform(cube[i][j]) ;
-
- cube[LEFT][0] = cube[BACK][1] ;
- cube[LEFT][1] = cube[FRONT][0] ;
- cube[LEFT][2] = cube[FRONT][3] ;
- cube[LEFT][3] = cube[BACK][2] ;
-
- cube[RIGHT][0] = cube[FRONT][1] ;
- cube[RIGHT][1] = cube[BACK][0] ;
- cube[RIGHT][2] = cube[BACK][3] ;
- cube[RIGHT][3] = cube[FRONT][2] ;
-
- cube[TOP][0] = cube[FRONT][3] ;
- cube[TOP][1] = cube[FRONT][2] ;
- cube[TOP][2] = cube[BACK][3] ;
- cube[TOP][3] = cube[BACK][2] ;
-
- cube[BOTTOM][0] = cube[BACK][1] ;
- cube[BOTTOM][1] = cube[BACK][0] ;
- cube[BOTTOM][2] = cube[FRONT][1] ;
- cube[BOTTOM][3] = cube[FRONT][0] ;
-
- int v = 0 ;
- Point3f[] vertices = new Point3f[72] ;
-
- for (int i = 0 ; i < 6 ; i++) {
- vertices[v++] = cube[i][0] ;
- vertices[v++] = cube[i][1] ;
- vertices[v++] = axes[i] ;
- vertices[v++] = cube[i][1] ;
- vertices[v++] = cube[i][2] ;
- vertices[v++] = axes[i] ;
- vertices[v++] = cube[i][2] ;
- vertices[v++] = cube[i][3] ;
- vertices[v++] = axes[i] ;
- vertices[v++] = cube[i][3] ;
- vertices[v++] = cube[i][0] ;
- vertices[v++] = axes[i] ;
- }
-
- int vertexFormat ;
- Material m = new Material() ;
- m.setCapability(Material.ALLOW_COMPONENT_READ) ;
- m.setCapability(Material.ALLOW_COMPONENT_WRITE) ;
-
- if (enableLighting) {
- vertexFormat =
- GeometryArray.COORDINATES | GeometryArray.NORMALS ;
- m.setLightingEnable(true) ;
- }
- else {
- vertexFormat = GeometryArray.COORDINATES ;
- m.setLightingEnable(false) ;
- }
-
- TriangleArray ta = new TriangleArray(72, vertexFormat) ;
- ta.setCoordinates(0, vertices) ;
-
- if (enableLighting) {
- Vector3f v0 = new Vector3f() ;
- Vector3f v1 = new Vector3f() ;
- Vector3f[] normals = new Vector3f[72] ;
-
- for (int i = 0 ; i < 72 ; i += 3) {
- v0.sub(vertices[i+1], vertices[i]) ;
- v1.sub(vertices[i+2], vertices[i]) ;
-
- Vector3f n = new Vector3f() ;
- n.cross(v0, v1) ;
- n.normalize() ;
-
- normals[i] = n ;
- normals[i+1] = n ;
- normals[i+2] = n ;
- }
- ta.setNormals(0, normals) ;
- }
-
- Appearance a = new Appearance() ;
- a.setMaterial(m) ;
- a.setCapability(Appearance.ALLOW_MATERIAL_READ) ;
- a.setCapability(Appearance.ALLOW_MATERIAL_WRITE) ;
-
- TransparencyAttributes tra = new TransparencyAttributes() ;
- tra.setCapability(TransparencyAttributes.ALLOW_MODE_READ) ;
- tra.setCapability(TransparencyAttributes.ALLOW_MODE_WRITE) ;
- tra.setCapability(TransparencyAttributes.ALLOW_VALUE_READ) ;
- tra.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE) ;
- ta.setCapability
- (TransparencyAttributes.ALLOW_BLEND_FUNCTION_READ) ;
- ta.setCapability
- (TransparencyAttributes.ALLOW_BLEND_FUNCTION_WRITE) ;
-
- a.setTransparencyAttributes(tra) ;
- a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_READ) ;
- a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE) ;
-
- setGeometry(ta) ;
- setAppearance(a) ;
-
- setCapability(ALLOW_APPEARANCE_READ) ;
- setCapability(ALLOW_APPEARANCE_WRITE) ;
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorInputAdaptor.java b/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorInputAdaptor.java
deleted file mode 100644
index cee6c02..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorInputAdaptor.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.sensor ;
-
-/**
- * The adaptor which receives sensor button and read events. The methods
- * in this class are empty; the ones of interest should be overridden by
- * classes extending this adaptor.
- *
- * @since Java 3D 1.3
- */
-public class SensorInputAdaptor
- implements SensorButtonListener, SensorReadListener {
-
- @Override
- public void pressed(SensorEvent e) {
- }
-
- @Override
- public void released(SensorEvent e) {
- }
-
- @Override
- public void dragged(SensorEvent e) {
- }
-
- @Override
- public void clicked(SensorEvent e) {
- }
-
- @Override
- public void read(SensorEvent e) {
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorReadListener.java b/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorReadListener.java
deleted file mode 100644
index f2f440c..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/SensorReadListener.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.sensor ;
-
-/**
- * This defines the interface for handling a sensor's read events in
- * conjuction with a SensorEventAgent
instance.
- *
- * The events passed to this listener's methods are ephemeral; they
- * are only valid until the listener has returned. If a listener needs to
- * retain the event it must be copied using the
- * SensorEvent(SensorEvent)
constructor.
- *
- * @see SensorEvent
- * @see SensorEventAgent
- * @see SensorButtonListener
- * @since Java 3D 1.3
- */
-public interface SensorReadListener {
- /**
- * This method is called each time the dispatchEvents
- * method of SensorEventAgent
is called and none of a
- * sensor's buttons have been handled by a button listener. The
- * sensor read value has not necessarily changed since the last read
- * event.
- *
- * @param e the sensor event
- */
- public void read(SensorEvent e) ;
-}
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/package.html b/src/classes/share/com/sun/j3d/utils/behaviors/sensor/package.html
deleted file mode 100644
index 25c9b13..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/sensor/package.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
Provides 6DOF sensor behavior classes.
- - diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/vp/OrbitBehavior.java b/src/classes/share/com/sun/j3d/utils/behaviors/vp/OrbitBehavior.java deleted file mode 100644 index b046096..0000000 --- a/src/classes/share/com/sun/j3d/utils/behaviors/vp/OrbitBehavior.java +++ /dev/null @@ -1,1074 +0,0 @@ -/* - * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any - * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY - * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL - * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF - * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS - * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR - * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, - * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND - * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR - * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed, licensed or - * intended for use in the design, construction, operation or - * maintenance of any nuclear facility. - * - */ - -package com.sun.j3d.utils.behaviors.vp; - -import java.awt.AWTEvent; -import java.awt.event.MouseEvent; - -import javax.media.j3d.Canvas3D; -import javax.media.j3d.Transform3D; -import javax.vecmath.Matrix3d; -import javax.vecmath.Point3d; -import javax.vecmath.Vector3d; - -import com.sun.j3d.internal.J3dUtilsI18N; -import com.sun.j3d.utils.universe.ViewingPlatform; - -/** - * Moves the View around a point of interest when the mouse is dragged with - * a mouse button pressed. Includes rotation, zoom, and translation - * actions. Zooming can also be obtained by using mouse wheel. - *
- * This behavior must be added to the ViewingPlatform
- * using the ViewingPlatform.setViewPlatformBehavior
method.
- *
- * The rotate action rotates the ViewPlatform around the point of interest - * when the mouse is moved with the main mouse button pressed. The - * rotation is in the direction of the mouse movement, with a default - * rotation of 0.01 radians for each pixel of mouse movement. - *
- * The zoom action moves the ViewPlatform closer to or further from the - * point of interest when the mouse is moved with the middle mouse button - * pressed (or Alt-main mouse button on systems without a middle mouse button). - * The default zoom action is to translate the ViewPlatform 0.01 units for each - * pixel of mouse movement. Moving the mouse up moves the ViewPlatform closer, - * moving the mouse down moves the ViewPlatform further away. - *
- * By default, the zoom action allows the ViewPlatform to move through
- * the center of rotation to orbit at a negative radius.
- * The STOP_ZOOM
constructor flag will stop the ViewPlatform at
- * a minimum radius from the center. The default minimum radius is 0.0
- * and can be set using the setMinRadius
method.
- *
- * The PROPORTIONAL_ZOOM
constructor flag changes the zoom action
- * to move the ViewPlatform proportional to its distance from the center
- * of rotation. For this mode, the default action is to move the ViewPlatform
- * by 1% of its distance from the center of rotation for each pixel of
- * mouse movement.
- *
- * The translate action translates the ViewPlatform when the mouse is moved - * with the right mouse button pressed (Shift-main mouse button on systems - * without a right mouse button). The translation is in the direction of the - * mouse movement, with a default translation of 0.01 units for each pixel - * of mouse movement. - *
- * The sensitivity of the actions can be scaled using the
- * set
ActionFactor()
methods which scale
- * the default movement by the factor. The rotate and translate actions
- * have separate factors for x and y.
- *
- * The actions can be reversed using the REVERSE_
ACTION
- * constructor flags. The default action moves the ViewPlatform around the
- * objects in the scene. The REVERSE_
ACTION flags can
- * make the objects in the scene appear to be moving in the direction
- * of the mouse movement.
- *
- * The actions can be disabled by either using the
- * DISABLE_
ACTION constructor flags or the
- * set
ActionEnable
methods.
- *
- * The default center of rotation is (0, 0, 0) and can be set using the
- *
- *
- * NOTE: Applications should not call this method.
- *
- * @param vp the target ViewingPlatform for this behavior
- */
- public void setViewingPlatform(ViewingPlatform vp) {
- this.vp = vp;
-
- if (vp!=null)
- targetTG = vp.getViewPlatformTransform();
- else
- targetTG = null;
- }
-
- /**
- * Returns the ViewingPlatform for this behavior
- * @return the ViewingPlatform for this behavior
- */
- public ViewingPlatform getViewingPlatform() {
- return vp;
- }
-
- /**
- * Copies the given Transform3D into the "home" transform, used to
- * position and reorient the ViewingPlatform to a known point of interest.
- *
- * @param home source transform to be copied
- * @since Java 3D 1.3
- */
- public void setHomeTransform(Transform3D home) {
- if (homeTransform == null)
- homeTransform = new Transform3D(home);
- else
- homeTransform.set(home);
- }
-
- /**
- * Returns the behaviors "home" transform.
- *
- * @param home transform to be returned
- * @since Java 3D 1.3
- */
- public void getHomeTransform(Transform3D home ) {
- home.set( homeTransform );
- }
-
- /**
- * Positions and reorients the ViewingPlatform to its "home" transform.
- * @since Java 3D 1.3
- */
- public void goHome() {
- if (targetTG != null && homeTransform != null)
- targetTG.setTransform(homeTransform);
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/vp/WandViewBehavior.java b/src/classes/share/com/sun/j3d/utils/behaviors/vp/WandViewBehavior.java
deleted file mode 100644
index c84ab0c..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/vp/WandViewBehavior.java
+++ /dev/null
@@ -1,3911 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.vp ;
-
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Map;
-
-import javax.media.j3d.Appearance;
-import javax.media.j3d.BadTransformException;
-import javax.media.j3d.BoundingSphere;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Group;
-import javax.media.j3d.Material;
-import javax.media.j3d.Sensor;
-import javax.media.j3d.Shape3D;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-import javax.media.j3d.TransparencyAttributes;
-import javax.media.j3d.View;
-import javax.media.j3d.WakeupCondition;
-import javax.media.j3d.WakeupOnElapsedFrames;
-import javax.vecmath.AxisAngle4d;
-import javax.vecmath.Color3f;
-import javax.vecmath.Matrix3d;
-import javax.vecmath.Matrix4d;
-import javax.vecmath.Point3d;
-import javax.vecmath.Vector3d;
-
-import com.sun.j3d.utils.behaviors.sensor.SensorBeamEcho;
-import com.sun.j3d.utils.behaviors.sensor.SensorButtonListener;
-import com.sun.j3d.utils.behaviors.sensor.SensorEvent;
-import com.sun.j3d.utils.behaviors.sensor.SensorEventAgent;
-import com.sun.j3d.utils.behaviors.sensor.SensorGnomonEcho;
-import com.sun.j3d.utils.behaviors.sensor.SensorInputAdaptor;
-import com.sun.j3d.utils.behaviors.sensor.SensorReadListener;
-import com.sun.j3d.utils.universe.ConfiguredUniverse;
-import com.sun.j3d.utils.universe.SimpleUniverse;
-import com.sun.j3d.utils.universe.Viewer;
-import com.sun.j3d.utils.universe.ViewingPlatform;
-
-/**
- * Manipulates view platform transforms using a motion-tracked wand or mouse
- * equipped with a six degree of freedom (6DOF) sensor. An optional two axis
- * (2D) valuator sensor is also directly supported. Default operation is set
- * up to enable both direct manipulation of the view transform and translation
- * back and forth along the direction the 6DOF sensor is pointing; rotation
- * is handled by the 2D valuator if available. An arbitrary number of sensors
- * and action bindings can be customized by accessing this behavior's
- *
- * This behavior can be instantiated from the configuration file read by
- *
- * {@link #Sensor6D Sensor6D} is the 6DOF sensor to use. This can also be set
- * directly with the appropriate constructor. This sensor must generate 6
- * degree of freedom position and orientation reads relative to the tracker
- * base in physical units. By default this behavior provides an echo for the
- * 6DOF sensor which indicates its position and orientation in the virtual
- * world; the echo attributes can be set by the {@link #EchoType EchoType},
- * {@link #EchoSize EchoSize}, {@link #EchoColor EchoColor}, and {@link
- * #EchoTransparency EchoTransparency} properties. See also the {@link
- * #NominalSensorRotation NominalSensorRotation} property, and the
- *
- * {@link #Sensor2D Sensor2D} is an optional 2D valuator to use in conjunction
- * with the 6DOF sensor. This can be set directly with the appropriate
- * constructor. The valuator should generate X and Y reads ranging from [-1.0
- * .. +1.0], with a nominal (deadzone) value of 0.0. The default
- * configuration expects to find these values along the translation components
- * of the read matrix, at indices 3 and 7, but these indices can be also be
- * specified by the {@link #MatrixIndices2D MatrixIndices2D} property.
- *
- * {@link #ButtonAction6D ButtonAction6D} sets an action for a specific button
- * on a 6DOF sensor. The actions available are:
- *
- * {@link #ReadAction2D ReadAction2D} sets the action bound to 2D valuator
- * reads; that is, non-zero values generated by the device when no buttons
- * have been pressed. If the value is (0.0, 0.0) or below the threshold value
- * set by {@link #Threshold2D Threshold2D}, then this behavior does nothing;
- * otherwise, the following actions can be performed:
- *
- * {@link #ButtonAction2D ButtonAction2D} sets an action for a specific button
- * on the 2D valuator. The available actions are the same as for
- *
- * The view transform may be reset to its home transform by pressing a number
- * of buttons simultaneously on the 6DOF sensor. The minimum number of
- * buttons that must be pressed is set by {@link #ResetViewButtonCount6D
- * ResetViewButtonCount6D}. This value must be greater than one; the default
- * is three. This action may be disabled by setting the property value to
- * None. The corresponding property for the 2D valuator is {@link
- * #ResetViewButtonCount2D ResetViewButtonCount2D}, with a default value of
- * None. Note, however, that the reset view action will be ineffectual if an
- * action which always modifies the view transform is bound to reads on the
- * sensor used to reset the view, since the reset transform will get
- * overwritten by the read action.
- *
- * The special value
- * Syntax:
- * This constructor should only be used if either
- *
- * This constructor should only be used if either
- *
- * If the echo
- * This constructor should only be used if
- * If the echo
- * This is invoked the first time
- * The rotation direction is controlled by the direction the 2D valuator
- * is pushed, and the rotation speed is scaled by the magnitude of the 2D
- * valuator read values.
- *
- * This listener will work in conjunction with a 6DOF sensor if supplied
- * in the constructor. If a 6DOF sensor is provided and
- *
- * The translation direction is controlled by the direction the 2D
- * valuator is pushed, and the speed is the translation speed scaled by
- * the fast speed factor and the magnitude of the 2D valuator reads.
- *
- * This listener will work in conjunction with a 6DOF sensor if supplied
- * in the constructor. If a 6DOF sensor is provided then the translation
- * occurs along the basis vectors of the 6DOF sensor's coordinate system;
- * otherwise, the translation occurs along the view platform's basis
- * vectors.
- *
- * @see #setReadAction2D
- * @see #setButtonAction2D
- * @see #setTranslationSpeed
- * @see #setFastSpeedFactor
- * @see #setThreshold2D
- * @see #setMatrixIndices2D
- */
- public class TranslationListener2D extends ListenerBase {
- private Sensor sensor2D, sensor6D ;
- private double[] m = new double[16] ;
- private Vector3d v3d = new Vector3d() ;
- private Transform3D sensor2DRead = new Transform3D() ;
- private double speedScaled ;
-
- @Override
- protected void initAction(Sensor s) {
- super.initAction(s) ;
- if (s != null && readAction6D == ECHO) {
- // Disable the 6DOF echo. It will be updated in this action.
- eventAgent.removeSensorReadListener(s, echoReadListener6D) ;
- }
- }
-
- @Override
- protected void endAction(Sensor s) {
- super.endAction(s) ;
- if (s != null && readAction6D == ECHO) {
- // Enable the 6DOF sensor echo.
- eventAgent.addSensorReadListener(s, echoReadListener6D) ;
- }
- }
-
- /**
- * Construct an instance of this class using the specified sensors.
- *
- * @param sensor2D 2D valuator sensor for translation
- * @param sensor6D 6DOF sensor for translation direction; may be
- *
- * This listener will work in conjunction with a 6DOF sensor if supplied
- * in the constructor. If
- * This property is set in the configuration file. The first command form
- * assumes that a
- * Syntax:
- * Alternative Syntax:
- * This property is set in the configuration file. The first command form
- * assumes that a
- * Syntax:
- * Alternative Syntax:
- *
- * Specifying a button index that is greater than that available with the
- * 6DOF sensor will result in an
- * This property is set in the configuration file read by
- *
- * Syntax:
- *
- * Specifying a button index that is greater that that available with the
- * 6DOF sensor will result in an
- * This method only configures the button listeners pre-defined by
- * this behavior. For complete control over the button actions, access
- * the
- * The X and Y values from the valuator should have a continuous range
- * from -1.0 to +1.0, although speeds can be scaled to compensate for a
- * different range. The X and Y values are found in the sensor's read
- * matrix at the indices specified by
- * The default property value of
- * A property value of
- * If this property value is to
- * A value of
- * This property is set in the configuration file read by
- *
- * Syntax:
- * The X and Y values from the valuator should have a continuous range
- * from -1.0 to +1.0, although speeds can be scaled to compensate for a
- * different range. The X and Y values are found in the sensor's read
- * matrix at the indices specified by the
- * The default action of
- * A value of
- * If the value is to
- * A value of
- * This method only configures the read listeners pre-defined by
- * this behavior. For complete control over the read actions, access
- * the
- * Specifying a button index that is greater that that available with the
- * 2D valuator will result in an
- * This property is set in the configuration file read by
- *
- * Syntax:
- * Specifying a button index that is greater that that available with the
- * 2D valuator will result in an
- * This method only configures the button listeners pre-defined by
- * this behavior. For complete control over the button actions, access
- * the
- * The default is
- * This property is set in the configuration file read by
- *
- * Syntax:
- * The default is
- * This method only configures the read listeners pre-defined by
- * this behavior. For complete control over the read actions, access
- * the
- * Syntax:
- *
- * Syntax:
- * Syntax:
- * Syntax:
- * Syntax:
- * Syntax:
- * Syntax:
- * This property is set in the configuration file read by
- *
- * Syntax:
- * The scaling applied with each frame is
- * This property is set in the configuration file read by
- *
- * Syntax:
- * The scaling applied with each frame is
- * Syntax:
- * The transform center source can be dynamically updated while the
- * behavior is running.
- *
- * @param source either
- * Syntax:
- * The transform center can be dynamically updated while the behavior is
- * running.
- *
- * @param center point in virtual world coordinates about which to rotate
- * and scale
- */
- public void setTransformCenter(Point3d center) {
- this.transformCenter.set(center) ;
- }
-
- /**
- * Gets the rotation/scale center in virtual world coordinates.
- * @param center
- * This behavior assumes that when a hand-held wand is pointed directly at
- * a screen in an upright position, then its 6DOF sensor's local
- * coordinate system axes (its basis vectors) are nominally aligned with
- * the image plate basis vectors; specifically, that the sensor's -Z axis
- * points toward the screen, the +Y axis points up, and the +X axis points
- * to the right. The translation and rotation listeners provided by this
- * behavior assume this orientation to determine the transforms to be
- * applied to the view platform; for example, translation applies along
- * the sensor Z axis, while rotation applies about axes defined in the
- * sensor XY plane.
- *
- * This nominal alignment may not hold true depending upon how the sensor
- * is mounted and how the specific
- * NOTE: the nominal sensor transform applies only to the
- * translation directions and rotation axes created by the listeners
- * defined in this behavior; for compatibility with the core Java 3D API,
- * sensor reads and the sensor hotspot location are still expressed in the
- * sensor's local coordinate system.
- *
- * This property is set in the configuration file read by
- *
- * Syntax:
- * This behavior assumes that when a hand-held wand is pointed directly at
- * a screen in an upright position, then its 6DOF sensor's local
- * coordinate system axes (its basis vectors) are nominally aligned with
- * the image plate basis vectors; specifically, that the sensor's -Z axis
- * points toward the screen, the +Y axis points up, and the +X axis points
- * to the right. The translation and rotation listeners provided by this
- * behavior assume this orientation to determine the transforms to be
- * applied to the view platform, in that translation applies along the
- * sensor Z axis, and rotation applies about axes defined in the sensor XY
- * plane.
- *
- * This nominal alignment may not hold true depending upon how the sensor
- * is mounted and how the specific
- * NOTE: the nominal sensor transform applies only to the
- * translation directions and rotation axes created by the listeners
- * defined in this behavior; for compatibility with the core Java 3D API,
- * sensor reads and the sensor hotspot location are still expressed in the
- * sensor's local coordinate system.
- *
- * @param transform Rotates vectors from the nominal sensor coordinate
- * system system to the sensor's local coordinate system; only the
- * rotational components are used. May be set
- * Syntax:
- * Syntax:
- * Syntax:
- * Syntax:
- * Syntax:
- * Syntax:
- * This method must be called before the behavior is made live in order to
- * have an effect.
- *
- * @param echo the Provides ViewPlatform navigation utility classes.
- *
- * A compression command includes an 8-bit header and can range up to 72
- * bits in length. The command with the maximum length is a 2-bit color
- * command with a 6-bit tag in the header, followed by four 16-bit color
- * components of data.
- *
- * A subcommand is either a position, normal, or color, though in practice
- * a position subcommand can only be part of a vertex command. Normal and
- * color subcommands can be parts of separate global normal and color
- * commands as well as parts of a vertex command.
- *
- * A subcommand includes a 6-bit header. Its length is 2 bits less than
- * the length of the corresponding command.
- *
- * @param header contains compression command header bits, right-justified
- * within the bits of the int
- * @param headerLength number of bits in header, either 8 for commands or
- * 6 for subcommands
- * @param body contains the body of the compression command,
- * right-justified within the bits of the long
- * @param bodyLength number of bits in the body
- */
- void addCommand(int header, int headerLength, long body, int bodyLength) {
- addByte(header, headerLength) ;
- addLong(lastBody, lastBodyLength) ;
-
- lastBody = body ;
- lastBodyLength = bodyLength ;
- }
-
- //
- // Add the rightmost bitCount bits of b to the end of the command stream.
- //
- private void addByte(int b, int bitCount) {
- int bitsEmpty = 8 - bitOffset ;
- b &= (int)CompressionStreamElement.lengthMask[bitCount] ;
-
- if (bitCount <= bitsEmpty) {
- bytes[byteOffset] |= (b << (bitsEmpty - bitCount)) ;
- bitOffset += bitCount ;
- return ;
- }
-
- if (bytes.length == byteOffset + 1) {
- byte newBytes[] = new byte[bytes.length * 2] ;
- System.arraycopy(bytes, 0, newBytes, 0, bytes.length) ;
- bytes = newBytes ;
- }
-
- bitOffset = bitCount - bitsEmpty ;
- bytes[byteOffset] |= (b >>> bitOffset) ;
-
- byteOffset++ ;
- bytes[byteOffset] = (byte)(b << (8 - bitOffset)) ;
- }
-
- //
- // Add the rightmost bitCount bits of l to the end of the command stream.
- //
- private void addLong(long l, int bitCount) {
- int byteCount = bitCount / 8 ;
- int excessBits = bitCount - byteCount * 8 ;
-
- if (excessBits > 0)
- addByte((int)(l >>> (byteCount * 8)), excessBits) ;
-
- while (byteCount > 0) {
- addByte((int)((l >>> ((byteCount - 1) * 8)) & 0xff), 8) ;
- byteCount-- ;
- }
- }
-
- /**
- * Add a no-op and the last command body. Pad out with additional no-ops
- * to a 64-bit boundary if necessary. A call to this method is required
- * in order to create a valid compression command stream.
- */
- void end() {
- int excessBytes, padBits ;
-
- // Add the 1st no-op and the last body.
- addByte(V_NO_OP, 8) ;
- addLong(lastBody, lastBodyLength) ;
-
- excessBytes = (byteOffset + 1) % 8 ;
- if (excessBytes == 0 && bitOffset == 8)
- // No padding necessary.
- return ;
-
- // Need to add padding with a 2nd no-op.
- addByte(V_NO_OP, 8) ;
- excessBytes = (byteOffset + 1) % 8 ;
-
- if (excessBytes == 0)
- padBits = 8 - bitOffset ;
- else {
- int fillBytes = 8 - excessBytes ;
- padBits = (8 * fillBytes) + (8 - bitOffset) ;
- }
-
- // The minimum length for a no-op command body is 5 bits.
- if (padBits < 5)
- // Have to cross the next 64-bit boundary.
- padBits += 64 ;
-
- // The maximum length of a no-op body is a 5-bit length + 31 bits of
- // fill for a total of 36.
- if (padBits < 37) {
- // Pad with the body of the 1st no-op.
- addLong((padBits - 5) << (padBits - 5), padBits) ;
- return ;
- }
-
- // The number of bits to pad at this point is [37..68]. Knock off 24
- // bits with the body of the 1st no-op to reduce the number of pad
- // bits to [13..44], which can be filled with 1 more no-op.
- addLong(19 << 19, 24) ;
- padBits -= 24 ;
-
- // Add a 3rd no-op.
- addByte(V_NO_OP, 8) ;
- padBits -= 8 ;
-
- // Complete padding with the body of the 2nd no-op.
- addLong((padBits - 5) << (padBits - 5), padBits) ;
- }
-
- /**
- * Get the number of bytes in the compression command stream.
- *
- * @return size of compressed data in bytes
- */
- int getByteCount() {
- if (byteOffset + bitOffset == 0)
- return 0 ;
- else
- return byteOffset + 1 ;
- }
-
- /**
- * Get the bytes composing the compression command stream.
- *
- * @return reference to array of bytes containing the compressed data
- */
- byte[] getBytes() {
- return bytes ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/compression/CompressedGeometryFile.java b/src/classes/share/com/sun/j3d/utils/compression/CompressedGeometryFile.java
deleted file mode 100644
index 87d0d75..0000000
--- a/src/classes/share/com/sun/j3d/utils/compression/CompressedGeometryFile.java
+++ /dev/null
@@ -1,1011 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.compression;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-import javax.media.j3d.CapabilityNotSetException;
-import javax.media.j3d.CompressedGeometry;
-import javax.media.j3d.CompressedGeometryHeader;
-
-//
-// The compressed geometry file format supported by this class has a 32
-// byte header followed by multiple compressed geometry objects.
-//
-// Each object consists of a block of compressed data and an 8-byte
-// individual block header describing its contents.
-//
-// The file ends with a directory data structure used for random access,
-// containing a 64-bit offset for each object in the order in which it
-// appears in the file. This is also used to find the size of the largest
-// object in the file and must be present.
-//
-
-/**
- * This class provides methods to read and write compressed geometry resource
- * files. These files usually end with the .cg extension and support
- * sequential as well as random access to multiple compressed geometry
- * objects.
- *
- * @deprecated As of Java 3D 1.5, replaced by
- * com.sun.j3d.utils.geometry.compression.{@link com.sun.j3d.utils.geometry.compression.CompressedGeometryFile}.
- */
-public class CompressedGeometryFile {
- private static final boolean print = false ;
- private static final boolean benchmark = false ;
-
- /**
- * The magic number which identifies the compressed geometry file type.
- */
- static final int MAGIC_NUMBER = 0xbaddfab4 ;
-
- /**
- * Byte offset of the magic number from start of file.
- */
- static final int MAGIC_NUMBER_OFFSET = 0 ;
-
- /**
- * Byte offset of the major version number from start of file.
- */
- static final int MAJOR_VERSION_OFFSET = 4 ;
-
- /**
- * Byte offset of the minor version number from start of file.
- */
- static final int MINOR_VERSION_OFFSET = 8 ;
-
- /**
- * Byte offset of the minor minor version number from start of file.
- */
- static final int MINOR_MINOR_VERSION_OFFSET = 12 ;
-
- /**
- * Byte offset of the number of objects from start of file.
- */
- static final int OBJECT_COUNT_OFFSET = 16 ;
-
- /**
- * Byte offset of the directory offset from start of file.
- * This offset is long word aligned since the directory offset is a long.
- */
- static final int DIRECTORY_OFFSET_OFFSET = 24 ;
-
- /**
- * File header total size in bytes.
- */
- static final int HEADER_SIZE = 32 ;
-
- /**
- * Byte offset of the object size from start of individual compressed
- * geometry block.
- */
- static final int OBJECT_SIZE_OFFSET = 0 ;
-
- /**
- * Byte offset of the compressed geometry data descriptor from start of
- * individual compressed geometry block.
- */
- static final int GEOM_DATA_OFFSET = 4 ;
-
- /**
- * Bits in compressed geometry data descriptor which encode the buffer type.
- */
- static final int TYPE_MASK = 0x03 ;
-
- /**
- * Bit in compressed geometry data descriptor encoding presence of normals.
- */
- static final int NORMAL_PRESENT_MASK = 0x04 ;
-
- /**
- * Bit in compressed geometry data descriptor encoding presence of colors.
- */
- static final int COLOR_PRESENT_MASK = 0x08 ;
-
- /**
- * Bit in compressed geometry data descriptor encoding presence of alphas.
- */
- static final int ALPHA_PRESENT_MASK = 0x10 ;
-
- /**
- * Value in compressed geometry data descriptor for a point buffer type.
- */
- static final int TYPE_POINT = 1 ;
-
- /**
- * Value in compressed geometry data descriptor for a line buffer type.
- */
- static final int TYPE_LINE = 2 ;
-
- /**
- * Value in compressed geometry data descriptor for a triangle buffer type.
- */
- static final int TYPE_TRIANGLE = 3 ;
-
- /**
- * Block header total size in bytes.
- */
- static final int BLOCK_HEADER_SIZE = 8 ;
-
- // The name of the compressed geometry resource file.
- String fileName = null ;
-
- // The major, minor, and subminor version number of the most recent
- // compressor used to compress any of the objects in the compressed
- // geometry resource file.
- int majorVersionNumber ;
- int minorVersionNumber ;
- int minorMinorVersionNumber ;
-
- // The number of objects in the compressed geometry resource file.
- int objectCount ;
-
- // The index of the current object in the file.
- int objectIndex = 0 ;
-
- // The random access file associated with this instance.
- RandomAccessFile cgFile = null ;
-
- // The magic number identifying the file type.
- int magicNumber ;
-
- // These fields are set from each individual block of compressed geometry.
- byte cgBuffer[] ;
- int geomSize ;
- int geomStart ;
- int geomDataType ;
-
- // The directory of object offsets is read from the end of the file.
- long directory[] ;
- long directoryOffset ;
-
- // The object sizes are computed from the directory offsets. These are
- // used to allocate a buffer large enough to hold the largest object and
- // to determine how many consecutive objects can be read into that buffer.
- int objectSizes[] ;
- int bufferObjectStart ;
- int bufferObjectCount ;
- int bufferNextObjectCount ;
- int bufferNextObjectOffset ;
-
- // The shared compressed geometry header object.
- CompressedGeometryHeader cgh ;
-
- // Flag indicating file update.
- boolean fileUpdate = false ;
-
- /**
- * Construct a new CompressedGeometryFile instance associated with the
- * specified file. An attempt is made to open the file with read-only
- * access; if this fails then a FileNotFoundException is thrown.
- *
- * @param file path to the compressed geometry resource file
- * @exception FileNotFoundException if file doesn't exist or
- * cannot be read
- * @exception IllegalArgumentException if the file is not a compressed
- * geometry resource file
- * @exception IOException if there is a header or directory read error
- */
- public CompressedGeometryFile(String file) throws IOException {
- this(file, false) ;
- }
-
- /**
- * Construct a new CompressedGeometryFile instance associated with the
- * specified file.
- *
- * @param file path to the compressed geometry resource file
- * @param rw if true, opens the file for read and write access or attempts
- * to create one if it doesn't exist; if false, opens the file with
- * read-only access
- * @exception FileNotFoundException if file doesn't exist or
- * access permissions disallow access
- * @exception IllegalArgumentException if the file is not a compressed
- * geometry resource file
- * @exception IOException if there is a header or directory read error
- */
- public CompressedGeometryFile(String file, boolean rw) throws IOException {
- // Open the file and read the file header.
- open(file, rw) ;
-
- // Copy the file name.
- fileName = new String(file) ;
-
- // Set up the file fields.
- initialize() ;
- }
-
- /**
- * Construct a new CompressedGeometryFile instance associated with a
- * currently open RandomAccessFile.
- *
- * @param file currently open RandomAccessFile
- * @exception IllegalArgumentException if the file is not a compressed
- * geometry resource file
- * @exception IOException if there is a header or directory read error
- */
- public CompressedGeometryFile(RandomAccessFile file) throws IOException {
- // Copy the file reference.
- cgFile = file ;
-
- // Set up the file fields.
- initialize() ;
- }
-
- /**
- * Delete all compressed objects from this instance. This method may only
- * be called after successfully creating a CompressedGeometryFile instance
- * with read-write access, so a corrupted or otherwise invalid resource
- * must be removed manually before it can be rewritten. The close()
- * method must be called sometime after invoking clear() in order to write
- * out the new directory structure.
- *
- * @exception IOException if clear fails
- */
- public void clear() throws IOException {
- // Truncate the file.
- cgFile.setLength(0) ;
-
- // Set up the file fields.
- initialize() ;
- }
-
- /**
- * Return a string containing the file name associated with this instance
- * or null if there is none.
- *
- * @return file name associated with this instance or null if there is
- * none
- */
- public String getFileName() {
- return fileName ;
- }
-
- /**
- * Return the major version number of the most recent compressor used to
- * compress any of the objects in this instance.
- *
- * @return major version number
- */
- public int getMajorVersionNumber() {
- return majorVersionNumber ;
- }
-
- /**
- * Return the minor version number of the most recent compressor used to
- * compress any of the objects in this instance.
- *
- * @return minor version number
- */
- public int getMinorVersionNumber() {
- return minorVersionNumber ;
- }
-
- /**
- * Return the subminor version number of the most recent compressor used to
- * compress any of the objects in this instance.
- *
- * @return subminor version number
- */
- public int getMinorMinorVersionNumber() {
- return minorMinorVersionNumber ;
- }
-
- /**
- * Return the number of compressed objects in this instance.
- *
- * @return number of compressed objects
- */
- public int getObjectCount() {
- return objectCount ;
- }
-
- /**
- * Return the current object index associated with this instance. This is
- * the index of the object that would be returned by an immediately
- * following call to the readNext() method. Its initial value is 0; -1
- * is returned if the last object has been read.
- *
- * @return current object index, or -1 if at end
- */
- public int getCurrentIndex() {
- if (objectIndex == objectCount)
- return -1 ;
- else
- return objectIndex ;
- }
-
- /**
- * Read the next compressed geometry object in the instance. This is
- * initially the first object (index 0) in the instance; otherwise, it is
- * whatever object is next after the last one read. The current object
- * index is incremented by 1 after the read. When the last object is read
- * the index becomes invalid and an immediately subsequent call to
- * readNext() returns null.
- *
- * @return a CompressedGeometry node component, or null if the last object
- * has been read
- * @exception IOException if read fails
- */
- public CompressedGeometry readNext() throws IOException {
- return readNext(cgBuffer.length) ;
- }
-
- /**
- * Read all compressed geometry objects contained in the instance. The
- * current object index becomes invalid; an immediately following call
- * to readNext() will return null.
- *
- * @return an array of CompressedGeometry node components.
- * @exception IOException if read fails
- */
- public CompressedGeometry[] read() throws IOException {
- long startTime = 0 ;
- CompressedGeometry cg[] = new CompressedGeometry[objectCount] ;
-
- if (benchmark)
- startTime = System.currentTimeMillis() ;
-
- objectIndex = 0 ;
- setFilePointer(directory[0]) ;
- bufferNextObjectCount = 0 ;
-
- for (int i = 0 ; i < objectCount ; i++)
- cg[i] = readNext(cgBuffer.length) ;
-
- if (benchmark) {
- long t = System.currentTimeMillis() - startTime ;
- System.out.println("read " + objectCount +
- " objects " + cgFile.length() +
- " bytes in " + (t/1000f) + " sec.") ;
- System.out.println((cgFile.length()/(float)t) + " Kbytes/sec.") ;
- }
-
- return cg ;
- }
-
- /**
- * Read the compressed geometry object at the specified index. The
- * current object index is set to the subsequent object unless the last
- * object has been read, in which case the index becomes invalid and an
- * immediately following call to readNext() will return null.
- *
- * @param index compressed geometry object to read
- * @return a CompressedGeometry node component
- * @exception IndexOutOfBoundsException if object index is
- * out of range
- * @exception IOException if read fails
- */
- public CompressedGeometry read(int index) throws IOException {
- objectIndex = index ;
-
- if (objectIndex < 0) {
- throw new IndexOutOfBoundsException
- ("\nobject index must be >= 0") ;
- }
- if (objectIndex >= objectCount) {
- throw new IndexOutOfBoundsException
- ("\nobject index must be < " + objectCount) ;
- }
-
- // Check if object is in cache.
- if ((objectIndex >= bufferObjectStart) &&
- (objectIndex < bufferObjectStart + bufferObjectCount)) {
- if (print) System.out.println("\ngetting object from cache\n") ;
-
- bufferNextObjectOffset = (int)
- (directory[objectIndex] - directory[bufferObjectStart]) ;
-
- bufferNextObjectCount =
- bufferObjectCount - (objectIndex - bufferObjectStart) ;
-
- return readNext() ;
-
- } else {
- // Move file pointer to correct offset.
- setFilePointer(directory[objectIndex]) ;
-
- // Force a read from current offset. Disable cache read-ahead
- // since cache hits are unlikely with random access.
- bufferNextObjectCount = 0 ;
- return readNext(objectSizes[objectIndex]) ;
- }
- }
-
-
- /**
- * Add a compressed geometry node component to the end of the instance.
- * The current object index becomes invalid; an immediately following call
- * to readNext() will return null. The close() method must be called at
- * some later time in order to create a valid compressed geometry file.
- *
- * @param cg a compressed geometry node component
- * @exception CapabilityNotSetException if unable to get compressed
- * geometry data from the node component
- * @exception IOException if write fails
- */
- public void write(CompressedGeometry cg) throws IOException {
- CompressedGeometryHeader cgh = new CompressedGeometryHeader() ;
- cg.getCompressedGeometryHeader(cgh) ;
-
- // Update the read/write buffer size if necessary.
- if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) {
- cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ;
- if (print) System.out.println("\ncgBuffer: reallocated " +
- (cgh.size+BLOCK_HEADER_SIZE) +
- " bytes") ;
- }
-
- cg.getCompressedGeometry(cgBuffer) ;
- write(cgh, cgBuffer) ;
- }
-
- /**
- * Add a buffer of compressed geometry data to the end of the
- * resource. The current object index becomes invalid; an immediately
- * following call to readNext() will return null. The close() method must
- * be called at some later time in order to create a valid compressed
- * geometry file.
- *
- * @param cgh a CompressedGeometryHeader object describing the data.
- * @param geometry the compressed geometry data
- * @exception IOException if write fails
- */
- public void write(CompressedGeometryHeader cgh, byte geometry[])
- throws IOException {
-
- // Update the read/write buffer size if necessary. It won't be used
- // in this method, but should be big enough to read any object in
- // the file, including the one to be written.
- if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) {
- cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ;
- if (print) System.out.println("\ncgBuffer: reallocated " +
- (cgh.size+BLOCK_HEADER_SIZE) +
- " bytes") ;
- }
-
- // Assuming backward compatibility, the version number of the file
- // should be the maximum of all individual compressed object versions.
- if ((cgh.majorVersionNumber > majorVersionNumber)
- ||
- ((cgh.majorVersionNumber == majorVersionNumber) &&
- (cgh.minorVersionNumber > minorVersionNumber))
- ||
- ((cgh.majorVersionNumber == majorVersionNumber) &&
- (cgh.minorVersionNumber == minorVersionNumber) &&
- (cgh.minorMinorVersionNumber > minorMinorVersionNumber))) {
-
- majorVersionNumber = cgh.majorVersionNumber ;
- minorVersionNumber = cgh.minorVersionNumber ;
- minorMinorVersionNumber = cgh.minorMinorVersionNumber ;
-
- this.cgh.majorVersionNumber = cgh.majorVersionNumber ;
- this.cgh.minorVersionNumber = cgh.minorVersionNumber ;
- this.cgh.minorMinorVersionNumber = cgh.minorMinorVersionNumber ;
- }
-
- // Get the buffer type and see what vertex components are present.
- int geomDataType = 0 ;
-
- switch (cgh.bufferType) {
- case CompressedGeometryHeader.POINT_BUFFER:
- geomDataType = TYPE_POINT ;
- break ;
- case CompressedGeometryHeader.LINE_BUFFER:
- geomDataType = TYPE_LINE ;
- break ;
- case CompressedGeometryHeader.TRIANGLE_BUFFER:
- geomDataType = TYPE_TRIANGLE ;
- break ;
- }
-
- if ((cgh.bufferDataPresent &
- CompressedGeometryHeader.NORMAL_IN_BUFFER) != 0)
- geomDataType |= NORMAL_PRESENT_MASK ;
-
- if ((cgh.bufferDataPresent &
- CompressedGeometryHeader.COLOR_IN_BUFFER) != 0)
- geomDataType |= COLOR_PRESENT_MASK ;
-
- if ((cgh.bufferDataPresent &
- CompressedGeometryHeader.ALPHA_IN_BUFFER) != 0)
- geomDataType |= ALPHA_PRESENT_MASK ;
-
- // Allocate new directory and object size arrays if necessary.
- if (objectCount == directory.length) {
- long newDirectory[] = new long[2*objectCount] ;
- int newObjectSizes[] = new int[2*objectCount] ;
-
- System.arraycopy(directory, 0,
- newDirectory, 0, objectCount) ;
- System.arraycopy(objectSizes, 0,
- newObjectSizes, 0, objectCount) ;
-
- directory = newDirectory ;
- objectSizes = newObjectSizes ;
-
- if (print)
- System.out.println("\ndirectory and size arrays: reallocated " +
- (2*objectCount) + " entries") ;
- }
-
- // Update directory and object size array.
- directory[objectCount] = directoryOffset ;
- objectSizes[objectCount] = cgh.size + BLOCK_HEADER_SIZE ;
- objectCount++ ;
-
- // Seek to the directory and overwrite from there.
- setFilePointer(directoryOffset) ;
- cgFile.writeInt(cgh.size) ;
- cgFile.writeInt(geomDataType) ;
- cgFile.write(geometry, 0, cgh.size) ;
- if (print)
- System.out.println("\nwrote " + cgh.size +
- " byte compressed object to " + fileName +
- "\nfile offset " + directoryOffset) ;
-
- // Update the directory offset.
- directoryOffset += cgh.size + BLOCK_HEADER_SIZE ;
-
- // Return end-of-file on next read.
- objectIndex = objectCount ;
-
- // Flag file update so close() will write out the directory.
- fileUpdate = true ;
- }
-
- /**
- * Release the resources associated with this instance.
- * Write out final header and directory if contents were updated.
- * This method must be called in order to create a valid compressed
- * geometry resource file if any updates were made.
- */
- public void close() {
- if (cgFile != null) {
- try {
- if (fileUpdate) {
- writeFileDirectory() ;
- writeFileHeader() ;
- }
- cgFile.close() ;
- }
- catch (IOException e) {
- // Don't propagate this exception.
- System.out.println("\nException: " + e.getMessage()) ;
- System.out.println("failed to close " + fileName) ;
- }
- }
- cgFile = null ;
- cgBuffer = null ;
- directory = null ;
- objectSizes = null ;
- }
-
-
- //
- // Open the file. Specifying a non-existent file creates a new one if
- // access permissions allow.
- //
- void open(String fname, boolean rw)
- throws FileNotFoundException, IOException {
-
- cgFile = null ;
- String mode ;
-
- if (rw)
- mode = "rw" ;
- else
- mode = "r" ;
-
- try {
- cgFile = new RandomAccessFile(fname, mode) ;
- if (print) System.out.println("\n" + fname +
- ": opened mode " + mode) ;
- }
- catch (FileNotFoundException e) {
- // N.B. this exception is also thrown on access permission errors
- throw new FileNotFoundException(e.getMessage() + "\n" + fname +
- ": open mode " + mode + " failed") ;
- }
- }
-
- //
- // Seek to the specified offset in the file.
- //
- void setFilePointer(long offset) throws IOException {
- cgFile.seek(offset) ;
-
- // Reset number of objects that can be read sequentially from cache.
- bufferNextObjectCount = 0 ;
- }
-
- //
- // Initialize directory, object size array, read/write buffer, and the
- // shared compressed geometry header.
- //
- void initialize() throws IOException {
- int maxSize = 0 ;
-
- if (cgFile.length() == 0) {
- // New file for writing: allocate nominal initial sizes for arrays.
- objectCount = 0 ;
- cgBuffer = new byte[32768] ;
- directory = new long[16] ;
- objectSizes = new int[directory.length] ;
-
- // Set fields as if they have been read.
- magicNumber = MAGIC_NUMBER ;
- majorVersionNumber = 1 ;
- minorVersionNumber = 0 ;
- minorMinorVersionNumber = 0 ;
- directoryOffset = HEADER_SIZE ;
-
- // Write the file header.
- writeFileHeader() ;
-
- } else {
- // Read the file header.
- readFileHeader() ;
-
- // Check file type.
- if (magicNumber != MAGIC_NUMBER) {
- close() ;
- throw new IllegalArgumentException
- ("\n" + fileName + " is not a compressed geometry file") ;
- }
-
- // Read the directory and determine object sizes.
- directory = new long[objectCount] ;
- readDirectory(directoryOffset, directory) ;
-
- objectSizes = new int[objectCount] ;
- for (int i = 0 ; i < objectCount-1 ; i++) {
- objectSizes[i] = (int)(directory[i+1] - directory[i]) ;
- if (objectSizes[i] > maxSize) maxSize = objectSizes[i] ;
- }
-
- if (objectCount > 0) {
- objectSizes[objectCount-1] =
- (int)(directoryOffset - directory[objectCount-1]) ;
-
- if (objectSizes[objectCount-1] > maxSize)
- maxSize = objectSizes[objectCount-1] ;
- }
-
- // Allocate a buffer big enough to read the largest object.
- cgBuffer = new byte[maxSize] ;
-
- // Move to the first object.
- setFilePointer(HEADER_SIZE) ;
- }
-
- // Set up common parts of the compressed geometry object header.
- cgh = new CompressedGeometryHeader() ;
- cgh.majorVersionNumber = this.majorVersionNumber ;
- cgh.minorVersionNumber = this.minorVersionNumber ;
- cgh.minorMinorVersionNumber = this.minorMinorVersionNumber ;
-
- if (print) {
- System.out.println(fileName + ": " + objectCount + " objects") ;
- System.out.println("magic number 0x" +
- Integer.toHexString(magicNumber) +
- ", version number " + majorVersionNumber +
- "." + minorVersionNumber +
- "." + minorMinorVersionNumber) ;
- System.out.println("largest object is " + maxSize + " bytes") ;
- }
- }
-
- //
- // Read the file header.
- //
- void readFileHeader() throws IOException {
- byte header[] = new byte[HEADER_SIZE] ;
-
- try {
- setFilePointer(0) ;
- if (cgFile.read(header) != HEADER_SIZE) {
- close() ;
- throw new IOException("failed header read") ;
- }
- }
- catch (IOException e) {
- if (cgFile != null) {
- close() ;
- }
- throw e ;
- }
-
- magicNumber =
- ((header[MAGIC_NUMBER_OFFSET+0] & 0xff) << 24) |
- ((header[MAGIC_NUMBER_OFFSET+1] & 0xff) << 16) |
- ((header[MAGIC_NUMBER_OFFSET+2] & 0xff) << 8) |
- ((header[MAGIC_NUMBER_OFFSET+3] & 0xff)) ;
-
- majorVersionNumber =
- ((header[MAJOR_VERSION_OFFSET+0] & 0xff) << 24) |
- ((header[MAJOR_VERSION_OFFSET+1] & 0xff) << 16) |
- ((header[MAJOR_VERSION_OFFSET+2] & 0xff) << 8) |
- ((header[MAJOR_VERSION_OFFSET+3] & 0xff)) ;
-
- minorVersionNumber =
- ((header[MINOR_VERSION_OFFSET+0] & 0xff) << 24) |
- ((header[MINOR_VERSION_OFFSET+1] & 0xff) << 16) |
- ((header[MINOR_VERSION_OFFSET+2] & 0xff) << 8) |
- ((header[MINOR_VERSION_OFFSET+3] & 0xff)) ;
-
- minorMinorVersionNumber =
- ((header[MINOR_MINOR_VERSION_OFFSET+0] & 0xff) << 24) |
- ((header[MINOR_MINOR_VERSION_OFFSET+1] & 0xff) << 16) |
- ((header[MINOR_MINOR_VERSION_OFFSET+2] & 0xff) << 8) |
- ((header[MINOR_MINOR_VERSION_OFFSET+3] & 0xff)) ;
-
- objectCount =
- ((header[OBJECT_COUNT_OFFSET+0] & 0xff) << 24) |
- ((header[OBJECT_COUNT_OFFSET+1] & 0xff) << 16) |
- ((header[OBJECT_COUNT_OFFSET+2] & 0xff) << 8) |
- ((header[OBJECT_COUNT_OFFSET+3] & 0xff)) ;
-
- directoryOffset =
- ((long)(header[DIRECTORY_OFFSET_OFFSET+0] & 0xff) << 56) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+1] & 0xff) << 48) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+2] & 0xff) << 40) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+3] & 0xff) << 32) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+4] & 0xff) << 24) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+5] & 0xff) << 16) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+6] & 0xff) << 8) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+7] & 0xff)) ;
- }
-
- //
- // Write the file header based on current field values.
- //
- void writeFileHeader() throws IOException {
- setFilePointer(0) ;
- try {
- cgFile.writeInt(MAGIC_NUMBER) ;
- cgFile.writeInt(majorVersionNumber) ;
- cgFile.writeInt(minorVersionNumber) ;
- cgFile.writeInt(minorMinorVersionNumber) ;
- cgFile.writeInt(objectCount) ;
- cgFile.writeInt(0) ; // long word alignment
- cgFile.writeLong(directoryOffset) ;
- if (print)
- System.out.println("wrote file header for " + fileName) ;
- }
- catch (IOException e) {
- throw new IOException
- (e.getMessage() +
- "\ncould not write file header for " + fileName) ;
- }
- }
-
- //
- // Read the directory of compressed geometry object offsets.
- //
- void readDirectory(long offset, long[] directory)
- throws IOException {
-
- byte buff[] = new byte[directory.length * 8] ;
- setFilePointer(offset) ;
-
- try {
- cgFile.read(buff) ;
- if (print)
- System.out.println("read " + buff.length + " byte directory") ;
- }
- catch (IOException e) {
- throw new IOException
- (e.getMessage() +
- "\nfailed to read " + buff.length +
- " byte directory, offset " + offset + " in file " + fileName) ;
- }
-
- for (int i = 0 ; i < directory.length ; i++) {
- directory[i] =
- ((long)(buff[i*8+0] & 0xff) << 56) |
- ((long)(buff[i*8+1] & 0xff) << 48) |
- ((long)(buff[i*8+2] & 0xff) << 40) |
- ((long)(buff[i*8+3] & 0xff) << 32) |
- ((long)(buff[i*8+4] & 0xff) << 24) |
- ((long)(buff[i*8+5] & 0xff) << 16) |
- ((long)(buff[i*8+6] & 0xff) << 8) |
- ((long)(buff[i*8+7] & 0xff)) ;
- }
- }
-
- //
- // Write the file directory.
- //
- void writeFileDirectory() throws IOException {
- setFilePointer(directoryOffset) ;
-
- int directoryAlign = (int)(directoryOffset % 8) ;
- if (directoryAlign != 0) {
- // Align to long word before writing directory of long offsets.
- byte bytes[] = new byte[8-directoryAlign] ;
-
- try {
- cgFile.write(bytes) ;
- if (print)
- System.out.println ("wrote " + (8-directoryAlign) +
- " bytes long alignment") ;
- }
- catch (IOException e) {
- throw new IOException
- (e.getMessage() +
- "\ncould not write " + directoryAlign +
- " bytes to long word align directory for " + fileName) ;
- }
- directoryOffset += 8-directoryAlign ;
- }
-
- try {
- for (int i = 0 ; i < objectCount ; i++)
- cgFile.writeLong(directory[i]) ;
-
- if (print)
- System.out.println("wrote file directory for " + fileName) ;
- }
- catch (IOException e) {
- throw new IOException
- (e.getMessage() +
- "\ncould not write directory for " + fileName) ;
- }
- }
-
- //
- // Get the next compressed object in the file, either from the read-ahead
- // cache or from the file itself.
- //
- CompressedGeometry readNext(int bufferReadLimit)
- throws IOException {
- if (objectIndex == objectCount)
- return null ;
-
- if (bufferNextObjectCount == 0) {
- // No valid objects are in the cache.
- int curSize = 0 ;
- bufferObjectCount = 0 ;
-
- // See how much we have room to read.
- for (int i = objectIndex ; i < objectCount ; i++) {
- if (curSize + objectSizes[i] > bufferReadLimit) break ;
- curSize += objectSizes[i] ;
- bufferObjectCount++ ;
- }
-
- // Try to read that amount.
- try {
- int n = cgFile.read(cgBuffer, 0, curSize) ;
- if (print)
- System.out.println("\nread " + n +
- " bytes from " + fileName) ;
- }
- catch (IOException e) {
- throw new IOException
- (e.getMessage() +
- "\nfailed to read " + curSize +
- " bytes, object " + objectIndex + " in file " + fileName) ;
- }
-
- // Point at the first object in the buffer.
- bufferObjectStart = objectIndex ;
- bufferNextObjectCount = bufferObjectCount ;
- bufferNextObjectOffset = 0 ;
- }
-
- // Get block header info.
- geomSize =
- ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+0]&0xff)<<24) |
- ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+1]&0xff)<<16) |
- ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+2]&0xff)<< 8) |
- ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+3]&0xff)) ;
-
- geomDataType =
- ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+0]&0xff) << 24) |
- ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+1]&0xff) << 16) |
- ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+2]&0xff) << 8) |
- ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+3]&0xff)) ;
-
- // Get offset of compressed geometry data from start of buffer.
- geomStart = bufferNextObjectOffset + BLOCK_HEADER_SIZE ;
-
- if (print) {
- System.out.println("\nobject " + objectIndex +
- "\nfile offset " + directory[objectIndex] +
- ", buffer offset " + bufferNextObjectOffset) ;
- System.out.println("size " + geomSize + " bytes, " +
- "data descriptor 0x" +
- Integer.toHexString(geomDataType)) ;
- }
-
- // Update cache info.
- bufferNextObjectOffset += objectSizes[objectIndex] ;
- bufferNextObjectCount-- ;
- objectIndex++ ;
-
- return newCG(geomSize, geomStart, geomDataType) ;
- }
-
-
- //
- // Construct and return a compressed geometry node.
- //
- CompressedGeometry newCG(int geomSize,
- int geomStart,
- int geomDataType) {
- cgh.size = geomSize ;
- cgh.start = geomStart ;
-
- if ((geomDataType & TYPE_MASK) == TYPE_POINT)
- cgh.bufferType = CompressedGeometryHeader.POINT_BUFFER ;
- else if ((geomDataType & TYPE_MASK) == TYPE_LINE)
- cgh.bufferType = CompressedGeometryHeader.LINE_BUFFER ;
- else if ((geomDataType & TYPE_MASK) == TYPE_TRIANGLE)
- cgh.bufferType = CompressedGeometryHeader.TRIANGLE_BUFFER ;
-
- cgh.bufferDataPresent = 0 ;
-
- if ((geomDataType & NORMAL_PRESENT_MASK) != 0)
- cgh.bufferDataPresent |=
- CompressedGeometryHeader.NORMAL_IN_BUFFER ;
-
- if ((geomDataType & COLOR_PRESENT_MASK) != 0)
- cgh.bufferDataPresent |=
- CompressedGeometryHeader.COLOR_IN_BUFFER ;
-
- if ((geomDataType & ALPHA_PRESENT_MASK) != 0)
- cgh.bufferDataPresent |=
- CompressedGeometryHeader.ALPHA_IN_BUFFER ;
-
- return new CompressedGeometry(cgh, cgBuffer) ;
- }
-
- /**
- * Release file resources when this object is garbage collected.
- */
- @Override
- protected void finalize() {
- close() ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/compression/CompressionStream.java b/src/classes/share/com/sun/j3d/utils/compression/CompressionStream.java
deleted file mode 100644
index 10e12ba..0000000
--- a/src/classes/share/com/sun/j3d/utils/compression/CompressionStream.java
+++ /dev/null
@@ -1,2342 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.compression;
-
-import java.nio.ByteBuffer;
-import java.nio.DoubleBuffer;
-import java.nio.FloatBuffer;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-
-import javax.media.j3d.Appearance;
-import javax.media.j3d.CompressedGeometryHeader;
-import javax.media.j3d.Geometry;
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.GeometryStripArray;
-import javax.media.j3d.IndexedGeometryArray;
-import javax.media.j3d.IndexedGeometryStripArray;
-import javax.media.j3d.IndexedLineArray;
-import javax.media.j3d.IndexedLineStripArray;
-import javax.media.j3d.IndexedQuadArray;
-import javax.media.j3d.IndexedTriangleArray;
-import javax.media.j3d.IndexedTriangleFanArray;
-import javax.media.j3d.IndexedTriangleStripArray;
-import javax.media.j3d.J3DBuffer;
-import javax.media.j3d.LineArray;
-import javax.media.j3d.LineStripArray;
-import javax.media.j3d.Material;
-import javax.media.j3d.QuadArray;
-import javax.media.j3d.Shape3D;
-import javax.media.j3d.TriangleArray;
-import javax.media.j3d.TriangleFanArray;
-import javax.media.j3d.TriangleStripArray;
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3d;
-import javax.vecmath.Point3f;
-import javax.vecmath.Point3i;
-import javax.vecmath.Vector3f;
-
-import com.sun.j3d.internal.BufferWrapper;
-import com.sun.j3d.utils.geometry.GeometryInfo;
-
-/**
- * This class is used as input to a geometry compressor. It collects elements
- * such as vertices, normals, colors, mesh references, and quantization
- * parameters in an ordered stream. This stream is then traversed during
- * the compression process and used to build the compressed output buffer.
- *
- * @see GeometryCompressor
- *
- * @deprecated As of Java 3D 1.5, replaced by
- * com.sun.j3d.utils.geometry.compression.{@link com.sun.j3d.utils.geometry.compression.CompressionStream}.
- */
-public class CompressionStream {
- //
- // NOTE: For now, copies are made of all GeometryArray vertex components
- // even when by-reference access is available.
- //
- // TODO: Retrofit all CompressionStreamElements and MeshBuffer to handle
- // offsets to vertex data array references so that vertex components don't
- // have to be copied. New CompressionStreamElements could be defined to
- // set the current array reference during the quantization pass, or the
- // reference could be included in every CompressionStreamElement along
- // with the data offsets.
- //
- // TODO: Quantize on-the-fly when adding GeometryArray vertex data so that
- // CompressionStreamElements don't need references to the original float,
- // double, or byte data. Quantization is currently a separate pass since
- // the 1st pass adds vertex data and gets the total object bounds, but
- // this can be computed by merging the bounds of each GeometryArray
- // compressed into a single object. The 2nd pass quantization is still
- // needed for vertex data which isn't retrieved from a GeometryArray; for
- // example, apps that might use the addVertex() methods directly instead
- // of addGeometryArray().
- //
- // TODO: To further optimize memory, create new subclasses of
- // CompressionStream{Color, Normal} for bundled attributes and add them as
- // explicit stream elements. Then CompressionStreamVertex won't need to
- // carry references to them. This memory savings might be negated by the
- // extra overhead of adding more elements to the stream, however.
- //
- // TODO: Keep the absolute quantized values in the mesh buffer mirror so
- // that unmeshed CompressionStreamElements don't need to carry them.
- //
- // TODO: Support texture coordinate compression even though Level II is
- // not supported by any hardware decompressor on any graphics card.
- // Software decompression is still useful for applications interested in
- // minimizing file space, transmission time, and object loading time.
- //
- private static final boolean debug = false ;
- private static final boolean benchmark = false ;
-
- // Mesh buffer normal substitution is unavailable in Level I.
- private static final boolean noMeshNormalSubstitution = true ;
-
- /**
- * This flag indicates that a vertex starts a new triangle or line strip.
- */
- static final int RESTART = 1 ;
-
- /**
- * This flag indicates that the next triangle in the strip is defined by
- * replacing the middle vertex of the previous triangle in the strip.
- * Equivalent to REPLACE_OLDEST for line strips.
- */
- static final int REPLACE_MIDDLE = 2 ;
-
- /**
- * This flag indicates that the next triangle in the strip is defined by
- * replacing the oldest vertex of the previous triangle in the strip.
- * Equivalent to REPLACE_MIDDLE for line strips.
- */
- static final int REPLACE_OLDEST = 3 ;
-
- /**
- * This flag indicates that a vertex is to be pushed into the mesh buffer.
- */
- static final int MESH_PUSH = 1 ;
-
- /**
- * This flag indicates that a vertex does not use the mesh buffer.
- */
- static final int NO_MESH_PUSH = 0 ;
-
- /**
- * Byte to float scale factor for scaling byte color components.
- */
- static final float ByteToFloatScale = 1.0f/255.0f;
-
- /**
- * Type of this stream, either CompressedGeometryHeader.POINT_BUFFER,
- * CompressedGeometryHeader.LINE_BUFFER, or
- * CompressedGeometryHeader.TRIANGLE_BUFFER
- */
- int streamType ;
-
- /**
- * A mask indicating which components are present in each vertex, as
- * defined by GeometryArray.
- */
- int vertexComponents ;
-
- /**
- * Boolean indicating colors are bundled with the vertices.
- */
- boolean vertexColors ;
-
- /**
- * Boolean indicating RGB colors are bundled with the vertices.
- */
- boolean vertexColor3 ;
-
- /**
- * Boolean indicating RGBA colors are bundled with the vertices.
- */
- boolean vertexColor4 ;
-
- /**
- * Boolean indicating normals are bundled with the vertices.
- */
- boolean vertexNormals ;
-
- /**
- * Boolean indicating texture coordinates are present.
- */
- boolean vertexTextures ;
-
- /**
- * Boolean indicating that 2D texture coordinates are used.
- * Currently only used to skip over textures in interleaved data.
- */
- boolean vertexTexture2 ;
-
- /**
- * Boolean indicating that 3D texture coordinates are used.
- * Currently only used to skip over textures in interleaved data.
- */
- boolean vertexTexture3 ;
-
- /**
- * Boolean indicating that 4D texture coordinates are used.
- * Currently only used to skip over textures in interleaved data.
- */
- boolean vertexTexture4 ;
-
- /**
- * Axes-aligned box enclosing all vertices in model coordinates.
- */
- Point3d mcBounds[] = new Point3d[2] ;
-
- /**
- * Axes-aligned box enclosing all vertices in normalized coordinates.
- */
- Point3d ncBounds[] = new Point3d[2] ;
-
- /**
- * Axes-aligned box enclosing all vertices in quantized coordinates.
- */
- Point3i qcBounds[] = new Point3i[2] ;
-
- /**
- * Center for normalizing positions to the unit cube.
- */
- double center[] = new double[3] ;
-
- /**
- * Maximum position range along the 3 axes.
- */
- double positionRangeMaximum ;
-
- /**
- * Scale for normalizing positions to the unit cube.
- */
- double scale ;
-
- /**
- * Current position component (X, Y, and Z) quantization value. This can
- * range from 1 to 16 bits and has a default of 16.
- *
- * At 1 bit of quantization it is not possible to express positive
- * absolute or delta positions.
- */
- int positionQuant ;
-
- /**
- * Current color component (R, G, B, A) quantization value. This can
- * range from 2 to 16 bits and has a default of 9.
- *
- * A color component is represented with a signed fixed-point value in
- * order to be able express negative deltas; the default of 9 bits
- * corresponds to the 8-bit color component range of the graphics hardware
- * commonly available. Colors must be non-negative, so the lower limit of
- * quantization is 2 bits.
- */
- int colorQuant ;
-
- /**
- * Current normal component (U and V) quantization value. This can range
- * from 0 to 6 bits and has a default of 6.
- *
- * At 0 bits of quantization normals are represented only as 6 bit
- * sextant/octant pairs and 14 specially encoded normals (the 6 axis
- * normals and the 8 octant midpoint normals); since U and V can only be 0
- * at the minimum quantization, the totally number of unique normals is
- * 12 + 14 = 26.
- */
- int normalQuant ;
-
- /**
- * Flag indicating position quantization change.
- */
- boolean positionQuantChanged ;
-
- /**
- * Flag indicating color quantization change.
- */
- boolean colorQuantChanged ;
-
- /**
- * Flag indicating normal quantization change.
- */
- boolean normalQuantChanged ;
-
- /**
- * Last quantized position.
- */
- int lastPosition[] = new int[3] ;
-
- /**
- * Last quantized color.
- */
- int lastColor[] = new int[4] ;
-
- /**
- * Last quantized normal's sextant.
- */
- int lastSextant ;
-
- /**
- * Last quantized normal's octant.
- */
- int lastOctant ;
-
- /**
- * Last quantized normal's U encoding parameter.
- */
- int lastU ;
-
- /**
- * Last quantized normal's V encoding parameter.
- */
- int lastV ;
-
- /**
- * Flag indicating last normal used a special encoding.
- */
- boolean lastSpecialNormal ;
-
- /**
- * Flag indicating the first position in this stream.
- */
- boolean firstPosition ;
-
- /**
- * Flag indicating the first color in this stream.
- */
- boolean firstColor ;
-
- /**
- * Flag indicating the first normal in this stream.
- */
- boolean firstNormal ;
-
- /**
- * The total number of bytes used to create the uncompressed geometric
- * elements in this stream, useful for performance analysis. This
- * excludes mesh buffer references.
- */
- int byteCount ;
-
- /**
- * The number of vertices created for this stream, excluding mesh buffer
- * references.
- */
- int vertexCount ;
-
- /**
- * The number of mesh buffer references created for this stream.
- */
- int meshReferenceCount ;
-
- /**
- * Mesh buffer mirror used for computing deltas during quantization pass
- * and a limited meshing algorithm for unstripped data.
- */
- MeshBuffer meshBuffer = new MeshBuffer() ;
-
-
- // Collection which holds the elements of this stream.
- private Collection stream ;
-
- // True if preceding stream elements were colors or normals. Used to flag
- // color and normal mesh buffer substitution when computing deltas during
- // quantization pass.
- private boolean lastElementColor = false ;
- private boolean lastLastElementColor = false ;
- private boolean lastElementNormal = false ;
- private boolean lastLastElementNormal = false ;
-
- // Some convenient temporary holding variables.
- private Point3f p3f = new Point3f() ;
- private Color3f c3f = new Color3f() ;
- private Color4f c4f = new Color4f() ;
- private Vector3f n3f = new Vector3f() ;
-
-
- // Private constructor for common initializations.
- private CompressionStream() {
- this.stream = new LinkedList() ;
-
- byteCount = 0 ;
- vertexCount = 0 ;
- meshReferenceCount = 0 ;
-
- mcBounds[0] = new Point3d(Double.POSITIVE_INFINITY,
- Double.POSITIVE_INFINITY,
- Double.POSITIVE_INFINITY) ;
- mcBounds[1] = new Point3d(Double.NEGATIVE_INFINITY,
- Double.NEGATIVE_INFINITY,
- Double.NEGATIVE_INFINITY) ;
-
- qcBounds[0] = new Point3i(Integer.MAX_VALUE,
- Integer.MAX_VALUE,
- Integer.MAX_VALUE) ;
- qcBounds[1] = new Point3i(Integer.MIN_VALUE,
- Integer.MIN_VALUE,
- Integer.MIN_VALUE) ;
-
- /* normalized bounds computed from quantized bounds */
- ncBounds[0] = new Point3d() ;
- ncBounds[1] = new Point3d() ;
- }
-
- /**
- * Creates a new CompressionStream for the specified geometry type and
- * vertex format.
- *
- * @param streamType type of data in this stream, either
- * CompressedGeometryHeader.POINT_BUFFER,
- * CompressedGeometryHeader.LINE_BUFFER, or
- * CompressedGeometryHeader.TRIANGLE_BUFFER
- *
- * @param vertexComponents a mask indicating which components are present
- * in each vertex, as defined by GeometryArray: COORDINATES, NORMALS, and
- * COLOR_3 or COLOR_4.
- *
- * @see GeometryCompressor
- * @see GeometryArray
- */
- CompressionStream(int streamType, int vertexComponents) {
- this() ;
- this.streamType = streamType ;
- this.vertexComponents = getVertexComponents(vertexComponents) ;
- }
-
- // See what vertex geometry components are present. The byReference,
- // interleaved, useNIOBuffer, and useCoordIndexOnly flags are not
- // examined.
- private int getVertexComponents(int vertexFormat) {
- int components = 0 ;
-
- vertexColors = vertexColor3 = vertexColor4 = vertexNormals =
- vertexTextures = vertexTexture2 = vertexTexture3 = vertexTexture4 =
- false ;
-
- if ((vertexFormat & GeometryArray.NORMALS) != 0) {
- vertexNormals = true ;
- components &= GeometryArray.NORMALS ;
- if (debug) System.out.println("vertexNormals") ;
- }
-
- if ((vertexFormat & GeometryArray.COLOR_3) != 0) {
- vertexColors = true ;
-
- if ((vertexFormat & GeometryArray.COLOR_4) != 0) {
- vertexColor4 = true ;
- components &= GeometryArray.COLOR_4 ;
- if (debug) System.out.println("vertexColor4") ;
- }
- else {
- vertexColor3 = true ;
- components &= GeometryArray.COLOR_3 ;
- if (debug) System.out.println("vertexColor3") ;
- }
- }
-
- if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
- vertexTextures = true ;
- vertexTexture2 = true ;
- components &= GeometryArray.TEXTURE_COORDINATE_2 ;
- if (debug) System.out.println("vertexTexture2") ;
- }
- else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
- vertexTextures = true ;
- vertexTexture3 = true ;
- components &= GeometryArray.TEXTURE_COORDINATE_3 ;
- if (debug) System.out.println("vertexTexture3") ;
- }
- else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
- vertexTextures = true ;
- vertexTexture4 = true ;
- components &= GeometryArray.TEXTURE_COORDINATE_4 ;
- if (debug) System.out.println("vertexTexture4") ;
- }
-
- if (vertexTextures)
- // Throw exception for now until texture is supported.
- throw new UnsupportedOperationException
- ("\ncompression of texture coordinates is not supported") ;
-
- return components ;
- }
-
- // Get the streamType associated with a GeometryArray instance.
- private int getStreamType(GeometryArray ga) {
- if (ga instanceof TriangleStripArray ||
- ga instanceof IndexedTriangleStripArray ||
- ga instanceof TriangleFanArray ||
- ga instanceof IndexedTriangleFanArray ||
- ga instanceof TriangleArray ||
- ga instanceof IndexedTriangleArray ||
- ga instanceof QuadArray ||
- ga instanceof IndexedQuadArray)
-
- return CompressedGeometryHeader.TRIANGLE_BUFFER ;
-
- else if (ga instanceof LineArray ||
- ga instanceof IndexedLineArray ||
- ga instanceof LineStripArray ||
- ga instanceof IndexedLineStripArray)
-
- return CompressedGeometryHeader.LINE_BUFFER ;
-
- else
- return CompressedGeometryHeader.POINT_BUFFER ;
- }
-
- /**
- * Iterates across all compression stream elements and applies
- * quantization parameters, encoding consecutive vertices as delta values
- * whenever possible. Each geometric element is mapped to a HuffmanNode
- * object containing its resulting bit length, right shift (trailing 0
- * count), and absolute or relative status.
- *
- * Positions are normalized to span a unit cube via an offset and a
- * uniform scale factor that maps the midpoint of the object extents along
- * each dimension to the origin, and the longest dimension of the object to
- * the open interval (-1.0 .. +1.0). The geometric endpoints along that
- * dimension are both one quantum away from unity; for example, at a
- * position quantization of 6 bits, an object would be normalized so that
- * its most negative dimension is at (-1 + 1/64) and the most positive is
- * at (1 - 1/64).
- *
- * Normals are assumed to be of unit length. Color components are clamped
- * to the [0..1) range, where the right endpoint is one quantum less
- * than 1.0.
- *
- * @param huffmanTable Table which will map geometric compression stream
- * elements to HuffmanNode objects describing each element's data
- * representation. This table can then be processed with Huffman's
- * algorithm to optimize the bit length of descriptor tags according to
- * the number of geometric elements mapped to each tag.
- */
- void quantize(HuffmanTable huffmanTable) {
- // Set up default initial quantization parameters. The position and
- // color parameters specify the number of bits for each X, Y, Z, R, G,
- // B, or A component. The normal quantization parameter specifies the
- // number of bits for each U and V component.
- positionQuant = 16 ;
- colorQuant = 9 ;
- normalQuant = 6 ;
-
- // Compute position center and scaling for normalization to the unit
- // cube. This is a volume bounded by the open intervals (-1..1) on
- // each axis.
- center[0] = (mcBounds[1].x + mcBounds[0].x) / 2.0 ;
- center[1] = (mcBounds[1].y + mcBounds[0].y) / 2.0 ;
- center[2] = (mcBounds[1].z + mcBounds[0].z) / 2.0 ;
-
- double xRange = mcBounds[1].x - mcBounds[0].x ;
- double yRange = mcBounds[1].y - mcBounds[0].y ;
- double zRange = mcBounds[1].z - mcBounds[0].z ;
-
- if (xRange > yRange)
- positionRangeMaximum = xRange ;
- else
- positionRangeMaximum = yRange ;
-
- if (zRange > positionRangeMaximum)
- positionRangeMaximum = zRange ;
-
- // Adjust the range of the unit cube to match the default
- // quantization.
- //
- // This scale factor along with the center values computed above will
- // produce 16-bit integer representations of the floating point
- // position coordinates ranging symmetrically about 0 from -32767 to
- // +32767. -32768 is not used and the normalized floating point
- // position coordinates of -1.0 as well as +1.0 will not be
- // represented.
- //
- // Applications which wish to seamlessly stitch together compressed
- // objects will need to be aware that the range of normalized
- // positions will be one quantum away from the [-1..1] endpoints of
- // the unit cube and should adjust scale factors accordingly.
- scale = (2.0 / positionRangeMaximum) * (32767.0 / 32768.0) ;
-
- // Flag quantization change.
- positionQuantChanged = colorQuantChanged = normalQuantChanged = true ;
-
- // Flag first position, color, and normal.
- firstPosition = firstColor = firstNormal = true ;
-
- // Apply quantization.
- Iterator i = stream.iterator() ;
- while (i.hasNext()) {
- Object o = i.next() ;
-
- if (o instanceof CompressionStreamElement) {
- ((CompressionStreamElement)o).quantize(this, huffmanTable) ;
-
- // Keep track of whether last two elements were colors or
- // normals for mesh buffer component substitution semantics.
- lastLastElementColor = lastElementColor ;
- lastLastElementNormal = lastElementNormal ;
- lastElementColor = lastElementNormal = false ;
-
- if (o instanceof CompressionStreamColor)
- lastElementColor = true ;
- else if (o instanceof CompressionStreamNormal)
- lastElementNormal = true ;
- }
- }
-
- // Compute the bounds in normalized coordinates.
- ncBounds[0].x = (double)qcBounds[0].x / 32768.0 ;
- ncBounds[0].y = (double)qcBounds[0].y / 32768.0 ;
- ncBounds[0].z = (double)qcBounds[0].z / 32768.0 ;
-
- ncBounds[1].x = (double)qcBounds[1].x / 32768.0 ;
- ncBounds[1].y = (double)qcBounds[1].y / 32768.0 ;
- ncBounds[1].z = (double)qcBounds[1].z / 32768.0 ;
- }
-
- /**
- * Iterates across all compression stream elements and builds the
- * compressed geometry command stream output.
- *
- * @param huffmanTable Table which maps geometric elements in this stream
- * to tags describing the encoding parameters (length, shift, and
- * absolute/relative status) to be used for their representations in the
- * compressed output. All tags must be 6 bits or less in length, and the
- * sum of the number of bits in the tag plus the number of bits in the
- * data it describes must be at least 6 bits in length.
- *
- * @param outputBuffer CommandStream to use for collecting the compressed
- * bits.
- */
- void outputCommands(HuffmanTable huffmanTable, CommandStream outputBuffer) {
- //
- // The first command output is setState to indicate what data is
- // bundled with each vertex. Although the semantics of geometry
- // decompression allow setState to appear anywhere in the stream, this
- // cannot be handled by the current Java 3D software decompressor,
- // which internally decompresses an entire compressed buffer into a
- // single retained object sharing a single consistent vertex format.
- // This limitation may be removed in subsequent releases of Java 3D.
- //
- int bnv = (vertexNormals? 1 : 0) ;
- int bcv = ((vertexColor3 || vertexColor4)? 1 : 0) ;
- int cap = (vertexColor4? 1 : 0) ;
-
- int command = CommandStream.SET_STATE | bnv ;
- long data = (bcv << 2) | (cap << 1) ;
-
- // Output the setState command.
- outputBuffer.addCommand(command, 8, data, 3) ;
-
- // Output the Huffman table commands.
- huffmanTable.outputCommands(outputBuffer) ;
-
- // Output each compression stream element's data.
- Iterator i = stream.iterator() ;
- while (i.hasNext()) {
- Object o = i.next() ;
- if (o instanceof CompressionStreamElement)
- ((CompressionStreamElement)o).outputCommand(huffmanTable,
- outputBuffer) ;
- }
-
- // Finish the header-forwarding interleave and long-word align.
- outputBuffer.end() ;
- }
-
- /**
- * Retrieve the total size of the uncompressed geometric data in bytes,
- * excluding mesh buffer references.
- * @return uncompressed byte count
- */
- int getByteCount() {
- return byteCount ;
- }
-
- /**
- * Retrieve the the number of vertices created for this stream, excluding
- * mesh buffer references.
- * @return vertex count
- */
- int getVertexCount() {
- return vertexCount ;
- }
-
- /**
- * Retrieve the number of mesh buffer references created for this stream.
- * @return mesh buffer reference count
- */
- int getMeshReferenceCount() {
- return meshReferenceCount ;
- }
-
- /**
- * Stream element that sets position quantization during quantize pass.
- */
- private class PositionQuant extends CompressionStreamElement {
- int value ;
-
- PositionQuant(int value) {
- this.value = value ;
- }
-
- @Override
- void quantize(CompressionStream s, HuffmanTable t) {
- positionQuant = value ;
- positionQuantChanged = true ;
-
- // Adjust range of unit cube scaling to match quantization.
- scale = (2.0 / positionRangeMaximum) *
- (((double)((1 << (value-1)) - 1))/((double)(1 << (value-1)))) ;
- }
-
- @Override
- public String toString() {
- return "positionQuant: " + value ;
- }
- }
-
- /**
- * Stream element that sets normal quantization during quantize pass.
- */
- private class NormalQuant extends CompressionStreamElement {
- int value ;
-
- NormalQuant(int value) {
- this.value = value ;
- }
-
- @Override
- void quantize(CompressionStream s, HuffmanTable t) {
- normalQuant = value ;
- normalQuantChanged = true ;
- }
-
- @Override
- public String toString() {
- return "normalQuant: " + value ;
- }
- }
-
- /**
- * Stream element that sets color quantization during quantize pass.
- */
- private class ColorQuant extends CompressionStreamElement {
- int value ;
-
- ColorQuant(int value) {
- this.value = value ;
- }
-
- @Override
- void quantize(CompressionStream s, HuffmanTable t) {
- colorQuant = value ;
- colorQuantChanged = true ;
- }
-
- @Override
- public String toString() {
- return "colorQuant: " + value ;
- }
- }
-
- /**
- * Stream element that references the mesh buffer.
- */
- private class MeshReference extends CompressionStreamElement {
- int stripFlag, meshIndex ;
-
- MeshReference(int stripFlag, int meshIndex) {
- this.stripFlag = stripFlag ;
- this.meshIndex = meshIndex ;
- meshReferenceCount++ ;
- }
-
- @Override
- void quantize(CompressionStream s, HuffmanTable t) {
- // Retrieve the vertex from the mesh buffer mirror and set up the
- // data needed for the next stream element to compute its deltas.
- CompressionStreamVertex v = meshBuffer.getVertex(meshIndex) ;
- lastPosition[0] = v.xAbsolute ;
- lastPosition[1] = v.yAbsolute ;
- lastPosition[2] = v.zAbsolute ;
-
- // Set up last color data if it exists and previous elements
- // don't override it.
- if (v.color != null && !lastElementColor &&
- !(lastElementNormal && lastLastElementColor)) {
- lastColor[0] = v.color.rAbsolute ;
- lastColor[1] = v.color.gAbsolute ;
- lastColor[2] = v.color.bAbsolute ;
- lastColor[3] = v.color.aAbsolute ;
- }
-
- // Set up last normal data if it exists and previous element
- // doesn't override it.
- if (v.normal != null && !lastElementNormal &&
- !(lastElementColor && lastLastElementNormal)) {
- lastSextant = v.normal.sextant ;
- lastOctant = v.normal.octant ;
- lastU = v.normal.uAbsolute ;
- lastV = v.normal.vAbsolute ;
- lastSpecialNormal = v.normal.specialNormal ;
- }
- }
-
- @Override
- void outputCommand(HuffmanTable t, CommandStream outputBuffer) {
- int command = CommandStream.MESH_B_R ;
- long data = stripFlag & 0x1 ;
-
- command |= (((meshIndex & 0xf) << 1) | (stripFlag >> 1)) ;
- outputBuffer.addCommand(command, 8, data, 1) ;
- }
-
- @Override
- public String toString() {
- return
- "meshReference: stripFlag " + stripFlag +
- " meshIndex " + meshIndex ;
- }
- }
-
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, int stripFlag) {
- stream.add(new CompressionStreamVertex(this, pos,
- (Vector3f)null, (Color3f)null,
- stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, Vector3f norm, int stripFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, (Color3f)null, stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, Color3f color, int stripFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, Color4f color, int stripFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, Vector3f norm, Color3f color,
- int stripFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, Vector3f norm, Color4f color,
- int stripFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, (Vector3f)null, (Color3f)null, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Vector3f norm,
- int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, (Color3f)null, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Color3f color,
- int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Color4f color,
- int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Vector3f norm, Color3f color,
- int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, color, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Vector3f norm, Color4f color,
- int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, color, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param color color data, either Color3f or Color4f, determined by
- * current vertex format
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Vector3f norm,
- Object color, int stripFlag, int meshFlag) {
-
- if (vertexColor3)
- stream.add(new CompressionStreamVertex
- (this, pos, norm, (Color3f)color, stripFlag, meshFlag)) ;
- else
- stream.add(new CompressionStreamVertex
- (this, pos, norm, (Color4f)color, stripFlag, meshFlag)) ;
- }
-
- /**
- * Add a mesh buffer reference to this stream.
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshIndex index of vertex to retrieve from the mesh buffer
- */
- void addMeshReference(int stripFlag, int meshIndex) {
- stream.add(new MeshReference(stripFlag, meshIndex)) ;
- }
-
- /**
- * Copy the given color to the end of this stream and use it as a global
- * state change that applies to all subsequent vertices.
- */
- void addColor(Color3f c3f) {
- stream.add(new CompressionStreamColor(this, c3f)) ;
- }
-
- /**
- * Copy the given color to the end of this stream and use it as a global
- * state change that applies to all subsequent vertices.
- */
- void addColor(Color4f c4f) {
- stream.add(new CompressionStreamColor(this, c4f)) ;
- }
-
- /**
- * Copy the given normal to the end of this stream and use it as a global
- * state change that applies to all subsequent vertices.
- */
- void addNormal(Vector3f n) {
- stream.add(new CompressionStreamNormal(this, n)) ;
- }
-
- /**
- * Add a new position quantization value to the end of this stream that
- * will apply to all subsequent vertex positions.
- *
- * @param value number of bits to quantize each position's X, Y,
- * and Z components, ranging from 1 to 16 with a default of 16
- */
- void addPositionQuantization(int value) {
- stream.add(new PositionQuant(value)) ;
- }
-
- /**
- * Add a new color quantization value to the end of this stream that will
- * apply to all subsequent colors.
- *
- * @param value number of bits to quantize each color's R, G, B, and
- * alpha components, ranging from 2 to 16 with a default of 9
- */
- void addColorQuantization(int value) {
- stream.add(new ColorQuant(value)) ;
- }
-
- /**
- * Add a new normal quantization value to the end of this stream that will
- * apply to all subsequent normals. This value specifies the number of
- * bits for each normal's U and V components.
- *
- * @param value number of bits for quantizing U and V, ranging from 0 to
- * 6 with a default of 6
- */
- void addNormalQuantization(int value) {
- stream.add(new NormalQuant(value)) ;
- }
-
- /**
- * Interface to access GeometryArray vertex components and add them to the
- * compression stream.
- *
- * A processVertex() implementation retrieves vertex components using the
- * appropriate access semantics of a particular GeometryArray, and adds
- * them to the compression stream.
- *
- * The implementation always pushes vertices into the mesh buffer unless
- * they match ones already there; if they do, it generates mesh buffer
- * references instead. This reduces the number of vertices when
- * non-stripped abutting facets are added to the stream.
- *
- * Note: Level II geometry compression semantics allow the mesh buffer
- * normals to be substituted with the value of an immediately
- * preceding SetNormal command, but this is unavailable in Level I.
- *
- * @param index vertex offset from the beginning of its data array
- * @param stripFlag RESTART, REPLACE_MIDDLE, or REPLACE_OLDEST
- */
- private interface GeometryAccessor {
- void processVertex(int index, int stripFlag) ;
- }
-
- /**
- * This class implements the GeometryAccessor interface for geometry
- * arrays accessed with by-copy semantics.
- */
- private class ByCopyGeometry implements GeometryAccessor {
- Point3f[] positions = null ;
- Vector3f[] normals = null ;
- Color3f[] colors3 = null ;
- Color4f[] colors4 = null ;
-
- ByCopyGeometry(GeometryArray ga) {
- this(ga, ga.getInitialVertexIndex(), ga.getValidVertexCount()) ;
- }
-
- ByCopyGeometry(GeometryArray ga,
- int firstVertex, int validVertexCount) {
- int i ;
- positions = new Point3f[validVertexCount] ;
- for (i = 0 ; i < validVertexCount ; i++)
- positions[i] = new Point3f() ;
-
- ga.getCoordinates(firstVertex, positions) ;
-
- if (vertexNormals) {
- normals = new Vector3f[validVertexCount] ;
- for (i = 0 ; i < validVertexCount ; i++)
- normals[i] = new Vector3f() ;
-
- ga.getNormals(firstVertex, normals) ;
- }
-
- if (vertexColor3) {
- colors3 = new Color3f[validVertexCount] ;
- for (i = 0 ; i < validVertexCount ; i++)
- colors3[i] = new Color3f() ;
-
- ga.getColors(firstVertex, colors3) ;
- }
- else if (vertexColor4) {
- colors4 = new Color4f[validVertexCount] ;
- for (i = 0 ; i < validVertexCount ; i++)
- colors4[i] = new Color4f() ;
-
- ga.getColors(firstVertex, colors4) ;
- }
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- Point3f p = positions[v] ;
- int r = meshBuffer.getMeshReference(p) ;
-
- if ((r == meshBuffer.NOT_FOUND) ||
- (vertexNormals && noMeshNormalSubstitution &&
- (! normals[v].equals(meshBuffer.getNormal(r))))) {
-
- Vector3f n = vertexNormals? normals[v] : null ;
- Object c = vertexColor3? (Object)colors3[v] :
- vertexColor4? (Object)colors4[v] : null ;
-
- addVertex(p, n, c, stripFlag, MESH_PUSH) ;
- meshBuffer.push(p, c, n) ;
- }
- else {
- if (vertexNormals && !noMeshNormalSubstitution &&
- (! normals[v].equals(meshBuffer.getNormal(r))))
- addNormal(normals[v]) ;
-
- if (vertexColor3 &&
- (! colors3[v].equals(meshBuffer.getColor3(r))))
- addColor(colors3[v]) ;
-
- else if (vertexColor4 &&
- (! colors4[v].equals(meshBuffer.getColor4(r))))
- addColor(colors4[v]) ;
-
- addMeshReference(stripFlag, r) ;
- }
- }
- }
-
- /**
- * Class which holds index array references for a geometry array.
- */
- private static class IndexArrays {
- int colorIndices[] = null ;
- int normalIndices[] = null ;
- int positionIndices[] = null ;
- }
-
- /**
- * Retrieves index array references for the specified IndexedGeometryArray.
- * Index arrays are copied starting from initialIndexIndex.
- */
- private void getIndexArrays(GeometryArray ga, IndexArrays ia) {
- IndexedGeometryArray iga = (IndexedGeometryArray)ga ;
-
- int initialIndexIndex = iga.getInitialIndexIndex() ;
- int indexCount = iga.getValidIndexCount() ;
- int vertexFormat = iga.getVertexFormat() ;
-
- boolean useCoordIndexOnly = false ;
- if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) {
- if (debug) System.out.println("useCoordIndexOnly") ;
- useCoordIndexOnly = true ;
- }
-
- ia.positionIndices = new int[indexCount] ;
- iga.getCoordinateIndices(initialIndexIndex, ia.positionIndices) ;
-
- if (vertexNormals) {
- if (useCoordIndexOnly) {
- ia.normalIndices = ia.positionIndices ;
- }
- else {
- ia.normalIndices = new int[indexCount] ;
- iga.getNormalIndices(initialIndexIndex, ia.normalIndices) ;
- }
- }
- if (vertexColor3 || vertexColor4) {
- if (useCoordIndexOnly) {
- ia.colorIndices = ia.positionIndices ;
- }
- else {
- ia.colorIndices = new int[indexCount] ;
- iga.getColorIndices(initialIndexIndex, ia.colorIndices) ;
- }
- }
- }
-
- /**
- * Class which holds indices for a specific vertex of an
- * IndexedGeometryArray.
- */
- private static class VertexIndices {
- int pi, ni, ci ;
- }
-
- /**
- * Retrieves vertex indices for a specific vertex in an
- * IndexedGeometryArray.
- */
- private void getVertexIndices(int v, IndexArrays ia, VertexIndices vi) {
- vi.pi = ia.positionIndices[v] ;
- if (vertexNormals)
- vi.ni = ia.normalIndices[v] ;
- if (vertexColors)
- vi.ci = ia.colorIndices[v] ;
- }
-
- /**
- * This class implements the GeometryAccessor interface for indexed
- * geometry arrays accessed with by-copy semantics.
- */
- private class IndexedByCopyGeometry extends ByCopyGeometry {
- IndexArrays ia = new IndexArrays() ;
- VertexIndices vi = new VertexIndices() ;
-
- IndexedByCopyGeometry(GeometryArray ga) {
- super(ga, 0, ga.getVertexCount()) ;
- getIndexArrays(ga, ia) ;
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- getVertexIndices(v, ia, vi) ;
- int r = meshBuffer.getMeshReference(vi.pi) ;
-
- if ((r == meshBuffer.NOT_FOUND) ||
- (vertexNormals && noMeshNormalSubstitution &&
- (vi.ni != meshBuffer.getNormalIndex(r)))) {
-
- Point3f p = positions[vi.pi] ;
- Vector3f n = vertexNormals? normals[vi.ni] : null ;
- Object c = vertexColor3? (Object)colors3[vi.ci] :
- vertexColor4? (Object)colors4[vi.ci] : null ;
-
- addVertex(p, n, c, stripFlag, MESH_PUSH) ;
- meshBuffer.push(vi.pi, vi.ci, vi.ni) ;
- }
- else {
- if (vertexNormals && !noMeshNormalSubstitution &&
- vi.ni != meshBuffer.getNormalIndex(r))
- addNormal(normals[vi.ni]) ;
-
- if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r))
- addColor(colors3[vi.ci]) ;
-
- else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r))
- addColor(colors4[vi.ci]) ;
-
- addMeshReference(stripFlag, r) ;
- }
- }
- }
-
- //
- // NOTE: For now, copies are made of all GeometryArray vertex components
- // even when by-reference access is available.
- //
- private static class VertexCopy {
- Object c = null ;
- Point3f p = null ;
- Vector3f n = null ;
- Color3f c3 = null ;
- Color4f c4 = null ;
- }
-
- private void processVertexCopy(VertexCopy vc, int stripFlag) {
- int r = meshBuffer.getMeshReference(vc.p) ;
-
- if ((r == meshBuffer.NOT_FOUND) ||
- (vertexNormals && noMeshNormalSubstitution &&
- (! vc.n.equals(meshBuffer.getNormal(r))))) {
-
- addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ;
- meshBuffer.push(vc.p, vc.c, vc.n) ;
- }
- else {
- if (vertexNormals && !noMeshNormalSubstitution &&
- (! vc.n.equals(meshBuffer.getNormal(r))))
- addNormal(vc.n) ;
-
- if (vertexColor3 && (! vc.c3.equals(meshBuffer.getColor3(r))))
- addColor(vc.c3) ;
-
- else if (vertexColor4 && (! vc.c4.equals(meshBuffer.getColor4(r))))
- addColor(vc.c4) ;
-
- addMeshReference(stripFlag, r) ;
- }
- }
-
- private void processIndexedVertexCopy(VertexCopy vc,
- VertexIndices vi,
- int stripFlag) {
-
- int r = meshBuffer.getMeshReference(vi.pi) ;
-
- if ((r == meshBuffer.NOT_FOUND) ||
- (vertexNormals && noMeshNormalSubstitution &&
- (vi.ni != meshBuffer.getNormalIndex(r)))) {
-
- addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ;
- meshBuffer.push(vi.pi, vi.ci, vi.ni) ;
- }
- else {
- if (vertexNormals && !noMeshNormalSubstitution &&
- vi.ni != meshBuffer.getNormalIndex(r))
- addNormal(vc.n) ;
-
- if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r))
- addColor(vc.c3) ;
-
- else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r))
- addColor(vc.c4) ;
-
- addMeshReference(stripFlag, r) ;
- }
- }
-
- /**
- * This abstract class implements the GeometryAccessor interface for
- * concrete subclasses which handle float and NIO interleaved geometry
- * arrays.
- */
- private abstract class InterleavedGeometry implements GeometryAccessor {
- VertexCopy vc = new VertexCopy() ;
-
- int vstride = 0 ;
- int coffset = 0 ;
- int noffset = 0 ;
- int poffset = 0 ;
- int tstride = 0 ;
- int tcount = 0 ;
-
- InterleavedGeometry(GeometryArray ga) {
- if (vertexTextures) {
- if (vertexTexture2) tstride = 2 ;
- else if (vertexTexture3) tstride = 3 ;
- else if (vertexTexture4) tstride = 4 ;
-
- tcount = ga.getTexCoordSetCount() ;
- vstride += tcount * tstride ;
- }
-
- if (vertexColors) {
- coffset = vstride ;
- if (vertexColor3) vstride += 3 ;
- else vstride += 4 ;
- }
-
- if (vertexNormals) {
- noffset = vstride ;
- vstride += 3 ;
- }
-
- poffset = vstride ;
- vstride += 3 ;
- }
-
- abstract void copyVertex(int pi, int ni, int ci, VertexCopy vc) ;
-
- @Override
- public void processVertex(int v, int stripFlag) {
- copyVertex(v, v, v, vc) ;
- processVertexCopy(vc, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for float
- * interleaved geometry arrays.
- */
- private class InterleavedGeometryFloat extends InterleavedGeometry {
- float[] vdata = null ;
-
- InterleavedGeometryFloat(GeometryArray ga) {
- super(ga) ;
- vdata = ga.getInterleavedVertices() ;
- }
-
- @Override
- void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
- int voffset ;
- voffset = pi * vstride ;
- vc.p = new Point3f(vdata[voffset + poffset + 0],
- vdata[voffset + poffset + 1],
- vdata[voffset + poffset + 2]) ;
-
- if (vertexNormals) {
- voffset = ni * vstride ;
- vc.n = new Vector3f(vdata[voffset + noffset + 0],
- vdata[voffset + noffset + 1],
- vdata[voffset + noffset + 2]) ;
- }
- if (vertexColor3) {
- voffset = ci * vstride ;
- vc.c3 = new Color3f(vdata[voffset + coffset + 0],
- vdata[voffset + coffset + 1],
- vdata[voffset + coffset + 2]) ;
- vc.c = vc.c3 ;
- }
- else if (vertexColor4) {
- voffset = ci * vstride ;
- vc.c4 = new Color4f(vdata[voffset + coffset + 0],
- vdata[voffset + coffset + 1],
- vdata[voffset + coffset + 2],
- vdata[voffset + coffset + 3]) ;
- vc.c = vc.c4 ;
- }
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for indexed
- * interleaved geometry arrays.
- */
- private class IndexedInterleavedGeometryFloat
- extends InterleavedGeometryFloat {
-
- IndexArrays ia = new IndexArrays() ;
- VertexIndices vi = new VertexIndices() ;
-
- IndexedInterleavedGeometryFloat(GeometryArray ga) {
- super(ga) ;
- getIndexArrays(ga, ia) ;
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- getVertexIndices(v, ia, vi) ;
- copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
- processIndexedVertexCopy(vc, vi, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for
- * interleaved NIO geometry arrays.
- */
- private class InterleavedGeometryNIO extends InterleavedGeometry {
- FloatBuffer fbw = null ;
-
- InterleavedGeometryNIO(GeometryArray ga) {
- super(ga) ;
- J3DBuffer buffer = ga.getInterleavedVertexBuffer() ;
- if (BufferWrapper.getBufferType(buffer) ==
- BufferWrapper.TYPE_FLOAT) {
- fbw = (FloatBuffer)buffer.getBuffer();
- }
- else {
- throw new IllegalArgumentException
- ("\ninterleaved vertex buffer must be FloatBuffer") ;
- }
- }
-
- @Override
- void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
- int voffset ;
- voffset = pi * vstride ;
- vc.p = new Point3f(fbw.get(voffset + poffset + 0),
- fbw.get(voffset + poffset + 1),
- fbw.get(voffset + poffset + 2)) ;
-
- if (vertexNormals) {
- voffset = ni * vstride ;
- vc.n = new Vector3f(fbw.get(voffset + noffset + 0),
- fbw.get(voffset + noffset + 1),
- fbw.get(voffset + noffset + 2)) ;
- }
- if (vertexColor3) {
- voffset = ci * vstride ;
- vc.c3 = new Color3f(fbw.get(voffset + coffset + 0),
- fbw.get(voffset + coffset + 1),
- fbw.get(voffset + coffset + 2)) ;
- vc.c = vc.c3 ;
- }
- else if (vertexColor4) {
- voffset = ci * vstride ;
- vc.c4 = new Color4f(fbw.get(voffset + coffset + 0),
- fbw.get(voffset + coffset + 1),
- fbw.get(voffset + coffset + 2),
- fbw.get(voffset + coffset + 3)) ;
- vc.c = vc.c4 ;
- }
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for indexed
- * interleaved NIO geometry arrays.
- */
- private class IndexedInterleavedGeometryNIO extends InterleavedGeometryNIO {
- IndexArrays ia = new IndexArrays() ;
- VertexIndices vi = new VertexIndices() ;
-
- IndexedInterleavedGeometryNIO(GeometryArray ga) {
- super(ga) ;
- getIndexArrays(ga, ia) ;
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- getVertexIndices(v, ia, vi) ;
- copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
- processIndexedVertexCopy(vc, vi, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for
- * non-interleaved geometry arrays accessed with by-reference semantics.
- */
- private class ByRefGeometry implements GeometryAccessor {
- VertexCopy vc = new VertexCopy() ;
-
- byte[] colorsB = null ;
- float[] colorsF = null ;
- float[] normals = null ;
- float[] positionsF = null ;
- double[] positionsD = null ;
-
- int initialPositionIndex = 0 ;
- int initialNormalIndex = 0 ;
- int initialColorIndex = 0 ;
-
- ByRefGeometry(GeometryArray ga) {
- positionsF = ga.getCoordRefFloat() ;
- if (debug && positionsF != null)
- System.out.println("float positions") ;
-
- positionsD = ga.getCoordRefDouble() ;
- if (debug && positionsD != null)
- System.out.println("double positions") ;
-
- if (positionsF == null && positionsD == null)
- throw new UnsupportedOperationException
- ("\nby-reference access to Point3{d,f} arrays") ;
-
- initialPositionIndex = ga.getInitialCoordIndex() ;
-
- if (vertexColors) {
- colorsB = ga.getColorRefByte() ;
- if (debug && colorsB != null)
- System.out.println("byte colors") ;
-
- colorsF = ga.getColorRefFloat() ;
- if (debug && colorsF != null)
- System.out.println("float colors") ;
-
- if (colorsB == null && colorsF == null)
- throw new UnsupportedOperationException
- ("\nby-reference access to Color{3b,3f,4b,4f} arrays") ;
-
- initialColorIndex = ga.getInitialColorIndex() ;
- }
-
- if (vertexNormals) {
- normals = ga.getNormalRefFloat() ;
- if (debug && normals != null)
- System.out.println("float normals") ;
-
- if (normals == null)
- throw new UnsupportedOperationException
- ("\nby-reference access to Normal3f array") ;
-
- initialNormalIndex = ga.getInitialNormalIndex() ;
- }
- }
-
- void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
- pi *= 3 ;
- if (positionsF != null) {
- vc.p = new Point3f(positionsF[pi + 0],
- positionsF[pi + 1],
- positionsF[pi + 2]) ;
- }
- else {
- vc.p = new Point3f((float)positionsD[pi + 0],
- (float)positionsD[pi + 1],
- (float)positionsD[pi + 2]) ;
- }
-
- ni *= 3 ;
- if (vertexNormals) {
- vc.n = new Vector3f(normals[ni + 0],
- normals[ni + 1],
- normals[ni + 2]) ;
- }
-
- if (vertexColor3) {
- ci *= 3 ;
- if (colorsB != null) {
- vc.c3 = new Color3f
- ((colorsB[ci + 0] & 0xff) * ByteToFloatScale,
- (colorsB[ci + 1] & 0xff) * ByteToFloatScale,
- (colorsB[ci + 2] & 0xff) * ByteToFloatScale) ;
- }
- else {
- vc.c3 = new Color3f(colorsF[ci + 0],
- colorsF[ci + 1],
- colorsF[ci + 2]) ;
- }
- vc.c = vc.c3 ;
- }
- else if (vertexColor4) {
- ci *= 4 ;
- if (colorsB != null) {
- vc.c4 = new Color4f
- ((colorsB[ci + 0] & 0xff) * ByteToFloatScale,
- (colorsB[ci + 1] & 0xff) * ByteToFloatScale,
- (colorsB[ci + 2] & 0xff) * ByteToFloatScale,
- (colorsB[ci + 3] & 0xff) * ByteToFloatScale) ;
- }
- else {
- vc.c4 = new Color4f(colorsF[ci + 0],
- colorsF[ci + 1],
- colorsF[ci + 2],
- colorsF[ci + 3]) ;
- }
- vc.c = vc.c4 ;
- }
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- copyVertex(v + initialPositionIndex,
- v + initialNormalIndex,
- v + initialColorIndex, vc) ;
-
- processVertexCopy(vc, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for indexed
- * non-interleaved geometry arrays accessed with by-reference semantics.
- */
- private class IndexedByRefGeometry extends ByRefGeometry {
- IndexArrays ia = new IndexArrays() ;
- VertexIndices vi = new VertexIndices() ;
-
- IndexedByRefGeometry(GeometryArray ga) {
- super(ga) ;
- getIndexArrays(ga, ia) ;
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- getVertexIndices(v, ia, vi) ;
- copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
- processIndexedVertexCopy(vc, vi, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for
- * non-interleaved geometry arrays accessed with NIO.
- */
- private class ByRefGeometryNIO implements GeometryAccessor {
- VertexCopy vc = new VertexCopy() ;
-
- ByteBuffer colorsB = null ;
- FloatBuffer colorsF = null ;
- FloatBuffer normals = null ;
- FloatBuffer positionsF = null ;
- DoubleBuffer positionsD = null ;
-
- int initialPositionIndex = 0 ;
- int initialNormalIndex = 0 ;
- int initialColorIndex = 0 ;
-
- ByRefGeometryNIO(GeometryArray ga) {
- J3DBuffer buffer ;
- buffer = ga.getCoordRefBuffer() ;
- initialPositionIndex = ga.getInitialCoordIndex() ;
-
- switch (BufferWrapper.getBufferType(buffer)) {
- case BufferWrapper.TYPE_FLOAT:
- positionsF = (FloatBuffer)buffer.getBuffer();
- if (debug) System.out.println("float positions buffer") ;
- break ;
- case BufferWrapper.TYPE_DOUBLE:
- positionsD = (DoubleBuffer)buffer.getBuffer();
- if (debug) System.out.println("double positions buffer") ;
- break ;
- default:
- throw new IllegalArgumentException
- ("\nposition buffer must be FloatBuffer or DoubleBuffer") ;
- }
-
- if (vertexColors) {
- buffer = ga.getColorRefBuffer() ;
- initialColorIndex = ga.getInitialColorIndex() ;
-
- switch (BufferWrapper.getBufferType(buffer)) {
- case BufferWrapper.TYPE_BYTE:
- colorsB = (ByteBuffer)buffer.getBuffer();
- if (debug) System.out.println("byte colors buffer") ;
- break ;
- case BufferWrapper.TYPE_FLOAT:
- colorsF = (FloatBuffer)buffer.getBuffer();
- if (debug) System.out.println("float colors buffer") ;
- break ;
- default:
- throw new IllegalArgumentException
- ("\ncolor buffer must be ByteBuffer or FloatBuffer") ;
- }
- }
-
- if (vertexNormals) {
- buffer = ga.getNormalRefBuffer() ;
- initialNormalIndex = ga.getInitialNormalIndex() ;
-
- switch (BufferWrapper.getBufferType(buffer)) {
- case BufferWrapper.TYPE_FLOAT:
- normals = (FloatBuffer)buffer.getBuffer();
- if (debug) System.out.println("float normals buffer") ;
- break ;
- default:
- throw new IllegalArgumentException
- ("\nnormal buffer must be FloatBuffer") ;
- }
- }
- }
-
- void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
- pi *= 3 ;
- if (positionsF != null) {
- vc.p = new Point3f(positionsF.get(pi + 0),
- positionsF.get(pi + 1),
- positionsF.get(pi + 2)) ;
- }
- else {
- vc.p = new Point3f((float)positionsD.get(pi + 0),
- (float)positionsD.get(pi + 1),
- (float)positionsD.get(pi + 2)) ;
- }
-
- ni *= 3 ;
- if (vertexNormals) {
- vc.n = new Vector3f(normals.get(ni + 0),
- normals.get(ni + 1),
- normals.get(ni + 2)) ;
- }
-
- if (vertexColor3) {
- ci *= 3 ;
- if (colorsB != null) {
- vc.c3 = new Color3f
- ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale,
- (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale,
- (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale) ;
- }
- else {
- vc.c3 = new Color3f(colorsF.get(ci + 0),
- colorsF.get(ci + 1),
- colorsF.get(ci + 2)) ;
- }
- vc.c = vc.c3 ;
- }
- else if (vertexColor4) {
- ci *= 4 ;
- if (colorsB != null) {
- vc.c4 = new Color4f
- ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale,
- (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale,
- (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale,
- (colorsB.get(ci + 3) & 0xff) * ByteToFloatScale) ;
- }
- else {
- vc.c4 = new Color4f(colorsF.get(ci + 0),
- colorsF.get(ci + 1),
- colorsF.get(ci + 2),
- colorsF.get(ci + 3)) ;
- }
- vc.c = vc.c4 ;
- }
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- copyVertex(v + initialPositionIndex,
- v + initialNormalIndex,
- v + initialColorIndex, vc) ;
-
- processVertexCopy(vc, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for
- * non-interleaved indexed geometry arrays accessed with NIO.
- */
- private class IndexedByRefGeometryNIO extends ByRefGeometryNIO {
- IndexArrays ia = new IndexArrays() ;
- VertexIndices vi = new VertexIndices() ;
-
- IndexedByRefGeometryNIO(GeometryArray ga) {
- super(ga) ;
- getIndexArrays(ga, ia) ;
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- getVertexIndices(v, ia, vi) ;
- copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
- processIndexedVertexCopy(vc, vi, stripFlag) ;
- }
- }
-
- /**
- * Convert a GeometryArray to compression stream elements and add them to
- * this stream.
- *
- * @param ga GeometryArray to convert
- * @exception IllegalArgumentException if GeometryArray has a
- * dimensionality or vertex format inconsistent with the CompressionStream
- */
- void addGeometryArray(GeometryArray ga) {
- int firstVertex = 0 ;
- int validVertexCount = 0 ;
- int vertexFormat = ga.getVertexFormat() ;
- GeometryAccessor geometryAccessor = null ;
-
- if (streamType != getStreamType(ga))
- throw new IllegalArgumentException
- ("GeometryArray has inconsistent dimensionality") ;
-
- if (vertexComponents != getVertexComponents(vertexFormat))
- throw new IllegalArgumentException
- ("GeometryArray has inconsistent vertex components") ;
-
- // Set up for vertex data access semantics.
- boolean NIO = (vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 ;
- boolean byRef = (vertexFormat & GeometryArray.BY_REFERENCE) != 0 ;
- boolean interleaved = (vertexFormat & GeometryArray.INTERLEAVED) != 0 ;
- boolean indexedGeometry = ga instanceof IndexedGeometryArray ;
-
- if (indexedGeometry) {
- if (debug) System.out.println("indexed") ;
- // Index arrays will be copied such that valid indices start at
- // offset 0 in the copied arrays.
- firstVertex = 0 ;
- validVertexCount = ((IndexedGeometryArray)ga).getValidIndexCount() ;
- }
-
- if (!byRef) {
- if (debug) System.out.println("by-copy") ;
- if (indexedGeometry) {
- geometryAccessor = new IndexedByCopyGeometry(ga) ;
- }
- else {
- firstVertex = 0 ;
- validVertexCount = ga.getValidVertexCount() ;
- geometryAccessor = new ByCopyGeometry(ga) ;
- }
- }
- else if (interleaved && NIO) {
- if (debug) System.out.println("interleaved NIO") ;
- if (indexedGeometry) {
- geometryAccessor = new IndexedInterleavedGeometryNIO(ga) ;
- }
- else {
- firstVertex = ga.getInitialVertexIndex() ;
- validVertexCount = ga.getValidVertexCount() ;
- geometryAccessor = new InterleavedGeometryNIO(ga) ;
- }
- }
- else if (interleaved && !NIO) {
- if (debug) System.out.println("interleaved") ;
- if (indexedGeometry) {
- geometryAccessor = new IndexedInterleavedGeometryFloat(ga) ;
- }
- else {
- firstVertex = ga.getInitialVertexIndex() ;
- validVertexCount = ga.getValidVertexCount() ;
- geometryAccessor = new InterleavedGeometryFloat(ga) ;
- }
- }
- else if (!interleaved && NIO) {
- if (debug) System.out.println("non-interleaved NIO") ;
- if (indexedGeometry) {
- geometryAccessor = new IndexedByRefGeometryNIO(ga) ;
- }
- else {
- firstVertex = 0 ;
- validVertexCount = ga.getValidVertexCount() ;
- geometryAccessor = new ByRefGeometryNIO(ga) ;
- }
- }
- else if (!interleaved && !NIO) {
- if (debug) System.out.println("non-interleaved by-ref") ;
- if (indexedGeometry) {
- geometryAccessor = new IndexedByRefGeometry(ga) ;
- }
- else {
- firstVertex = 0 ;
- validVertexCount = ga.getValidVertexCount() ;
- geometryAccessor = new ByRefGeometry(ga) ;
- }
- }
-
- // Set up for topology.
- int stripCount = 0 ;
- int stripCounts[] = null ;
- int constantStripLength = 0 ;
- int replaceCode = RESTART ;
- boolean strips = false ;
- boolean implicitStrips = false ;
-
- if (ga instanceof TriangleStripArray ||
- ga instanceof IndexedTriangleStripArray ||
- ga instanceof LineStripArray ||
- ga instanceof IndexedLineStripArray) {
-
- strips = true ;
- replaceCode = REPLACE_OLDEST ;
- if (debug) System.out.println("strips") ;
- }
- else if (ga instanceof TriangleFanArray ||
- ga instanceof IndexedTriangleFanArray) {
-
- strips = true ;
- replaceCode = REPLACE_MIDDLE ;
- if (debug) System.out.println("fans") ;
- }
- else if (ga instanceof QuadArray ||
- ga instanceof IndexedQuadArray) {
-
- // Handled as fan arrays with 4 vertices per fan.
- implicitStrips = true ;
- constantStripLength = 4 ;
- replaceCode = REPLACE_MIDDLE ;
- if (debug) System.out.println("quads") ;
- }
-
- // Get strip counts.
- if (strips) {
- if (indexedGeometry) {
- IndexedGeometryStripArray igsa ;
- igsa = (IndexedGeometryStripArray)ga ;
-
- stripCount = igsa.getNumStrips() ;
- stripCounts = new int[stripCount] ;
- igsa.getStripIndexCounts(stripCounts) ;
-
- } else {
- GeometryStripArray gsa ;
- gsa = (GeometryStripArray)ga ;
-
- stripCount = gsa.getNumStrips() ;
- stripCounts = new int[stripCount] ;
- gsa.getStripVertexCounts(stripCounts) ;
- }
- }
-
- // Build the compression stream for this shape's geometry.
- int v = firstVertex ;
- if (strips) {
- for (int i = 0 ; i < stripCount ; i++) {
- geometryAccessor.processVertex(v++, RESTART) ;
- for (int j = 1 ; j < stripCounts[i] ; j++) {
- geometryAccessor.processVertex(v++, replaceCode) ;
- }
- }
- }
- else if (implicitStrips) {
- while (v < firstVertex + validVertexCount) {
- geometryAccessor.processVertex(v++, RESTART) ;
- for (int j = 1 ; j < constantStripLength ; j++) {
- geometryAccessor.processVertex(v++, replaceCode) ;
- }
- }
- }
- else {
- while (v < firstVertex + validVertexCount) {
- geometryAccessor.processVertex(v++, RESTART) ;
- }
- }
- }
-
- /**
- * Print the stream to standard output.
- */
- void print() {
- System.out.println("\nstream has " + stream.size() + " entries") ;
- System.out.println("uncompressed size " + byteCount + " bytes") ;
- System.out.println("upper position bound: " + mcBounds[1].toString()) ;
- System.out.println("lower position bound: " + mcBounds[0].toString()) ;
- System.out.println("X, Y, Z centers (" +
- ((float)center[0]) + " " +
- ((float)center[1]) + " " +
- ((float)center[2]) + ")\n" +
- "scale " + ((float)scale) + "\n") ;
-
- Iterator i = stream.iterator() ;
- while (i.hasNext()) {
- System.out.println(i.next().toString() + "\n") ;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////
- // //
- // The following constructors and methods are currently the only public //
- // members of this class. All other members are subject to revision. //
- // //
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Creates a CompressionStream from an array of Shape3D scene graph
- * objects. These Shape3D objects may only consist of a GeometryArray
- * component and an optional Appearance component. The resulting stream
- * may be used as input to the GeometryCompressor methods.
- *
- * Each Shape3D in the array must be of the same dimensionality (point,
- * line, or surface) and have the same vertex format as the others.
- * Texture coordinates are ignored.
- *
- * If a color is specified in the material attributes for a Shape3D then
- * that color is added to the CompressionStream as the current global
- * color. Subsequent colors as well as any colors bundled with vertices
- * will override it. Only the material diffuse colors are used; all other
- * appearance attributes are ignored.
- *
- * @param positionQuant
- * number of bits to quantize each position's X, Y,
- * and Z components, ranging from 1 to 16
- *
- * @param colorQuant
- * number of bits to quantize each color's R, G, B, and
- * alpha components, ranging from 2 to 16
- *
- * @param normalQuant
- * number of bits for quantizing each normal's U and V components, ranging
- * from 0 to 6
- *
- * @param shapes
- * an array of Shape3D scene graph objects containing
- * GeometryArray objects, all with the same vertex format and
- * dimensionality
- *
- * @exception IllegalArgumentException if any Shape3D has an inconsistent
- * dimensionality or vertex format, or if any Shape3D contains a geometry
- * component that is not a GeometryArray
- *
- * @see Shape3D
- * @see GeometryArray
- * @see GeometryCompressor
- */
- public CompressionStream(int positionQuant, int colorQuant,
- int normalQuant, Shape3D shapes[]) {
- this() ;
- if (debug) System.out.println("CompressionStream(Shape3D[]):") ;
-
- if (shapes == null)
- throw new IllegalArgumentException("null Shape3D array") ;
-
- if (shapes.length == 0)
- throw new IllegalArgumentException("zero-length Shape3D array") ;
-
- if (shapes[0] == null)
- throw new IllegalArgumentException("Shape3D at index 0 is null") ;
-
- long startTime = 0 ;
- if (benchmark) startTime = System.currentTimeMillis() ;
-
- Geometry g = shapes[0].getGeometry() ;
- if (! (g instanceof GeometryArray))
- throw new IllegalArgumentException
- ("Shape3D at index 0 is not a GeometryArray") ;
-
- GeometryArray ga = (GeometryArray)g ;
- this.streamType = getStreamType(ga) ;
- this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ;
-
- // Add global quantization parameters to the start of the stream.
- addPositionQuantization(positionQuant) ;
- addColorQuantization(colorQuant) ;
- addNormalQuantization(normalQuant) ;
-
- // Loop through all shapes.
- for (int s = 0 ; s < shapes.length ; s++) {
- if (debug) System.out.println("\nShape3D " + s + ":") ;
-
- g = shapes[s].getGeometry() ;
- if (! (g instanceof GeometryArray))
- throw new IllegalArgumentException
- ("Shape3D at index " + s + " is not a GeometryArray") ;
-
- // Check for material color and add it to the stream if it exists.
- Appearance a = shapes[s].getAppearance() ;
- if (a != null) {
- Material m = a.getMaterial() ;
- if (m != null) {
- m.getDiffuseColor(c3f) ;
- if (vertexColor4) {
- c4f.set(c3f.x, c3f.y, c3f.z, 1.0f) ;
- addColor(c4f) ;
- } else
- addColor(c3f) ;
- }
- }
-
- // Add the geometry array to the stream.
- addGeometryArray((GeometryArray)g) ;
- }
-
- if (benchmark) {
- long t = System.currentTimeMillis() - startTime ;
- System.out.println
- ("\nCompressionStream:\n" + shapes.length + " shapes in " +
- (t / 1000f) + " sec") ;
- }
- }
-
- /**
- * Creates a CompressionStream from an array of Shape3D scene graph
- * objects. These Shape3D objects may only consist of a GeometryArray
- * component and an optional Appearance component. The resulting stream
- * may be used as input to the GeometryCompressor methods.
- *
- * Each Shape3D in the array must be of the same dimensionality (point,
- * line, or surface) and have the same vertex format as the others.
- * Texture coordinates are ignored.
- *
- * If a color is specified in the material attributes for a Shape3D then
- * that color is added to the CompressionStream as the current global
- * color. Subsequent colors as well as any colors bundled with vertices
- * will override it. Only the material diffuse colors are used; all other
- * appearance attributes are ignored.
- *
- * Defaults of 16, 9, and 6 bits are used as the quantization values for
- * positions, colors, and normals respectively. These are the maximum
- * resolution values defined for positions and normals; the default of 9
- * for color is the equivalent of the 8 bits of RGBA component resolution
- * commonly available in graphics frame buffers.
- *
- * @param shapes
- * an array of Shape3D scene graph objects containing
- * GeometryArray objects, all with the same vertex format and
- * dimensionality.
- *
- * @exception IllegalArgumentException if any Shape3D has an inconsistent
- * dimensionality or vertex format, or if any Shape3D contains a geometry
- * component that is not a GeometryArray
- *
- * @see Shape3D
- * @see GeometryArray
- * @see GeometryCompressor
- */
- public CompressionStream(Shape3D shapes[]) {
- this(16, 9, 6, shapes) ;
- }
-
- /**
- * Creates a CompressionStream from an array of GeometryInfo objects. The
- * resulting stream may be used as input to the GeometryCompressor
- * methods.
- *
- * Each GeometryInfo in the array must be of the same dimensionality
- * (point, line, or surface) and have the same vertex format as the
- * others. Texture coordinates are ignored.
- *
- * @param positionQuant
- * number of bits to quantize each position's X, Y,
- * and Z components, ranging from 1 to 16
- *
- * @param colorQuant
- * number of bits to quantize each color's R, G, B, and
- * alpha components, ranging from 2 to 16
- *
- * @param normalQuant
- * number of bits for quantizing each normal's U and V components, ranging
- * from 0 to 6
- *
- * @param geometry
- * an array of GeometryInfo objects, all with the same
- * vertex format and dimensionality
- *
- * @exception IllegalArgumentException if any GeometryInfo object has an
- * inconsistent dimensionality or vertex format
- *
- * @see GeometryInfo
- * @see GeometryCompressor
- */
- public CompressionStream(int positionQuant, int colorQuant,
- int normalQuant, GeometryInfo geometry[]) {
- this() ;
- if (debug) System.out.println("CompressionStream(GeometryInfo[])") ;
-
- if (geometry == null)
- throw new IllegalArgumentException("null GeometryInfo array") ;
-
- if (geometry.length == 0)
- throw new IllegalArgumentException
- ("zero-length GeometryInfo array") ;
-
- if (geometry[0] == null)
- throw new IllegalArgumentException
- ("GeometryInfo at index 0 is null") ;
-
- long startTime = 0 ;
- if (benchmark) startTime = System.currentTimeMillis() ;
-
- GeometryArray ga = geometry[0].getGeometryArray() ;
- this.streamType = getStreamType(ga) ;
- this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ;
-
- // Add global quantization parameters to the start of the stream.
- addPositionQuantization(positionQuant) ;
- addColorQuantization(colorQuant) ;
- addNormalQuantization(normalQuant) ;
-
- // Loop through all GeometryInfo objects and add them to the stream.
- for (int i = 0 ; i < geometry.length ; i++) {
- if (debug) System.out.println("\nGeometryInfo " + i + ":") ;
- addGeometryArray(geometry[i].getGeometryArray()) ;
- }
-
- if (benchmark) {
- long t = System.currentTimeMillis() - startTime ;
- System.out.println
- ("\nCompressionStream:\n" + geometry.length +
- " GeometryInfo objects in " + (t / 1000f) + " sec") ;
- }
- }
-
- /**
- * Creates a CompressionStream from an array of GeometryInfo objects. The
- * resulting stream may be used as input to the GeometryCompressor
- * methods.
- *
- * Each GeometryInfo in the array must be of the same dimensionality
- * (point, line, or surface) and have the same vertex format as the
- * others. Texture coordinates are ignored.
- *
- * Defaults of 16, 9, and 6 bits are used as the quantization values for
- * positions, colors, and normals respectively. These are the maximum
- * resolution values defined for positions and normals; the default of 9
- * for color is the equivalent of the 8 bits of RGBA component resolution
- * commonly available in graphics frame buffers.
- *
- * @param geometry
- * an array of GeometryInfo objects, all with the same
- * vertex format and dimensionality
- *
- * @exception IllegalArgumentException if any GeometryInfo object has an
- * inconsistent dimensionality or vertex format
- *
- * @see GeometryInfo
- * @see GeometryCompressor
- */
- public CompressionStream(GeometryInfo geometry[]) {
- this(16, 9, 6, geometry) ;
- }
-
- /**
- * Get the original bounds of the coordinate data, in modeling coordinates.
- * Coordinate data is positioned and scaled to a normalized cube after
- * compression.
- *
- * @return Point3d array of length 2, where the 1st Point3d is the lower
- * bounds and the 2nd Point3d is the upper bounds.
- * @since Java 3D 1.3
- */
- public Point3d[] getModelBounds() {
- Point3d[] bounds = new Point3d[2] ;
- bounds[0] = new Point3d(mcBounds[0]) ;
- bounds[1] = new Point3d(mcBounds[1]) ;
- return bounds ;
- }
-
- /**
- * Get the bounds of the compressed object in normalized coordinates.
- * These have an maximum bounds by [-1.0 .. +1.0] across each axis.
- *
- * @return Point3d array of length 2, where the 1st Point3d is the lower
- * bounds and the 2nd Point3d is the upper bounds.
- * @since Java 3D 1.3
- */
- public Point3d[] getNormalizedBounds() {
- Point3d[] bounds = new Point3d[2] ;
- bounds[0] = new Point3d(ncBounds[0]) ;
- bounds[1] = new Point3d(ncBounds[1]) ;
- return bounds ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamColor.java b/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamColor.java
deleted file mode 100644
index 674eb96..0000000
--- a/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamColor.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.compression;
-
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4f;
-
-/**
- * This class represents a color in a compression stream. It maintains both
- * floating-point and quantized representations. This color may be bundled
- * with a vertex or exist separately as a global color.
- */
-class CompressionStreamColor extends CompressionStreamElement {
- private int R, G, B, A ;
- private boolean color3 ;
- private boolean color4 ;
- private float colorR, colorG, colorB, colorA ;
-
- int rAbsolute, gAbsolute, bAbsolute, aAbsolute ;
-
- /**
- * Create a CompressionStreamColor.
- *
- * @param stream CompressionStream associated with this element
- * @param color3 floating-point representation to be encoded
- */
- CompressionStreamColor(CompressionStream stream, Color3f c3) {
- this.color4 = false ;
- this.color3 = true ;
- colorR = c3.x ;
- colorG = c3.y ;
- colorB = c3.z ;
- colorA = 0.0f ;
- stream.byteCount += 12 ;
- }
-
- /**
- * Create a CompressionStreamColor.
- *
- * @param stream CompressionStream associated with this element
- * @param color4 floating-point representation to be encoded
- */
- CompressionStreamColor(CompressionStream stream, Color4f c4) {
- this.color3 = false ;
- this.color4 = true ;
- colorR = c4.x ;
- colorG = c4.y ;
- colorB = c4.z ;
- colorA = c4.w ;
- stream.byteCount += 16 ;
- }
-
- /**
- * Quantize a floating point color to fixed point integer components of
- * the specified number of bits. The bit length can range from a maximum
- * of 16 to a minimum of 2 bits since negative colors are not defined.
- *
- * The bit length is the total number of bits in the signed version of the
- * fixed point representation of the input color, which is assumed to
- * be normalized into the [0..1) range. With the maximum bit length of
- * 16, 15 bits of positive colors can be represented; a bit length of 9 is
- * needed to get the 8 bit positive color size in common use.
- *
- * @param stream CompressionStream associated with this element
- * @param table HuffmanTable for collecting data about the quantized
- * representation of this element
- */
- @Override
- void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
- // Clamp quantization.
- int quant =
- (stream.colorQuant < 2? 2 :
- (stream.colorQuant > 16? 16 : stream.colorQuant)) ;
-
- absolute = false ;
- if (stream.firstColor || stream.colorQuantChanged) {
- absolute = true ;
- stream.lastColor[0] = 0 ;
- stream.lastColor[1] = 0 ;
- stream.lastColor[2] = 0 ;
- stream.lastColor[3] = 0 ;
- stream.firstColor = false ;
- stream.colorQuantChanged = false ;
- }
-
- // Convert the floating point position to s.15 2's complement.
- if (color3) {
- R = (int)(colorR * 32768.0) ;
- G = (int)(colorG * 32768.0) ;
- B = (int)(colorB * 32768.0) ;
- A = 0 ;
- } else if (color4) {
- R = (int)(colorR * 32768.0) ;
- G = (int)(colorG * 32768.0) ;
- B = (int)(colorB * 32768.0) ;
- A = (int)(colorA * 32768.0) ;
- }
-
- // Clamp color components.
- R = (R > 32767? 32767: (R < 0? 0: R)) ;
- G = (G > 32767? 32767: (G < 0? 0: G)) ;
- B = (B > 32767? 32767: (B < 0? 0: B)) ;
- A = (A > 32767? 32767: (A < 0? 0: A)) ;
-
- // Compute quantized values.
- R &= quantizationMask[quant] ;
- G &= quantizationMask[quant] ;
- B &= quantizationMask[quant] ;
- A &= quantizationMask[quant] ;
-
- // Copy and retain absolute color for mesh buffer lookup.
- rAbsolute = R ;
- gAbsolute = G ;
- bAbsolute = B ;
- aAbsolute = A ;
-
- // Compute deltas.
- R -= stream.lastColor[0] ;
- G -= stream.lastColor[1] ;
- B -= stream.lastColor[2] ;
- A -= stream.lastColor[3] ;
-
- // Update last values.
- stream.lastColor[0] += R ;
- stream.lastColor[1] += G ;
- stream.lastColor[2] += B ;
- stream.lastColor[3] += A ;
-
- // Compute length and shift common to all components.
- if (color3)
- computeLengthShift(R, G, B) ;
-
- else if (color4)
- computeLengthShift(R, G, B, A) ;
-
- // 0-length components are allowed only for normals.
- if (length == 0)
- length = 1 ;
-
- // Add this element to the Huffman table associated with this stream.
- huffmanTable.addColorEntry(length, shift, absolute) ;
- }
-
- /**
- * Output a setColor command.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- @Override
- void outputCommand(HuffmanTable table, CommandStream output) {
- outputColor(table, output, CommandStream.SET_COLOR, 8) ;
- }
-
- /**
- * Output a color subcommand.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- void outputSubcommand(HuffmanTable table, CommandStream output) {
-
- outputColor(table, output, 0, 6) ;
- }
-
- //
- // Output the final compressed bits to the output command stream.
- //
- private void outputColor(HuffmanTable table, CommandStream output,
- int header, int headerLength) {
- HuffmanNode t ;
-
- // Look up the Huffman token for this compression stream element.
- t = table.getColorEntry(length, shift, absolute) ;
-
- // Construct the color subcommand components. The maximum length of a
- // color subcommand is 70 bits (a tag with a length of 6 followed by 4
- // components of 16 bits each). The subcommand is therefore
- // constructed initially using just the first 3 components, with the
- // 4th component added later after the tag has been shifted into the
- // subcommand header.
- int componentLength = t.dataLength - t.shift ;
- int subcommandLength = t.tagLength + (3 * componentLength) ;
-
- R = (R >> t.shift) & (int)lengthMask[componentLength] ;
- G = (G >> t.shift) & (int)lengthMask[componentLength] ;
- B = (B >> t.shift) & (int)lengthMask[componentLength] ;
-
- long colorSubcommand =
- (((long)t.tag) << (3 * componentLength)) |
- (((long)R) << (2 * componentLength)) |
- (((long)G) << (1 * componentLength)) |
- (((long)B) << (0 * componentLength)) ;
-
- if (subcommandLength < 6) {
- // The header will have some empty bits. The Huffman tag
- // computation will prevent this if necessary.
- header |= (int)(colorSubcommand << (6 - subcommandLength)) ;
- subcommandLength = 0 ;
- }
- else {
- // Move the 1st 6 bits of the subcommand into the header.
- header |= (int)(colorSubcommand >>> (subcommandLength - 6)) ;
- subcommandLength -= 6 ;
- }
-
- // Add alpha if present.
- if (color4) {
- A = (A >> t.shift) & (int)lengthMask[componentLength] ;
- colorSubcommand = (colorSubcommand << componentLength) | A ;
- subcommandLength += componentLength ;
- }
-
- // Add the header and body to the output buffer.
- output.addCommand(header, headerLength,
- colorSubcommand, subcommandLength) ;
- }
-
- @Override
- public String toString() {
- String d = absolute? "" : "delta " ;
- String c = (colorR + " " + colorG + " " + colorB +
- (color4? (" " + colorA): "")) ;
-
- return
- "color: " + c + "\n" +
- " fixed point " + d + + R + " " + G + " " + B + "\n" +
- " length " + length + " shift " + shift +
- (absolute? " absolute" : " relative") ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamElement.java b/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamElement.java
deleted file mode 100644
index ed98617..0000000
--- a/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamElement.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.compression;
-
-/**
- * Instances of this class are used as elements in a CompressionStream.
- * @see CompressionStream
- */
-abstract class CompressionStreamElement {
- /**
- * Bit length of quantized geometric components.
- */
- int length ;
-
- /**
- * Number of trailing zeros in quantized geometric components.
- */
- int shift ;
-
- /**
- * If false, geometric component values are represented as differences
- * from those of the preceding element in the stream.
- */
- boolean absolute ;
-
- /**
- * Array with elements that can be used as masks to apply a quantization
- * to the number of bits indicated by the referencing index [0..16].
- */
- static final int quantizationMask[] = {
- 0xFFFF0000, 0xFFFF8000, 0xFFFFC000, 0xFFFFE000,
- 0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00,
- 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0,
- 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE,
- 0xFFFFFFFF
- } ;
-
- /**
- * Array with elements that can be used as masks to retain the number of
- * trailing bits of data indicated by the referencing index [0..64]. Used
- * to clear the leading sign bits of fixed-point 2's complement numbers
- * and in building the compressed output stream.
- */
- static final long lengthMask[] = {
- 0x0000000000000000L, 0x0000000000000001L,
- 0x0000000000000003L, 0x0000000000000007L,
- 0x000000000000000FL, 0x000000000000001FL,
- 0x000000000000003FL, 0x000000000000007FL,
- 0x00000000000000FFL, 0x00000000000001FFL,
- 0x00000000000003FFL, 0x00000000000007FFL,
- 0x0000000000000FFFL, 0x0000000000001FFFL,
- 0x0000000000003FFFL, 0x0000000000007FFFL,
- 0x000000000000FFFFL, 0x000000000001FFFFL,
- 0x000000000003FFFFL, 0x000000000007FFFFL,
- 0x00000000000FFFFFL, 0x00000000001FFFFFL,
- 0x00000000003FFFFFL, 0x00000000007FFFFFL,
- 0x0000000000FFFFFFL, 0x0000000001FFFFFFL,
- 0x0000000003FFFFFFL, 0x0000000007FFFFFFL,
- 0x000000000FFFFFFFL, 0x000000001FFFFFFFL,
- 0x000000003FFFFFFFL, 0x000000007FFFFFFFL,
- 0x00000000FFFFFFFFL, 0x00000001FFFFFFFFL,
- 0x00000003FFFFFFFFL, 0x00000007FFFFFFFFL,
- 0x0000000FFFFFFFFFL, 0x0000001FFFFFFFFFL,
- 0x0000003FFFFFFFFFL, 0x0000007FFFFFFFFFL,
- 0x000000FFFFFFFFFFL, 0x000001FFFFFFFFFFL,
- 0x000003FFFFFFFFFFL, 0x000007FFFFFFFFFFL,
- 0x00000FFFFFFFFFFFL, 0x00001FFFFFFFFFFFL,
- 0x00003FFFFFFFFFFFL, 0x00007FFFFFFFFFFFL,
- 0x0000FFFFFFFFFFFFL, 0x0001FFFFFFFFFFFFL,
- 0x0003FFFFFFFFFFFFL, 0x0007FFFFFFFFFFFFL,
- 0x000FFFFFFFFFFFFFL, 0x001FFFFFFFFFFFFFL,
- 0x003FFFFFFFFFFFFFL, 0x007FFFFFFFFFFFFFL,
- 0x00FFFFFFFFFFFFFFL, 0x01FFFFFFFFFFFFFFL,
- 0x03FFFFFFFFFFFFFFL, 0x07FFFFFFFFFFFFFFL,
- 0x0FFFFFFFFFFFFFFFL, 0x1FFFFFFFFFFFFFFFL,
- 0x3FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL,
- 0xFFFFFFFFFFFFFFFFL
- } ;
-
-
- /**
- * Computes the quantized representation of this stream element.
- *
- * @param stream CompressionStream associated with this element
- * @param table HuffmanTable for collecting data about the quantized
- * representation of this element
- */
- abstract void quantize(CompressionStream stream, HuffmanTable table) ;
-
- /**
- * Outputs the compressed bits representing this stream element.
- * Some instances of CompressionStreamElement don't require an
- * implementation and will inherit the stub provided here.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- void outputCommand(HuffmanTable table, CommandStream output) {
- }
-
- /**
- * Finds the minimum bits needed to represent the given 16-bit signed 2's
- * complement integer. For positive integers, this include the first
- * 1 starting from the left, plus a 0 sign bit; for negative integers,
- * this includes the first 0 starting from the left, plus a 1 sign bit.
- * 0 is a special case returning 0; however, 0-length components are valid
- * ONLY for normals.
- *
- * The decompressor uses the data length to determine how many bits of
- * sign extension to add to the data coming in from the compressed stream
- * in order to create a 16-bit signed 2's complement integer. E.g., a data
- * length of 12 indicates that 16-12=4 bits of sign are to be extended.
- *
- * @param number a signed 2's complement integer representable in 16 bits
- * or less
- * @return minimum number of bits to represent the number
- */
- private static final int getLength(int number) {
- if (number == 0)
- return 0 ;
-
- else if ((number & 0x8000) > 0) {
- // negative numbers
- if ((number & 0x4000) == 0) return 16 ;
- if ((number & 0x2000) == 0) return 15 ;
- if ((number & 0x1000) == 0) return 14 ;
- if ((number & 0x0800) == 0) return 13 ;
- if ((number & 0x0400) == 0) return 12 ;
- if ((number & 0x0200) == 0) return 11 ;
- if ((number & 0x0100) == 0) return 10 ;
- if ((number & 0x0080) == 0) return 9 ;
- if ((number & 0x0040) == 0) return 8 ;
- if ((number & 0x0020) == 0) return 7 ;
- if ((number & 0x0010) == 0) return 6 ;
- if ((number & 0x0008) == 0) return 5 ;
- if ((number & 0x0004) == 0) return 4 ;
- if ((number & 0x0002) == 0) return 3 ;
- if ((number & 0x0001) == 0) return 2 ;
-
- return 1 ;
-
- } else {
- // positive numbers
- if ((number & 0x4000) > 0) return 16 ;
- if ((number & 0x2000) > 0) return 15 ;
- if ((number & 0x1000) > 0) return 14 ;
- if ((number & 0x0800) > 0) return 13 ;
- if ((number & 0x0400) > 0) return 12 ;
- if ((number & 0x0200) > 0) return 11 ;
- if ((number & 0x0100) > 0) return 10 ;
- if ((number & 0x0080) > 0) return 9 ;
- if ((number & 0x0040) > 0) return 8 ;
- if ((number & 0x0020) > 0) return 7 ;
- if ((number & 0x0010) > 0) return 6 ;
- if ((number & 0x0008) > 0) return 5 ;
- if ((number & 0x0004) > 0) return 4 ;
- if ((number & 0x0002) > 0) return 3 ;
-
- return 2 ;
- }
- }
-
- /**
- * Finds the rightmost 1 bit in the given 16-bit integer. This value is
- * used by the decompressor to indicate the number of trailing zeros to be
- * added to the end of the data coming in from the compressed stream,
- * accomplished by left shifting the data by the indicated amount.
- * 0 is a special case returning 0.
- *
- * @param number an integer representable in 16 bits or less
- * @return number of trailing zeros
- */
- private static final int getShift(int number) {
- if (number == 0) return 0 ;
-
- if ((number & 0x0001) > 0) return 0 ;
- if ((number & 0x0002) > 0) return 1 ;
- if ((number & 0x0004) > 0) return 2 ;
- if ((number & 0x0008) > 0) return 3 ;
- if ((number & 0x0010) > 0) return 4 ;
- if ((number & 0x0020) > 0) return 5 ;
- if ((number & 0x0040) > 0) return 6 ;
- if ((number & 0x0080) > 0) return 7 ;
- if ((number & 0x0100) > 0) return 8 ;
- if ((number & 0x0200) > 0) return 9 ;
- if ((number & 0x0400) > 0) return 10 ;
- if ((number & 0x0800) > 0) return 11 ;
- if ((number & 0x1000) > 0) return 12 ;
- if ((number & 0x2000) > 0) return 13 ;
- if ((number & 0x4000) > 0) return 14 ;
-
- return 15 ;
- }
-
- /**
- * Computes common length and shift of 2 numbers.
- */
- final void computeLengthShift(int n0, int n1) {
- int s0 = n0 & 0x8000 ;
- int s1 = n1 & 0x8000 ;
-
- // equal sign optimization
- if (s0 == s1)
- if (s0 == 0)
- this.length = getLength(n0 | n1) ;
- else
- this.length = getLength(n0 & n1) ;
- else
- this.length = getMaximum(getLength(n0), getLength(n1)) ;
-
- this.shift = getShift(n0 | n1) ;
- }
-
-
- /**
- * Computes common length and shift of 3 numbers.
- */
- final void computeLengthShift(int n0, int n1, int n2) {
- int s0 = n0 & 0x8000 ;
- int s1 = n1 & 0x8000 ;
- int s2 = n2 & 0x8000 ;
-
- // equal sign optimization
- if (s0 == s1)
- if (s1 == s2)
- if (s2 == 0)
- this.length = getLength(n0 | n1 | n2) ;
- else
- this.length = getLength(n0 & n1 & n2) ;
- else
- if (s1 == 0)
- this.length = getMaximum(getLength(n0 | n1),
- getLength(n2)) ;
- else
- this.length = getMaximum(getLength(n0 & n1),
- getLength(n2)) ;
- else
- if (s1 == s2)
- if (s2 == 0)
- this.length = getMaximum(getLength(n1 | n2),
- getLength(n0)) ;
- else
- this.length = getMaximum(getLength(n1 & n2),
- getLength(n0)) ;
- else
- if (s0 == 0)
- this.length = getMaximum(getLength(n0 | n2),
- getLength(n1)) ;
- else
- this.length = getMaximum(getLength(n0 & n2),
- getLength(n1)) ;
-
- this.shift = getShift(n0 | n1 | n2) ;
- }
-
-
- /**
- * Computes common length and shift of 4 numbers.
- */
- final void computeLengthShift(int n0, int n1, int n2, int n3) {
- this.length = getMaximum(getLength(n0), getLength(n1),
- getLength(n2), getLength(n3)) ;
-
- this.shift = getShift(n0 | n1 | n2 | n3) ;
- }
-
-
- /**
- * Finds the maximum of two integers.
- */
- private static final int getMaximum(int x, int y) {
- if (x > y)
- return x ;
- else
- return y ;
- }
-
- /**
- * Finds the maximum of three integers.
- */
- private static final int getMaximum(int x, int y, int z) {
- if (x > y)
- if (x > z)
- return x ;
- else
- return z ;
- else
- if (y > z)
- return y ;
- else
- return z ;
- }
-
- /**
- * Finds the maximum of four integers.
- */
- private static final int getMaximum(int x, int y, int z, int w) {
- int n0, n1 ;
-
- if (x > y)
- n0 = x ;
- else
- n0 = y ;
-
- if (z > w)
- n1 = z ;
- else
- n1 = w ;
-
- if (n0 > n1)
- return n0 ;
- else
- return n1 ;
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamNormal.java b/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamNormal.java
deleted file mode 100644
index b43939a..0000000
--- a/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamNormal.java
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.compression;
-
-import javax.vecmath.Vector3f;
-
-/**
- * This class represents a normal in a compression stream. It maintains both
- * floating-point and quantized representations. This normal may be bundled
- * with a vertex or exist separately as a global normal.
- */
-class CompressionStreamNormal extends CompressionStreamElement {
- private int u, v ;
- private int specialOctant, specialSextant ;
- private float normalX, normalY, normalZ ;
-
- int octant, sextant ;
- boolean specialNormal ;
- int uAbsolute, vAbsolute ;
-
- /**
- * Create a CompressionStreamNormal.
- *
- * @param stream CompressionStream associated with this element
- * @param normal floating-point representation to be encoded
- */
- CompressionStreamNormal(CompressionStream stream, Vector3f normal) {
- this.normalX = normal.x ;
- this.normalY = normal.y ;
- this.normalZ = normal.z ;
- stream.byteCount += 12 ;
- }
-
- //
- // Normal Encoding Parameterization
- //
- // A floating point normal is quantized to a desired number of bits by
- // comparing it to candidate entries in a table of every possible normal
- // at that quantization and finding the closest match. This table of
- // normals is indexed by the following encoding:
- //
- // First, points on a unit radius sphere are parameterized by two angles,
- // th and psi, using usual spherical coordinates. th is the angle about
- // the y axis, psi is the inclination to the plane containing the point.
- // The mapping between rectangular and spherical coordinates is:
- //
- // x = cos(th)*cos(psi)
- // y = sin(psi)
- // z = sin(th)*cos(psi)
- //
- // Points on sphere are folded first by octant, and then by sort order
- // of xyz into one of six sextants. All the table encoding takes place in
- // the positive octant, in the region bounded by the half spaces:
- //
- // x >= z
- // z >= y
- // y >= 0
- //
- // This triangular shaped patch runs from 0 to 45 degrees in th, and
- // from 0 to as much as 0.615479709 (MAX_Y_ANG) in psi. The xyz bounds
- // of the patch is:
- //
- // (1, 0, 0) (1/sqrt(2), 0, 1/sqrt(2)) (1/sqrt(3), 1/sqrt(3), 1/sqrt(3))
- //
- // When dicing this space up into discrete points, the choice for y is
- // linear quantization in psi. This means that if the y range is to be
- // divided up into n segments, the angle of segment j is:
- //
- // psi(j) = MAX_Y_ANG*(j/n)
- //
- // The y height of the patch (in arc length) is *not* the same as the xz
- // dimension. However, the subdivision quantization needs to treat xz and
- // y equally. To achieve this, the th angles are re-parameterized as
- // reflected psi angles. That is, the i-th point's th is:
- //
- // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*(i/n)))
- //
- // To go the other direction, the angle th corresponds to the real index r
- // (in the same 0-n range as i):
- //
- // r(th) = n*atan(sin(th))/MAX_Y_ANG
- //
- // Rounded to the nearest integer, this gives the closest integer index i
- // to the xz angle th. Because the triangle has a straight edge on the
- // line x=z, it is more intuitive to index the xz angles in reverse
- // order. Thus the two equations above are replaced by:
- //
- // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*((n-i)/n)))
- //
- // r(th) = n*(1 - atan(sin(th))/MAX_Y_ANG)
- //
- // Each level of quantization subdivides the triangular patch twice as
- // densely. The case in which only the three vertices of the triangle are
- // present is the first logical stage of representation, but because of
- // how the table is encoded the first usable case starts one level of
- // sub-division later. This three point level has an n of 2 by the above
- // conventions.
- //
- private static final int MAX_UV_BITS = 6 ;
- private static final int MAX_UV_ENTRIES = 64 ;
-
- private static final double cgNormals[][][][] =
- new double[MAX_UV_BITS+1][MAX_UV_ENTRIES+1][MAX_UV_ENTRIES+1][3] ;
-
- private static final double MAX_Y_ANG = 0.615479709 ;
- private static final double UNITY_14 = 16384.0 ;
-
- private static void computeNormals() {
- int inx, iny, inz, n ;
- double th, psi, qnx, qny, qnz ;
-
- for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) {
- n = 1 << quant ;
-
- for (int j = 0 ; j <= n ; j++) {
- for (int i = 0 ; i <= n ; i++) {
- if (i+j > n) continue ;
-
- psi = MAX_Y_ANG*(j/((double) n)) ;
- th = Math.asin(Math.tan(MAX_Y_ANG*((n-i)/((double) n)))) ;
-
- qnx = Math.cos(th)*Math.cos(psi) ;
- qny = Math.sin(psi) ;
- qnz = Math.sin(th)*Math.cos(psi) ;
-
- // The normal table uses 16-bit components and must be
- // able to represent both +1.0 and -1.0, so convert the
- // floating point normal components to fixed point with 14
- // fractional bits, a unity bit, and a sign bit (s1.14).
- // Set them back to get the float equivalent.
- qnx = qnx*UNITY_14 ; inx = (int)qnx ;
- qnx = inx ; qnx = qnx/UNITY_14 ;
-
- qny = qny*UNITY_14 ; iny = (int)qny ;
- qny = iny ; qny = qny/UNITY_14 ;
-
- qnz = qnz*UNITY_14 ; inz = (int)qnz ;
- qnz = inz ; qnz = qnz/UNITY_14 ;
-
- cgNormals[quant][j][i][0] = qnx ;
- cgNormals[quant][j][i][1] = qny ;
- cgNormals[quant][j][i][2] = qnz ;
- }
- }
- }
- }
-
- //
- // An inverse sine table is used for each quantization level to take the Y
- // component of a normal (which is the sine of the inclination angle) and
- // obtain the closest quantized Y angle.
- //
- // At any level of compression, there are a fixed number of different Y
- // angles (between 0 and MAX_Y_ANG). The inverse table is built to have
- // slightly more than twice as many entries as y angles at any particular
- // level; this ensures that the inverse look-up will get within one angle
- // of the right one. The size of the table should be as small as
- // possible, but with its delta sine still smaller than the delta sine
- // between the last two angles to be encoded.
- //
- // Example: the inverse sine table has a maximum angle of 0.615479709. At
- // the maximum resolution of 6 bits there are 65 discrete angles used,
- // but twice as many are needed for thresholding between angles, so the
- // delta angle is 0.615479709/128. The difference then between the last
- // two angles to be encoded is:
- // sin(0.615479709*128.0/128.0) - sin(0.615479709*127.0/128.0) = 0.003932730
- //
- // Using 8 significent bits below the binary point, fixed point can
- // represent sines in increments of 0.003906250, just slightly smaller.
- // However, because the maximum Y angle sine is 0.577350269, only 148
- // instead of 256 table entries are needed.
- //
- private static final short inverseSine[][] = new short[MAX_UV_BITS+1][] ;
-
- // UNITY_14 * sin(MAX_Y_ANGLE)
- private static final short MAX_SIN_14BIT = 9459 ;
-
- private static void computeInverseSineTables() {
- int intSin, deltaSin, intAngle ;
- double floatSin, floatAngle ;
- short sin14[] = new short[MAX_UV_ENTRIES+1] ;
-
- // Build table of sines in s1.14 fixed point for each of the
- // discrete angles used at maximum resolution.
- for (int i = 0 ; i <= MAX_UV_ENTRIES ; i++) {
- sin14[i] = (short)(UNITY_14*Math.sin(i*MAX_Y_ANG/MAX_UV_ENTRIES)) ;
- }
-
- for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) {
- switch (quant) {
- default:
- case 6:
- // Delta angle: MAX_Y_ANGLE/128.0
- // Bits below binary point for fixed point delta sine: 8
- // Integer delta sine: 64
- // Inverse sine table size: 148 entries
- deltaSin = 1 << (14 - 8) ;
- break ;
- case 5:
- // Delta angle: MAX_Y_ANGLE/64.0
- // Bits below binary point for fixed point delta sine: 7
- // Integer delta sine: 128
- // Inverse sine table size: 74 entries
- deltaSin = 1 << (14 - 7) ;
- break ;
- case 4:
- // Delta angle: MAX_Y_ANGLE/32.0
- // Bits below binary point for fixed point delta sine: 6
- // Integer delta sine: 256
- // Inverse sine table size: 37 entries
- deltaSin = 1 << (14 - 6) ;
- break ;
- case 3:
- // Delta angle: MAX_Y_ANGLE/16.0
- // Bits below binary point for fixed point delta sine: 5
- // Integer delta sine: 512
- // Inverse sine table size: 19 entries
- deltaSin = 1 << (14 - 5) ;
- break ;
- case 2:
- // Delta angle: MAX_Y_ANGLE/8.0
- // Bits below binary point for fixed point delta sine: 4
- // Integer delta sine: 1024
- // Inverse sine table size: 10 entries
- deltaSin = 1 << (14 - 4) ;
- break ;
- case 1:
- // Delta angle: MAX_Y_ANGLE/4.0
- // Bits below binary point for fixed point delta sine: 3
- // Integer delta sine: 2048
- // Inverse sine table size: 5 entries
- deltaSin = 1 << (14 - 3) ;
- break ;
- case 0:
- // Delta angle: MAX_Y_ANGLE/2.0
- // Bits below binary point for fixed point delta sine: 2
- // Integer delta sine: 4096
- // Inverse sine table size: 3 entries
- deltaSin = 1 << (14 - 2) ;
- break ;
- }
-
- inverseSine[quant] = new short[(MAX_SIN_14BIT/deltaSin) + 1] ;
-
- intSin = 0 ;
- for (int i = 0 ; i < inverseSine[quant].length ; i++) {
- // Compute float representation of integer sine with desired
- // number of fractional bits by effectively right shifting 14.
- floatSin = intSin/UNITY_14 ;
-
- // Compute the angle with this sine value and quantize it.
- floatAngle = Math.asin(floatSin) ;
- intAngle = (int)((floatAngle/MAX_Y_ANG) * (1 << quant)) ;
-
- // Choose the closest of the three nearest quantized values
- // intAngle-1, intAngle, and intAngle+1.
- if (intAngle > 0) {
- if (Math.abs(sin14[intAngle << (6-quant)] - intSin) >
- Math.abs(sin14[(intAngle-1) << (6-quant)] - intSin))
- intAngle = intAngle-1 ;
- }
-
- if (intAngle < (1 << quant)) {
- if (Math.abs(sin14[intAngle << (6-quant)] - intSin) >
- Math.abs(sin14[(intAngle+1) << (6-quant)] - intSin))
- intAngle = intAngle+1 ;
- }
-
- inverseSine[quant][i] = (short)intAngle ;
- intSin += deltaSin ;
- }
- }
- }
-
- /**
- * Compute static tables needed for normal quantization.
- */
- static {
- computeNormals() ;
- computeInverseSineTables() ;
- }
-
- /**
- * Quantize the floating point normal to a 6-bit octant/sextant plus u,v
- * components of [0..6] bits. Full resolution is 18 bits and the minimum
- * is 6 bits.
- *
- * @param stream CompressionStream associated with this element
- * @param table HuffmanTable for collecting data about the quantized
- * representation of this element
- */
- @Override
- void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
- double nx, ny, nz, t ;
-
- // Clamp UV quantization.
- int quant =
- (stream.normalQuant < 0? 0 :
- (stream.normalQuant > 6? 6 : stream.normalQuant)) ;
-
- nx = normalX ;
- ny = normalY ;
- nz = normalZ ;
-
- octant = 0 ;
- sextant = 0 ;
- u = 0 ;
- v = 0 ;
-
- // Normalize the fixed point normal to the positive signed octant.
- if (nx < 0.0) {
- octant |= 4 ;
- nx = -nx ;
- }
- if (ny < 0.0) {
- octant |= 2 ;
- ny = -ny ;
- }
- if (nz < 0.0) {
- octant |= 1 ;
- nz = -nz ;
- }
-
- // Normalize the fixed point normal to the proper sextant of the octant.
- if (nx < ny) {
- sextant |= 1 ;
- t = nx ;
- nx = ny ;
- ny = t ;
- }
- if (nz < ny) {
- sextant |= 2 ;
- t = ny ;
- ny = nz ;
- nz = t ;
- }
- if (nx < nz) {
- sextant |= 4 ;
- t = nx ;
- nx = nz ;
- nz = t ;
- }
-
- // Convert the floating point y component to s1.14 fixed point.
- int yInt = (int)(ny * UNITY_14) ;
-
- // The y component of the normal is the sine of the y angle. Quantize
- // the y angle by using the fixed point y component as an index into
- // the inverse sine table of the correct size for the quantization
- // level. (12 - quant) bits of the s1.14 y normal component are
- // rolled off with a right shift; the remaining bits then match the
- // number of bits used to represent the delta sine of the table.
- int yIndex = inverseSine[quant][yInt >> (12-quant)] ;
-
- // Search the two xz rows near y for the best match.
- int ii = 0 ;
- int jj = 0 ;
- int n = 1 << quant ;
- double dot, bestDot = -1 ;
-
- for (int j = yIndex-1 ; j < yIndex+1 && j <= n ; j++) {
- if (j < 0)
- continue ;
-
- for (int i = 0 ; i <= n ; i++) {
- if (i+j > n)
- continue ;
-
- dot = nx * cgNormals[quant][j][i][0] +
- ny * cgNormals[quant][j][i][1] +
- nz * cgNormals[quant][j][i][2] ;
-
- if (dot > bestDot) {
- bestDot = dot ;
- ii = i ;
- jj = j ;
- }
- }
- }
-
- // Convert u and v to standard grid form.
- u = ii << (6 - quant) ;
- v = jj << (6 - quant) ;
-
- // Check for special normals and specially encode them.
- specialNormal = false ;
- if (u == 64 && v == 0) {
- // six coordinate axes case
- if (sextant == 0 || sextant == 2) {
- // +/- x-axis
- specialSextant = 0x6 ;
- specialOctant = ((octant & 4) != 0)? 0x2 : 0 ;
-
- } else if (sextant == 3 || sextant == 1) {
- // +/- y-axis
- specialSextant = 0x6 ;
- specialOctant = 4 | (((octant & 2) != 0)? 0x2 : 0) ;
-
- } else if (sextant == 5 || sextant == 4) {
- // +/- z-axis
- specialSextant = 0x7 ;
- specialOctant = ((octant & 1) != 0)? 0x2 : 0 ;
- }
- specialNormal = true ;
- u = v = 0 ;
-
- } else if (u == 0 && v == 64) {
- // eight mid point case
- specialSextant = 6 | (octant >> 2) ;
- specialOctant = ((octant & 0x3) << 1) | 1 ;
- specialNormal = true ;
- u = v = 0 ;
- }
-
- // Compute deltas if possible.
- // Use the non-normalized ii and jj indices.
- int du = 0 ;
- int dv = 0 ;
- int uv64 = 64 >> (6 - quant) ;
-
- absolute = false ;
- if (stream.firstNormal || stream.normalQuantChanged ||
- stream.lastSpecialNormal || specialNormal) {
- // The first normal by definition is absolute, and normals cannot
- // be represented as deltas to or from special normals, nor from
- // normals with a different quantization.
- absolute = true ;
- stream.firstNormal = false ;
- stream.normalQuantChanged = false ;
-
- } else if (stream.lastOctant == octant &&
- stream.lastSextant == sextant) {
- // Deltas are always allowed within the same sextant/octant.
- du = ii - stream.lastU ;
- dv = jj - stream.lastV ;
-
- } else if (stream.lastOctant != octant &&
- stream.lastSextant == sextant &&
- (((sextant == 1 || sextant == 5) &&
- (stream.lastOctant & 3) == (octant & 3)) ||
- ((sextant == 0 || sextant == 4) &&
- (stream.lastOctant & 5) == (octant & 5)) ||
- ((sextant == 2 || sextant == 3) &&
- (stream.lastOctant & 6) == (octant & 6)))) {
- // If the sextants are the same, the octants can differ only when
- // they are bordering each other on the same edge that the
- // sextant has.
- du = ii - stream.lastU ;
- dv = -jj - stream.lastV ;
-
- // Can't delta by less than -64.
- if (dv < -uv64) absolute = true ;
-
- // Can't delta doubly defined points.
- if (jj == 0) absolute = true ;
-
- } else if (stream.lastOctant == octant &&
- stream.lastSextant != sextant &&
- ((sextant == 0 && stream.lastSextant == 4) ||
- (sextant == 4 && stream.lastSextant == 0) ||
- (sextant == 1 && stream.lastSextant == 5) ||
- (sextant == 5 && stream.lastSextant == 1) ||
- (sextant == 2 && stream.lastSextant == 3) ||
- (sextant == 3 && stream.lastSextant == 2))) {
- // If the octants are the same, the sextants must border on
- // the i side (this case) or the j side (next case).
- du = -ii - stream.lastU ;
- dv = jj - stream.lastV ;
-
- // Can't delta by less than -64.
- if (du < -uv64) absolute = true ;
-
- // Can't delta doubly defined points.
- if (ii == 0) absolute = true ;
-
- } else if (stream.lastOctant == octant &&
- stream.lastSextant != sextant &&
- ((sextant == 0 && stream.lastSextant == 2) ||
- (sextant == 2 && stream.lastSextant == 0) ||
- (sextant == 1 && stream.lastSextant == 3) ||
- (sextant == 3 && stream.lastSextant == 1) ||
- (sextant == 4 && stream.lastSextant == 5) ||
- (sextant == 5 && stream.lastSextant == 4))) {
- // If the octants are the same, the sextants must border on
- // the j side (this case) or the i side (previous case).
- if (((ii + jj ) != uv64) && (ii != 0) && (jj != 0)) {
- du = uv64 - ii - stream.lastU ;
- dv = uv64 - jj - stream.lastV ;
-
- // Can't delta by greater than +63.
- if ((du >= uv64) || (dv >= uv64))
- absolute = true ;
- } else
- // Can't delta doubly defined points.
- absolute = true ;
-
- } else
- // Can't delta this normal.
- absolute = true ;
-
- if (absolute == false) {
- // Convert du and dv to standard grid form.
- u = du << (6 - quant) ;
- v = dv << (6 - quant) ;
- }
-
- // Compute length and shift common to all components.
- computeLengthShift(u, v) ;
-
- if (absolute && length > 6) {
- // Absolute normal u, v components are unsigned 6-bit integers, so
- // truncate the 0 sign bit for values > 0x001f.
- length = 6 ;
- }
-
- // Add this element to the Huffman table associated with this stream.
- huffmanTable.addNormalEntry(length, shift, absolute) ;
-
- // Save current normal as last.
- stream.lastSextant = sextant ;
- stream.lastOctant = octant ;
- stream.lastU = ii ;
- stream.lastV = jj ;
- stream.lastSpecialNormal = specialNormal ;
-
- // Copy and retain absolute normal for mesh buffer lookup.
- uAbsolute = ii ;
- vAbsolute = jj ;
- }
-
- /**
- * Output a setNormal command.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- @Override
- void outputCommand(HuffmanTable table, CommandStream output) {
- outputNormal(table, output, CommandStream.SET_NORM, 8) ;
- }
-
- /**
- * Output a normal subcommand.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- void outputSubcommand(HuffmanTable table, CommandStream output) {
- outputNormal(table, output, 0, 6) ;
- }
-
- //
- // Output the final compressed bits to the output command stream.
- //
- private void outputNormal(HuffmanTable table, CommandStream output,
- int header, int headerLength) {
-
- HuffmanNode t ;
-
- // Look up the Huffman token for this compression stream element.
- t = table.getNormalEntry(length, shift, absolute) ;
-
- // Construct the normal subcommand.
- int componentLength = t.dataLength - t.shift ;
- int subcommandLength = 0 ;
- long normalSubcommand = 0 ;
-
- if (absolute) {
- // A 3-bit sextant and a 3-bit octant are always present.
- subcommandLength = t.tagLength + 6 ;
-
- if (specialNormal)
- // Use the specially-encoded sextant and octant.
- normalSubcommand =
- (t.tag << 6) | (specialSextant << 3) | specialOctant ;
- else
- // Use the general encoding rule.
- normalSubcommand =
- (t.tag << 6) | (sextant << 3) | octant ;
- } else {
- // The tag is immediately followed by the u and v delta components.
- subcommandLength = t.tagLength ;
- normalSubcommand = t.tag ;
- }
-
- // Add the u and v values to the subcommand.
- subcommandLength += (2 * componentLength) ;
-
- u = (u >> t.shift) & (int)lengthMask[componentLength] ;
- v = (v >> t.shift) & (int)lengthMask[componentLength] ;
-
- normalSubcommand =
- (normalSubcommand << (2 * componentLength)) |
- (u << (1 * componentLength)) |
- (v << (0 * componentLength)) ;
-
- if (subcommandLength < 6) {
- // The header will have some empty bits. The Huffman tag
- // computation will prevent this if necessary.
- header |= (int)(normalSubcommand << (6 - subcommandLength)) ;
- subcommandLength = 0 ;
- }
- else {
- // Move the 1st 6 bits of the subcommand into the header.
- header |= (int)(normalSubcommand >>> (subcommandLength - 6)) ;
- subcommandLength -= 6 ;
- }
-
- // Add the header and body to the output buffer.
- output.addCommand(header, headerLength,
- normalSubcommand, subcommandLength) ;
- }
-
- @Override
- public String toString() {
- String fixed ;
-
- if (specialNormal)
- fixed = " special normal, sextant " + specialSextant +
- " octant " + specialOctant ;
-
- else if (absolute)
- fixed = " sextant " + sextant + " octant " + octant +
- " u " + u + " v " + v ;
- else
- fixed = " du " + u + " dv " + v ;
-
- return
- "normal: " + normalX + " " + normalY + " " + normalZ + "\n"
- + fixed + "\n" + " length " + length + " shift " + shift +
- (absolute? " absolute" : " relative") ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamVertex.java b/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamVertex.java
deleted file mode 100644
index 906c107..0000000
--- a/src/classes/share/com/sun/j3d/utils/compression/CompressionStreamVertex.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.compression;
-
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3f;
-
-/**
- * This class represents a vertex in a compression stream. It maintains both
- * floating-point and quantized representations of the vertex position along
- * with meshing and vertex replacement flags for line and surface
- * primitives. If normals or colors are bundled with geometry vertices then
- * instances of this class will also contain references to normal or color
- * stream elements.
- */
-class CompressionStreamVertex extends CompressionStreamElement {
- private int X, Y, Z ;
- private int meshFlag ;
- private int stripFlag ;
- private float floatX, floatY, floatZ ;
-
- int xAbsolute, yAbsolute, zAbsolute ;
- CompressionStreamColor color = null ;
- CompressionStreamNormal normal = null ;
-
- /**
- * Create a CompressionStreamVertex with the given parameters.
- *
- * @param stream CompressionStream associated with this vertex
- * @param p position
- * @param n normal bundled with this vertex or null if not bundled
- * @param c color bundled with this vertex or null if not bundled
- * @param stripFlag CompressionStream.RESTART,
- * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
- * @param meshFlag CompressionStream.MESH_PUSH or
- * CompressionStream.NO_MESH_PUSH
- */
- CompressionStreamVertex(CompressionStream stream,
- Point3f p, Vector3f n, Color3f c,
- int stripFlag, int meshFlag) {
-
- this(stream, p, n, stripFlag, meshFlag) ;
-
- if (stream.vertexColor3)
- color = new CompressionStreamColor(stream, c) ;
- }
-
- /**
- * Create a CompressionStreamVertex with the given parameters.
- *
- * @param stream CompressionStream associated with this vertex
- * @param p position
- * @param n normal bundled with this vertex or null if not bundled
- * @param c color bundled with this vertex or null if not bundled
- * @param stripFlag CompressionStream.RESTART,
- * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
- * @param meshFlag CompressionStream.MESH_PUSH or
- * CompressionStream.NO_MESH_PUSH
- */
- CompressionStreamVertex(CompressionStream stream,
- Point3f p, Vector3f n, Color4f c,
- int stripFlag, int meshFlag) {
-
- this(stream, p, n, stripFlag, meshFlag) ;
-
- if (stream.vertexColor4)
- color = new CompressionStreamColor(stream, c) ;
- }
-
- /**
- * Create a CompressionStreamVertex with the given parameters.
- *
- * @param stream CompressionStream associated with this vertex
- * @param p position
- * @param n normal bundled with this vertex or null if not bundled
- * @param stripFlag CompressionStream.RESTART,
- * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
- * @param meshFlag CompressionStream.MESH_PUSH or
- * CompressionStream.NO_MESH_PUSH
- */
- CompressionStreamVertex(CompressionStream stream, Point3f p, Vector3f n,
- int stripFlag, int meshFlag) {
-
- this.stripFlag = stripFlag ;
- this.meshFlag = meshFlag ;
- this.floatX = p.x ;
- this.floatY = p.y ;
- this.floatZ = p.z ;
-
- stream.byteCount += 12 ;
- stream.vertexCount++ ;
-
- if (p.x < stream.mcBounds[0].x) stream.mcBounds[0].x = p.x ;
- if (p.y < stream.mcBounds[0].y) stream.mcBounds[0].y = p.y ;
- if (p.z < stream.mcBounds[0].z) stream.mcBounds[0].z = p.z ;
-
- if (p.x > stream.mcBounds[1].x) stream.mcBounds[1].x = p.x ;
- if (p.y > stream.mcBounds[1].y) stream.mcBounds[1].y = p.y ;
- if (p.z > stream.mcBounds[1].z) stream.mcBounds[1].z = p.z ;
-
- if (stream.vertexNormals)
- normal = new CompressionStreamNormal(stream, n) ;
- }
-
- /**
- * Quantize the floating point position to fixed point integer components
- * of the specified number of bits. The bit length can range from 1 to 16.
- *
- * @param stream CompressionStream associated with this element
- * @param table HuffmanTable for collecting data about the quantized
- * representation of this element
- */
- @Override
- void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
- double px, py, pz ;
-
- // Clamp quantization.
- int quant =
- (stream.positionQuant < 1? 1 :
- (stream.positionQuant > 16? 16 : stream.positionQuant)) ;
-
- absolute = false ;
- if (stream.firstPosition || stream.positionQuantChanged) {
- absolute = true ;
- stream.lastPosition[0] = 0 ;
- stream.lastPosition[1] = 0 ;
- stream.lastPosition[2] = 0 ;
- stream.firstPosition = false ;
- stream.positionQuantChanged = false ;
- }
-
- // Normalize position to the unit cube. This is bounded by the open
- // intervals (-1..1) on each axis.
- px = (floatX - stream.center[0]) * stream.scale ;
- py = (floatY - stream.center[1]) * stream.scale ;
- pz = (floatZ - stream.center[2]) * stream.scale ;
-
- // Convert the floating point position to s.15 2's complement.
- // ~1.0 -> 32767 (0x00007fff) [ ~1.0 = 32767.0/32768.0]
- // ~-1.0 -> -32767 (0xffff8001) [~-1.0 = -32767.0/32768.0]
- X = (int)(px * 32768.0) ;
- Y = (int)(py * 32768.0) ;
- Z = (int)(pz * 32768.0) ;
-
- // Compute quantized values.
- X &= quantizationMask[quant] ;
- Y &= quantizationMask[quant] ;
- Z &= quantizationMask[quant] ;
-
- // Update quantized bounds.
- if (X < stream.qcBounds[0].x) stream.qcBounds[0].x = X ;
- if (Y < stream.qcBounds[0].y) stream.qcBounds[0].y = Y ;
- if (Z < stream.qcBounds[0].z) stream.qcBounds[0].z = Z ;
-
- if (X > stream.qcBounds[1].x) stream.qcBounds[1].x = X ;
- if (Y > stream.qcBounds[1].y) stream.qcBounds[1].y = Y ;
- if (Z > stream.qcBounds[1].z) stream.qcBounds[1].z = Z ;
-
- // Copy and retain absolute position for mesh buffer lookup.
- xAbsolute = X ;
- yAbsolute = Y ;
- zAbsolute = Z ;
-
- // Compute deltas.
- X -= stream.lastPosition[0] ;
- Y -= stream.lastPosition[1] ;
- Z -= stream.lastPosition[2] ;
-
- // Update last values.
- stream.lastPosition[0] += X ;
- stream.lastPosition[1] += Y ;
- stream.lastPosition[2] += Z ;
-
- // Deltas which exceed the range of 16-bit signed 2's complement
- // numbers are handled by sign-extension of the 16th bit in order to
- // effect a 16-bit wrap-around.
- X = (X << 16) >> 16 ;
- Y = (Y << 16) >> 16 ;
- Z = (Z << 16) >> 16 ;
-
- // Compute length and shift common to all components.
- computeLengthShift(X, Y, Z) ;
-
- // 0-length components are allowed only for normals.
- if (length == 0)
- length = 1 ;
-
- // Add this element to the Huffman table associated with this stream.
- huffmanTable.addPositionEntry(length, shift, absolute) ;
-
- // Quantize any bundled color or normal.
- if (color != null)
- color.quantize(stream, huffmanTable) ;
-
- if (normal != null)
- normal.quantize(stream, huffmanTable) ;
-
- // Push this vertex into the mesh buffer mirror, if necessary, so it
- // can be retrieved for computing deltas when mesh buffer references
- // are subsequently encountered during the quantization pass.
- if (meshFlag == stream.MESH_PUSH)
- stream.meshBuffer.push(this) ;
- }
-
- /**
- * Output the final compressed bits to the compression command stream.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- @Override
- void outputCommand(HuffmanTable huffmanTable, CommandStream outputBuffer) {
-
- HuffmanNode t ;
- int command = CommandStream.VERTEX ;
-
- // Look up the Huffman token for this compression stream element. The
- // values of length and shift found there will override the
- // corresponding fields in this element, which represent best-case
- // compression without regard to tag length.
- t = huffmanTable.getPositionEntry(length, shift, absolute) ;
-
- // Construct the position subcommand.
- int componentLength = t.dataLength - t.shift ;
- int subcommandLength = t.tagLength + (3 * componentLength) ;
-
- X = (X >> t.shift) & (int)lengthMask[componentLength] ;
- Y = (Y >> t.shift) & (int)lengthMask[componentLength] ;
- Z = (Z >> t.shift) & (int)lengthMask[componentLength] ;
-
- long positionSubcommand =
- (((long)t.tag) << (3 * componentLength)) |
- (((long)X) << (2 * componentLength)) |
- (((long)Y) << (1 * componentLength)) |
- (((long)Z) << (0 * componentLength)) ;
-
- if (subcommandLength < 6) {
- // The header will have some empty bits. The Huffman tag
- // computation will prevent this if necessary.
- command |= (int)(positionSubcommand << (6 - subcommandLength)) ;
- subcommandLength = 0 ;
- }
- else {
- // Move the 1st 6 bits of the subcommand into the header.
- command |= (int)(positionSubcommand >>> (subcommandLength - 6)) ;
- subcommandLength -= 6 ;
- }
-
- // Construct the vertex command body.
- long body =
- (((long)stripFlag) << (subcommandLength + 1)) |
- (((long)meshFlag) << (subcommandLength + 0)) |
- (positionSubcommand & lengthMask[subcommandLength]) ;
-
- // Add the vertex command to the output buffer.
- outputBuffer.addCommand(command, 8, body, subcommandLength + 3) ;
-
- // Output any normal and color subcommands.
- if (normal != null)
- normal.outputSubcommand(huffmanTable, outputBuffer) ;
-
- if (color != null)
- color.outputSubcommand(huffmanTable, outputBuffer) ;
- }
-
- @Override
- public String toString() {
- String d = absolute? "" : "delta " ;
- String c = (color == null? "": "\n\n " + color.toString()) ;
- String n = (normal == null? "": "\n\n " + normal.toString()) ;
-
- return
- "position: " + floatX + " " + floatY + " " + floatZ + "\n" +
- "fixed point " + d + + X + " " + Y + " " + Z + "\n" +
- "length " + length + " shift " + shift +
- (absolute? " absolute" : " relative") + "\n" +
- "strip flag " + stripFlag + " mesh flag " + meshFlag +
- c + n ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/compression/GeometryCompressor.java b/src/classes/share/com/sun/j3d/utils/compression/GeometryCompressor.java
deleted file mode 100644
index d3fda17..0000000
--- a/src/classes/share/com/sun/j3d/utils/compression/GeometryCompressor.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.compression;
-
-import java.io.IOException;
-
-import javax.media.j3d.CompressedGeometry;
-import javax.media.j3d.CompressedGeometryHeader;
-import javax.vecmath.Point3d;
-
-/**
- * A GeometryCompressor takes a stream of geometric elements and
- * quantization parameters (the CompressionStream object) and
- * compresses it into a stream of commands as defined by appendix B
- * of the Java 3D specification. The resulting data may be output
- * in the form of a CompressedGeometry node component or appended
- * to a CompressedGeometryFile.
- *
- * @see CompressionStream
- * @see CompressedGeometry
- * @see CompressedGeometryFile
- *
- * @deprecated As of Java 3D 1.5, replaced by
- * com.sun.j3d.utils.geometry.compression.{@link com.sun.j3d.utils.geometry.compression.GeometryCompressor}.
- */
-public class GeometryCompressor {
- private static final boolean benchmark = false ;
- private static final boolean printStream = false ;
- private static final boolean printHuffman = false ;
-
- private HuffmanTable huffmanTable ;
- private CommandStream outputBuffer ;
- private CompressedGeometryHeader cgHeader ;
- private long startTime ;
-
- public GeometryCompressor() {
- // Create a compressed geometry header.
- cgHeader = new CompressedGeometryHeader() ;
-
- // v1.0.0 - pre-FCS
- // v1.0.1 - fixed winding order, FCS version (J3D 1.1.2)
- // v1.0.2 - normal component length maximum 6, LII hardware (J3D 1.2)
- cgHeader.majorVersionNumber = 1 ;
- cgHeader.minorVersionNumber = 0 ;
- cgHeader.minorMinorVersionNumber = 2 ;
- }
-
- /**
- * Compress a stream into a CompressedGeometry node component.
- *
- * @param stream CompressionStream containing the geometry to be compressed
- * @return a CompressedGeometry node component
- */
- public CompressedGeometry compress(CompressionStream stream) {
- CompressedGeometry cg ;
-
- compressStream(stream) ;
- cg = new CompressedGeometry(cgHeader, outputBuffer.getBytes()) ;
-
- outputBuffer.clear() ;
- return cg ;
- }
-
- /**
- * Compress a stream and append the output to a CompressedGeometryFile.
- * The resource remains open for subsequent updates; its close() method
- * must be called to create a valid compressed geometry resource file.
- *
- * @param stream CompressionStream containing the geometry to be compressed
- * @param f a currently open CompressedGeometryFile with write access
- * @exception IOException if write fails
- */
- public void compress(CompressionStream stream, CompressedGeometryFile f)
- throws IOException {
-
- compressStream(stream) ;
- f.write(cgHeader, outputBuffer.getBytes()) ;
-
- outputBuffer.clear() ;
- }
-
- //
- // Compress the stream and put the results in the output buffer.
- // Set up the CompressedGeometryHeader object.
- //
- private void compressStream(CompressionStream stream) {
- if (benchmark) startTime = System.currentTimeMillis() ;
-
- // Create the Huffman table.
- huffmanTable = new HuffmanTable() ;
-
- // Quantize the stream, compute deltas between consecutive elements if
- // possible, and histogram the data length distribution.
- stream.quantize(huffmanTable) ;
-
- // Compute tags for stream tokens.
- huffmanTable.computeTags() ;
-
- // Create the output buffer and assemble the compressed output.
- outputBuffer = new CommandStream(stream.getByteCount() / 3) ;
- stream.outputCommands(huffmanTable, outputBuffer) ;
-
- // Print any desired info.
- if (benchmark) printBench(stream) ;
- if (printStream) stream.print() ;
- if (printHuffman) huffmanTable.print() ;
-
- // Set up the compressed geometry header object.
- cgHeader.bufferType = stream.streamType ;
- cgHeader.bufferDataPresent = 0 ;
- cgHeader.lowerBound = new Point3d(stream.ncBounds[0]) ;
- cgHeader.upperBound = new Point3d(stream.ncBounds[1]) ;
-
- if (stream.vertexNormals)
- cgHeader.bufferDataPresent |=
- CompressedGeometryHeader.NORMAL_IN_BUFFER ;
-
- if (stream.vertexColor3 || stream.vertexColor4)
- cgHeader.bufferDataPresent |=
- CompressedGeometryHeader.COLOR_IN_BUFFER ;
-
- if (stream.vertexColor4)
- cgHeader.bufferDataPresent |=
- CompressedGeometryHeader.ALPHA_IN_BUFFER ;
-
- cgHeader.start = 0 ;
- cgHeader.size = outputBuffer.getByteCount() ;
-
- // Clear the huffman table for next use.
- huffmanTable.clear() ;
- }
-
- private void printBench(CompressionStream stream) {
- long t = System.currentTimeMillis() - startTime ;
- int vertexCount = stream.getVertexCount() ;
- int meshReferenceCount = stream.getMeshReferenceCount() ;
- int totalVertices = meshReferenceCount + vertexCount ;
- float meshPercent = 100f * meshReferenceCount/(float)totalVertices ;
-
- float compressionRatio =
- stream.getByteCount() / ((float)outputBuffer.getByteCount()) ;
-
- int vertexBytes =
- 12 + (stream.vertexColor3 ? 12 : 0) +
- (stream.vertexColor4 ? 16 : 0) + (stream.vertexNormals ? 12 : 0) ;
-
- float compressedVertexBytes =
- outputBuffer.getByteCount() / (float)totalVertices ;
-
- System.out.println
- ("\nGeometryCompressor:\n" + totalVertices + " total vertices\n" +
- vertexCount + " streamed vertices\n" + meshReferenceCount +
- " mesh buffer references (" + meshPercent + "%)\n" +
- stream.getByteCount() + " bytes streamed geometry compressed to " +
- outputBuffer.getByteCount() + " in " + (t/1000f) + " sec\n" +
- (stream.getByteCount()/(float)t) + " kbytes/sec, " +
- "stream compression ratio " + compressionRatio + "\n\n" +
- vertexBytes + " original bytes per vertex, " +
- compressedVertexBytes + " compressed bytes per vertex\n" +
- "total vertex compression ratio " +
- (vertexBytes / (float)compressedVertexBytes) + "\n\n" +
- "lower bound " + stream.ncBounds[0].toString() +"\n" +
- "upper bound " + stream.ncBounds[1].toString()) ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/compression/HuffmanNode.java b/src/classes/share/com/sun/j3d/utils/compression/HuffmanNode.java
deleted file mode 100644
index a89eec8..0000000
--- a/src/classes/share/com/sun/j3d/utils/compression/HuffmanNode.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.compression;
-
-import java.util.Collection;
-import java.util.Comparator;
-
-/**
- * Instances of this class are used as the nodes of binary trees representing
- * mappings of tags to compression stream elements. Tags are descriptors
- * inserted into the compression command stream that specify the encoding of
- * immediately succeeding data elements.
- *
- * The tag assignments in such a tree are computed from the paths taken from
- * the root to the leaf nodes. Each leaf node represents the particular way
- * one or more compression stream elements wound up being encoded with respect
- * to various combinations of data lengths, shifts, and absolute/relative
- * status.
- *
- * Huffman's algorithm for constructing binary trees with minimal weighted
- * path lengths can be used to optimize the bit lengths of the tags with
- * respect to the frequency of occurrence of their associated data encodings
- * in the compression stream. The weighted path length is the sum of the
- * frequencies of all the leaf nodes times their path lengths to the root of
- * the tree.
- *
- * The length of the longest tag determines the size of the table mapping tags
- * to data representations. The geometry compression specification limits the
- * size of the table to 64 entries, so tags cannot be longer than 6 bits. The
- * depth of the tree is reduced through a process of increasing the data
- * lengths of less frequently occuring nodes so they can be merged with other
- * more frequent nodes.
- */
-class HuffmanNode {
- int tag, tagLength ;
- int shift, dataLength ;
- boolean absolute ;
-
- private int frequency ;
- private HuffmanNode child0, child1, mergeNode ;
- private boolean merged, unmergeable, cleared ;
-
- void clear() {
- tag = -1 ;
- tagLength = -1 ;
-
- shift = -1 ;
- dataLength = -1 ;
- absolute = false ;
-
- child0 = null ;
- child1 = null ;
- mergeNode = null ;
-
- frequency = 0 ;
- merged = false ;
- unmergeable = false ;
- cleared = true ;
- }
-
- HuffmanNode() {
- clear() ;
- }
-
- HuffmanNode(int length, int shift, boolean absolute) {
- this() ;
- set(length, shift, absolute) ;
- }
-
- final void set(int length, int shift, boolean absolute) {
- this.dataLength = length ;
- this.shift = shift ;
- this.absolute = absolute ;
- this.cleared = false ;
- }
-
- final boolean cleared() {
- return cleared ;
- }
-
- final void addCount() {
- frequency++ ;
- }
-
- final boolean hasCount() {
- return frequency > 0 ;
- }
-
- final boolean tokenEquals(HuffmanNode node) {
- return
- this.absolute == node.absolute &&
- this.dataLength == node.dataLength &&
- this.shift == node.shift ;
- }
-
- void addChildren(HuffmanNode child0, HuffmanNode child1) {
- this.child0 = child0 ;
- this.child1 = child1 ;
- this.frequency = child0.frequency + child1.frequency ;
- }
-
- void collectLeaves(int tag, int tagLength, Collection collection) {
- if (child0 == null) {
- this.tag = tag ;
- this.tagLength = tagLength ;
- collection.add(this) ;
- } else {
- child0.collectLeaves((tag << 1) | 0, tagLength + 1, collection) ;
- child1.collectLeaves((tag << 1) | 1, tagLength + 1, collection) ;
- }
- }
-
- boolean mergeInto(HuffmanNode node) {
- if (this.absolute == node.absolute) {
- if (this.dataLength > node.dataLength)
- node.dataLength = this.dataLength ;
-
- if (this.shift < node.shift)
- node.shift = this.shift ;
-
- node.frequency += this.frequency ;
- this.mergeNode = node ;
- this.merged = true ;
- return true ;
-
- } else
- return false ;
- }
-
- int incrementLength() {
- if (shift > 0)
- shift-- ;
- else
- dataLength++ ;
-
- return dataLength - shift ;
- }
-
- final boolean merged() {
- return merged ;
- }
-
- final HuffmanNode getMergeNode() {
- return mergeNode ;
- }
-
- void setUnmergeable() {
- unmergeable = true ;
- }
-
- final boolean unmergeable() {
- return unmergeable ;
- }
-
- @Override
- public String toString() {
- return
- "shift " + shift + " data length " + dataLength +
- (absolute? " absolute " : " relative ") +
- "\ntag 0x" + Integer.toHexString(tag) + " tag length " + tagLength +
- "\nfrequency: " + frequency ;
- }
-
- /**
- * Sorts nodes in ascending order by frequency.
- */
- static class FrequencyComparator implements Comparator {
- @Override
- public final int compare(Object o1, Object o2) {
- return ((HuffmanNode)o1).frequency - ((HuffmanNode)o2).frequency ;
- }
- }
-
- /**
- * Sorts nodes in descending order by tag bit length.
- */
- static class TagLengthComparator implements Comparator {
- @Override
- public final int compare(Object o1, Object o2) {
- return ((HuffmanNode)o2).tagLength - ((HuffmanNode)o1).tagLength ;
- }
- }
-
- static FrequencyComparator frequencyComparator = new FrequencyComparator() ;
- static TagLengthComparator tagLengthComparator = new TagLengthComparator() ;
-}
diff --git a/src/classes/share/com/sun/j3d/utils/compression/HuffmanTable.java b/src/classes/share/com/sun/j3d/utils/compression/HuffmanTable.java
deleted file mode 100644
index 881a7ea..0000000
--- a/src/classes/share/com/sun/j3d/utils/compression/HuffmanTable.java
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.compression;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.ListIterator;
-
-/**
- * This class maintains a map from compression stream elements (tokens) onto
- * HuffmanNode objects. A HuffmanNode contains a tag describing the
- * associated token's data length, right shift value, and absolute/relative
- * status.
- *
- * The tags are computed using Huffman's algorithm to build a binary tree with
- * a minimal total weighted path length. The frequency of each token is
- * used as its node's weight when building the tree. The path length from the
- * root to the token's node then indicates the bit length that should be used
- * for that token's tag in order to minimize the total size of the compressed
- * stream.
- */
-class HuffmanTable {
- private static final int MAX_TAG_LENGTH = 6 ;
-
- private HuffmanNode positions[] ;
- private HuffmanNode normals[] ;
- private HuffmanNode colors[] ;
-
- /**
- * Create a new HuffmanTable with entries for all possible position,
- * normal, and color tokens.
- */
- HuffmanTable() {
- //
- // Position and color components can have data lengths up to 16
- // bits, with right shifts up to 15 bits. The position and color
- // lookup tables are therefore 2*17*16=544 entries in length to
- // account for all possible combinations of data lengths, shifts,
- // and relative or absolute status.
- //
- colors = new HuffmanNode[544] ;
- positions = new HuffmanNode[544] ;
-
- //
- // Delta normals can have uv components up to 7 bits in length with
- // right shifts up to 6 bits. Absolute normals can have uv components
- // up to 6 bits in length with right shifts up to 5 bits. The normal
- // lookup table is therefore 2*8*7=112 entries in length.
- //
- normals = new HuffmanNode[112] ;
- }
-
- private final int getPositionIndex(int len, int shift, boolean absolute) {
- return (absolute? 1:0)*272 + len*16 + shift ;
- }
-
- private final int getNormalIndex(int length, int shift, boolean absolute) {
- return (absolute? 1:0)*56 + length*7 + shift ;
- }
-
- private final int getColorIndex(int length, int shift, boolean absolute) {
- return getPositionIndex(length, shift, absolute) ;
- }
-
-
- /**
- * Add a position entry with the given length, shift, and absolute
- * status.
- *
- * @param length number of bits in each X, Y, and Z component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous vertex in the compression stream
- */
- void addPositionEntry(int length, int shift, boolean absolute) {
- addEntry(positions, getPositionIndex(length, shift, absolute),
- length, shift, absolute) ;
- }
-
- /**
- * Get the position entry associated with the specified length, shift, and
- * absolute status. This will contain a tag indicating the actual
- * encoding to be used in the compression command stream, not necessarily
- * the same as the original length and shift with which the the entry was
- * created.
- *
- * @param length number of bits in each X, Y, and Z component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous vertex in the compression stream
- * @return HuffmanNode mapped to the specified parameters
- */
- HuffmanNode getPositionEntry(int length, int shift, boolean absolute) {
- return getEntry(positions, getPositionIndex(length, shift, absolute)) ;
- }
-
- /**
- * Add a color entry with the given length, shift, and absolute
- * status.
- *
- * @param length number of bits in each R, G, B, and A component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous color in the compression stream
- */
- void addColorEntry(int length, int shift, boolean absolute) {
- addEntry(colors, getColorIndex(length, shift, absolute),
- length, shift, absolute) ;
- }
-
- /**
- * Get the color entry associated with the specified length, shift, and
- * absolute status. This will contain a tag indicating the actual
- * encoding to be used in the compression command stream, not necessarily
- * the same as the original length and shift with which the the entry was
- * created.
- *
- * @param length number of bits in each R, G, B, and A component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous color in the compression stream
- * @return HuffmanNode mapped to the specified parameters
- */
- HuffmanNode getColorEntry(int length, int shift, boolean absolute) {
- return getEntry(colors, getColorIndex(length, shift, absolute)) ;
- }
-
- /**
- * Add a normal entry with the given length, shift, and absolute
- * status.
- *
- * @param length number of bits in each U and V component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous normal in the compression stream
- */
- void addNormalEntry(int length, int shift, boolean absolute) {
- addEntry(normals, getNormalIndex(length, shift, absolute),
- length, shift, absolute) ;
- }
-
- /**
- * Get the normal entry associated with the specified length, shift, and
- * absolute status. This will contain a tag indicating the actual
- * encoding to be used in the compression command stream, not necessarily
- * the same as the original length and shift with which the the entry was
- * created.
- *
- * @param length number of bits in each U and V component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous normal in the compression stream
- * @return HuffmanNode mapped to the specified parameters
- */
- HuffmanNode getNormalEntry(int length, int shift, boolean absolute) {
- return getEntry(normals, getNormalIndex(length, shift, absolute)) ;
- }
-
-
- private void addEntry(HuffmanNode table[], int index,
- int length, int shift, boolean absolute) {
-
- if (table[index] == null)
- table[index] = new HuffmanNode(length, shift, absolute) ;
-
- else if (table[index].cleared())
- table[index].set(length, shift, absolute) ;
-
- table[index].addCount() ;
- }
-
- private HuffmanNode getEntry(HuffmanNode table[], int index) {
- HuffmanNode t = table[index] ;
-
- while (t.merged())
- t = t.getMergeNode() ;
-
- return t ;
- }
-
- private void getEntries(HuffmanNode table[], Collection c) {
- for (int i = 0 ; i < table.length ; i++)
- if (table[i] != null && !table[i].cleared() &&
- table[i].hasCount() && !table[i].merged())
- c.add(table[i]) ;
- }
-
-
- /**
- * Clear this HuffmanTable instance.
- */
- void clear() {
- for (int i = 0 ; i < positions.length ; i++)
- if (positions[i] != null)
- positions[i].clear() ;
-
- for (int i = 0 ; i < colors.length ; i++)
- if (colors[i] != null)
- colors[i].clear() ;
-
- for (int i = 0 ; i < normals.length ; i++)
- if (normals[i] != null)
- normals[i].clear() ;
- }
-
- /**
- * Compute optimized tags for each position, color, and normal entry.
- */
- void computeTags() {
- LinkedList nodeList = new LinkedList() ;
- getEntries(positions, nodeList) ;
- computeTags(nodeList, 3) ;
-
- nodeList.clear() ;
- getEntries(colors, nodeList) ;
- computeTags(nodeList, 3) ;
-
- nodeList.clear() ;
- getEntries(normals, nodeList) ;
- computeTags(nodeList, 2) ;
- }
-
- //
- // Compute tags for a list of Huffman tokens.
- //
- private void computeTags(LinkedList nodes, int minComponentCount) {
- HuffmanNode node0, node1, node2 ;
-
- // Return if there's nothing to do.
- if (nodes.isEmpty())
- return ;
-
- while (true) {
- // Sort the nodes in ascending order by frequency.
- Collections.sort(nodes, HuffmanNode.frequencyComparator) ;
-
- // Apply Huffman's algorithm to construct a binary tree with a
- // minimum total weighted path length.
- node0 = (HuffmanNode)nodes.removeFirst() ;
- while (nodes.size() > 0) {
- node1 = (HuffmanNode)nodes.removeFirst() ;
- node2 = new HuffmanNode() ;
-
- node2.addChildren(node0, node1) ;
- addNodeInOrder(nodes, node2, HuffmanNode.frequencyComparator) ;
-
- node0 = (HuffmanNode)nodes.removeFirst() ;
- }
-
- // node0 is the root of the resulting binary tree. Traverse it
- // assigning tags and lengths to the leaf nodes. The leaves are
- // collected into the now empty node list.
- node0.collectLeaves(0, 0, nodes) ;
-
- // Sort the nodes in descending order by tag length.
- Collections.sort(nodes, HuffmanNode.tagLengthComparator) ;
-
- // Check for tag length overrun.
- if (((HuffmanNode)nodes.getFirst()).tagLength > MAX_TAG_LENGTH) {
- // Tokens need to be merged and the tree rebuilt with the new
- // combined frequencies.
- merge(nodes) ;
-
- } else {
- // Increase tag length + data length if they're too small.
- expand(nodes, minComponentCount) ;
- break ;
- }
- }
- }
-
- //
- // Merge a token with a long tag into some other token. The merged token
- // will be removed from the list along with any duplicate node the merge
- // created, reducing the size of the list by 1 or 2 elements until only
- // unmergeable tokens are left.
- //
- private void merge(LinkedList nodes) {
- ListIterator i = nodes.listIterator(0) ;
- HuffmanNode node0, node1, node2 ;
- int index = 0 ;
-
- while (i.hasNext()) {
- // Get the node with the longest possibly mergeable tag.
- node0 = (HuffmanNode)i.next() ;
- if (node0.unmergeable()) continue ;
-
- // Try to find a node that can be merged with node0. This is any
- // node that matches its absolute/relative status.
- i.remove() ;
- while (i.hasNext()) {
- node1 = (HuffmanNode)i.next() ;
- if (node0.mergeInto(node1)) {
- // Search for a duplicate of the possibly modified node1
- // and merge into it so that node weights remain valid.
- // If a duplicate exists it must be further in the list,
- // otherwise node0 would have merged into it.
- i.remove() ;
- while (i.hasNext()) {
- node2 = (HuffmanNode)i.next() ;
- if (node1.tokenEquals(node2)) {
- node1.mergeInto(node2) ;
- return ;
- }
- }
- // node1 has no duplicate, so return it to the list.
- i.add(node1) ;
- return ;
- }
- }
-
- // node0 can't be merged with any other node; it must be the only
- // relative or absolute node in the list. Mark it as unmergeable
- // to avoid unnecessary searches on subsequent calls to merge()
- // and return it to the list.
- node0.setUnmergeable() ;
- i.add(node0) ;
-
- // Restart the iteration.
- i = nodes.listIterator(0) ;
- }
- }
-
- //
- // Empty bits within a compression command header are not allowed. If
- // the tag length plus the total data length is less than 6 bits then
- // the token's length must be increased.
- //
- private void expand(LinkedList nodes, int minComponentCount) {
- Iterator i = nodes.iterator() ;
-
- while (i.hasNext()) {
- HuffmanNode n = (HuffmanNode)i.next() ;
-
- while (n.tagLength +
- (minComponentCount * (n.dataLength - n.shift)) < 6) {
-
- n.incrementLength() ;
- }
- }
- }
-
- //
- // Insert a node into the correct place in a sorted list of nodes.
- //
- private void addNodeInOrder(LinkedList l, HuffmanNode node, Comparator c) {
- ListIterator i = l.listIterator(0) ;
-
- while (i.hasNext()) {
- HuffmanNode n = (HuffmanNode)i.next() ;
- if (c.compare(n, node) > 0) {
- n = (HuffmanNode)i.previous() ;
- break ;
- }
- }
- i.add(node) ;
- }
-
- /**
- * Create compression stream commands for decompressors to use to set up
- * their decompression tables.
- *
- * @param output CommandStream which receives the compression commands
- */
- void outputCommands(CommandStream output) {
- LinkedList nodeList = new LinkedList() ;
- getEntries(positions, nodeList) ;
- outputCommands(nodeList, output, CommandStream.POSITION_TABLE) ;
-
- nodeList.clear() ;
- getEntries(colors, nodeList) ;
- outputCommands(nodeList, output, CommandStream.COLOR_TABLE) ;
-
- nodeList.clear() ;
- getEntries(normals, nodeList) ;
- outputCommands(nodeList, output, CommandStream.NORMAL_TABLE) ;
- }
-
- //
- // Output a setTable command for each unique token.
- //
- private void outputCommands(Collection nodes,
- CommandStream output, int tableId) {
-
- Iterator i = nodes.iterator() ;
- while (i.hasNext()) {
- HuffmanNode n = (HuffmanNode)i.next() ;
- int addressRange = (1 << n.tagLength) | n.tag ;
- int dataLength = (n.dataLength == 16? 0 : n.dataLength) ;
-
- int command =
- CommandStream.SET_TABLE | (tableId << 1) | (addressRange >> 6) ;
-
- long body =
- ((addressRange & 0x3f) << 9) | (dataLength << 5) |
- (n.absolute? 0x10 : 0) | n.shift ;
-
- output.addCommand(command, 8, body, 15) ;
- }
- }
-
- /**
- * Print a collection of HuffmanNode objects to standard out.
- *
- * @param header descriptive string
- * @param nodes Collection of HuffmanNode objects to print
- */
- void print(String header, Collection nodes) {
- System.out.println(header + "\nentries: " + nodes.size() + "\n") ;
-
- Iterator i = nodes.iterator() ;
- while(i.hasNext()) {
- HuffmanNode n = (HuffmanNode)i.next() ;
- System.out.println(n.toString() + "\n") ;
- }
- }
-
- /**
- * Print the contents of this instance to standard out.
- */
- void print() {
- LinkedList nodeList = new LinkedList() ;
-
- getEntries(positions, nodeList) ;
- Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
- print("\nposition tokens and tags", nodeList) ;
-
- nodeList.clear() ;
- getEntries(colors, nodeList) ;
- Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
- print("\ncolor tokens and tags", nodeList) ;
-
- nodeList.clear() ;
- getEntries(normals, nodeList) ;
- Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
- print("\nnormal tokens and tags", nodeList) ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/compression/MeshBuffer.java b/src/classes/share/com/sun/j3d/utils/compression/MeshBuffer.java
deleted file mode 100644
index 59701d1..0000000
--- a/src/classes/share/com/sun/j3d/utils/compression/MeshBuffer.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.compression;
-
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3f;
-
-/**
- * This class mirrors the vertex mesh buffer stack supported by the geometry
- * compression semantics.
- */
-class MeshBuffer {
- //
- // The fixed-length mesh buffer stack is represented by circular buffers.
- // Three stack representations are provided: vertices, positions, and
- // indices.
- //
- // The vertex representation stores references to CompressionStreamVertex
- // objects. The position representation stores references to Point3f,
- // Vector3f, Color3f, and Color4f objects, while the index representation
- // stores indices into externally maintained arrays of those objects. All
- // these representations may be used independently and all provide access
- // to the stored references via a mesh buffer index.
- //
- // In addition, the position and index representations provide lookup
- // mechanisms to check if positions or indices exist in the mesh buffer
- // and return their mesh buffer indices if they do. This is used to
- // implement a limited meshing algorithm which reduces the number of
- // vertices when non-stripped abutting facets are added to a compression
- // stream.
- //
- static final int NOT_FOUND = -1 ;
-
- private static final int SIZE = 16 ;
- private static final int NAN_HASH =
- new Point3f(Float.NaN, Float.NaN, Float.NaN).hashCode() ;
-
- private int topIndex = SIZE - 1 ;
- private int positionIndices[] = new int[SIZE] ;
- private int normalIndices[] = new int[SIZE] ;
- private int colorIndices[] = new int[SIZE] ;
-
- private int topPosition = SIZE - 1 ;
- private int positionHashCodes[] = new int[SIZE] ;
- private Point3f positions[] = new Point3f[SIZE] ;
- private Vector3f normals[] = new Vector3f[SIZE] ;
- private Color3f colors3[] = new Color3f[SIZE] ;
- private Color4f colors4[] = new Color4f[SIZE] ;
-
- private int topVertex = SIZE - 1 ;
- private CompressionStreamVertex vertices[] =
- new CompressionStreamVertex[SIZE] ;
-
- MeshBuffer() {
- for (int i = 0 ; i < SIZE ; i++) {
- positionHashCodes[i] = NAN_HASH ;
-
- positionIndices[i] = NOT_FOUND ;
- normalIndices[i] = NOT_FOUND ;
- colorIndices[i] = NOT_FOUND ;
- }
- }
-
- private static int nextTop(int top) {
- // The stack top references an element in the fixed-length backing
- // array in which the stack is stored. Stack elements below it have
- // decreasing indices into the backing array until element 0, at which
- // point the indices wrap to the end of the backing array and back to
- // the top.
- //
- // A push is accomplished by incrementing the stack top in a circular
- // buffer and storing the data into the new stack element it
- // references. The bottom of the stack is the element with the next
- // higher index from the top in the backing array, and is overwritten
- // with each new push.
- return (top + 1) % SIZE ;
- }
-
- private static int flipOffset(int top, int offset) {
- // Flips an offset relative to the beginning of the backing array to
- // an offset from the top of the stack. Also works in reverse, from
- // an offset from the top of the stack to an offset from the beginning
- // of the backing array.
- if (offset > top) offset -= SIZE ;
- return top - offset ;
- }
-
- //
- // Mesh buffer vertex stack. This is currently only used for vertex
- // lookup during the quantization pass in order to compute delta values;
- // no mesh reference lookup is necessary.
- //
- void push(CompressionStreamVertex v) {
- topVertex = nextTop(topVertex) ;
- vertices[topVertex] = v ;
- }
-
- CompressionStreamVertex getVertex(int meshReference) {
- return vertices[flipOffset(topVertex, meshReference)] ;
- }
-
-
- //
- // Mesh buffer index stack and index reference lookup support.
- //
- void push(int positionIndex, int normalIndex) {
- topIndex = nextTop(topIndex) ;
-
- positionIndices[topIndex] = positionIndex ;
- normalIndices[topIndex] = normalIndex ;
- }
-
- void push(int positionIndex, int colorIndex, int normalIndex) {
- push(positionIndex, normalIndex) ;
- colorIndices[topIndex] = colorIndex ;
- }
-
- int getMeshReference(int positionIndex) {
- int index ;
- for (index = 0 ; index < SIZE ; index++)
- if (positionIndices[index] == positionIndex)
- break ;
-
- if (index == SIZE) return NOT_FOUND ;
- return flipOffset(topIndex, index) ;
- }
-
- int getPositionIndex(int meshReference) {
- return positionIndices[flipOffset(topIndex, meshReference)] ;
- }
-
- int getColorIndex(int meshReference) {
- return colorIndices[flipOffset(topIndex, meshReference)] ;
- }
-
- int getNormalIndex(int meshReference) {
- return normalIndices[flipOffset(topIndex, meshReference)] ;
- }
-
-
- //
- // Mesh buffer position stack and position reference lookup support.
- //
- void push(Point3f position, Vector3f normal) {
- topPosition = nextTop(topPosition) ;
-
- positionHashCodes[topPosition] = position.hashCode() ;
- positions[topPosition] = position ;
- normals[topPosition] = normal ;
- }
-
- void push(Point3f position, Color3f color, Vector3f normal) {
- push(position, normal) ;
- colors3[topPosition] = color ;
- }
-
- void push(Point3f position, Color4f color, Vector3f normal) {
- push(position, normal) ;
- colors4[topPosition] = color ;
- }
-
- void push(Point3f position, Object color, Vector3f normal) {
- push(position, normal) ;
- if (color instanceof Color3f)
- colors3[topPosition] = (Color3f)color ;
- else
- colors4[topPosition] = (Color4f)color ;
- }
-
- int getMeshReference(Point3f position) {
- int index ;
- int hashCode = position.hashCode() ;
-
- for (index = 0 ; index < SIZE ; index++)
- if (positionHashCodes[index] == hashCode)
- if (positions[index].equals(position))
- break ;
-
- if (index == SIZE) return NOT_FOUND ;
- return flipOffset(topPosition, index) ;
- }
-
- Point3f getPosition(int meshReference) {
- return positions[flipOffset(topPosition, meshReference)] ;
- }
-
- Color3f getColor3(int meshReference) {
- return colors3[flipOffset(topPosition, meshReference)] ;
- }
-
- Color4f getColor4(int meshReference) {
- return colors4[flipOffset(topPosition, meshReference)] ;
- }
-
- Vector3f getNormal(int meshReference) {
- return normals[flipOffset(topPosition, meshReference)] ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/compression/package.html b/src/classes/share/com/sun/j3d/utils/compression/package.html
deleted file mode 100644
index 628453b..0000000
--- a/src/classes/share/com/sun/j3d/utils/compression/package.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
- Deprecated: Use
- * By default all primitives with the same parameters share their
- * geometry (e.g., you can have 50 shperes in your scene, but the
- * geometry is stored only once). A change to one primitive will
- * effect all shared nodes. Another implication of this
- * implementation is that the capabilities of the geometry are shared,
- * and once one of the shared nodes is live, the capabilities cannot
- * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to
- * share geometry among primitives with the same parameters.
- */
-
-public class Box extends Primitive {
-
- /**
- * Used to designate the front side of the box when using
- * getShape().
- *
- * @see Box#getShape
- */
- public static final int FRONT = 0;
-
- /**
- * Used to designate the back side of the box when using
- * getShape().
- *
- * @see Box#getShape
- */
- public static final int BACK = 1;
-
- /**
- * Used to designate the right side of the box when using
- * getShape().
- *
- * @see Box#getShape
- */
- public static final int RIGHT = 2;
-
- /**
- * Used to designate the left side of the box when using
- * getShape().
- *
- * @see Box#getShape
- */
- public static final int LEFT = 3;
-
- /**
- * Used to designate the top side of the box when using
- * getShape().
- *
- * @see Box#getShape
- */
- public static final int TOP = 4;
-
- /**
- * Used to designate the bottom side of the box when using
- * getShape().
- *
- * @see Box#getShape
- */
- public static final int BOTTOM = 5;
-
- float xDim, yDim, zDim;
-
- int numTexUnit = 1;
-
- /**
- * Constructs a default box of 1.0 in all dimensions.
- * Normals are generated by default, texture coordinates are not.
- */
-
- public Box()
- {
- this(1.0f, 1.0f, 1.0f, GENERATE_NORMALS, null);
- }
-
- /**
- * Constructs a box of a given dimension and appearance.
- * Normals are generated by default, texture coordinates are not.
- *
- * @param xdim X-dimension size.
- * @param ydim Y-dimension size.
- * @param zdim Z-dimension size.
- * @param ap Appearance
- */
-
- public Box(float xdim, float ydim, float zdim, Appearance ap)
- {
- this(xdim, ydim, zdim, GENERATE_NORMALS, ap);
- }
-
- /**
- * Constructs a box of a given dimension, flags, and appearance.
- *
- * @param xdim X-dimension size.
- * @param ydim Y-dimension size.
- * @param zdim Z-dimension size.
- * @param primflags primitive flags.
- * @param ap Appearance
- */
-
- public Box(float xdim, float ydim, float zdim, int primflags,
- Appearance ap, int numTexUnit) {
- int i;
- double sign;
-
- xDim = xdim;
- yDim = ydim;
- zDim = zdim;
- flags = primflags;
- this.numTexUnit = numTexUnit;
- boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0;
-
- //Depending on whether normal inward bit is set.
- if ((flags & GENERATE_NORMALS_INWARD) != 0)
- sign = -1.0;
- else sign = 1.0;
-
-
-// TransformGroup objTrans = new TransformGroup();
-// objTrans.setCapability(ALLOW_CHILDREN_READ);
-// this.addChild(objTrans);
-
- Shape3D shape[] = new Shape3D[6];
-
- GeomBuffer cache = null;
-
- for (i = FRONT; i <= BOTTOM; i++){
-
- cache = getCachedGeometry(Primitive.BOX, xdim, ydim, zdim, i, i,
- primflags);
- if (cache != null) {
-// System.out.println("using cached geometry i = " + i);
- shape[i] = new Shape3D(cache.getComputedGeometry());
- numVerts += cache.getNumVerts();
- numTris += cache.getNumTris();
- }
- else {
-
- GeomBuffer gbuf = new GeomBuffer(4, numTexUnit);
-
- gbuf.begin(GeomBuffer.QUAD_STRIP);
- for (int j = 0; j < 2; j++){
- gbuf.normal3d( (double) normals[i].x*sign,
- (double) normals[i].y*sign,
- (double) normals[i].z*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(tcoords[i*8 + j*2], 1.0 - tcoords[i*8 + j*2 + 1]);
- }
- else {
- gbuf.texCoord2d(tcoords[i*8 + j*2], tcoords[i*8 + j*2 + 1]);
- }
-
- gbuf.vertex3d( (double) verts[i*12 + j*3]*xdim,
- (double) verts[i*12+ j*3 + 1]*ydim,
- (double) verts[i*12+ j*3 + 2]*zdim );
- }
- for (int j = 3; j > 1; j--){
- gbuf.normal3d( (double) normals[i].x*sign,
- (double) normals[i].y*sign,
- (double) normals[i].z*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(tcoords[i*8 + j*2], 1.0 - tcoords[i*8 + j*2 + 1]);
- }
- else {
- gbuf.texCoord2d(tcoords[i*8 + j*2], tcoords[i*8 + j*2 + 1]);
- }
- gbuf.vertex3d( (double) verts[i*12 + j*3]*xdim,
- (double) verts[i*12+ j*3 + 1]*ydim,
- (double) verts[i*12+ j*3 + 2]*zdim );
- }
- gbuf.end();
- shape[i] = new Shape3D(gbuf.getGeom(flags));
- numVerts = gbuf.getNumVerts();
- numTris = gbuf.getNumTris();
-
- if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
- cacheGeometry(Primitive.BOX, xdim, ydim, zdim, i, i,
- primflags, gbuf);
- }
- }
-
- if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
- (shape[i]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
- (shape[i]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
- }
-
- if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
- (shape[i]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
- }
-
-// objTrans.addChild(shape[i]);
- this.addChild(shape[i]);
- }
-
- if (ap == null){
- setAppearance();
- }
- else setAppearance(ap);
- }
-
- public Box(float xdim, float ydim, float zdim, int primflags,
- Appearance ap) {
- this(xdim, ydim, zdim, primflags, ap, 1);
- }
-
- /**
- * Gets one of the faces (Shape3D) from the box that contains the
- * geometry and appearance. This allows users to modify the
- * appearance or geometry of individual parts.
- * @param partId The part to return.
- * @return The Shape3D object associated with the partID. If an
- * invalid partId is passed in, null is returned.
- */
-
- @Override
- public Shape3D getShape(int partId) {
- if ((partId >= FRONT) && (partId <= BOTTOM))
-// return (Shape3D)(((Group)getChild(0)).getChild(partId));
- return (Shape3D)getChild(partId);
- return null;
- }
-
- /**
- * Sets appearance of the box. This will set each face of the
- * box to the same appearance. To set each face's appearance
- * separately, use getShape(partId) to get the
- * individual shape and call shape.setAppearance(ap).
- */
-
- @Override
- public void setAppearance(Appearance ap){
-// ((Shape3D)((Group)getChild(0)).getChild(TOP)).setAppearance(ap);
-// ((Shape3D)((Group)getChild(0)).getChild(LEFT)).setAppearance(ap);
-// ((Shape3D)((Group)getChild(0)).getChild(RIGHT)).setAppearance(ap);
-// ((Shape3D)((Group)getChild(0)).getChild(FRONT)).setAppearance(ap);
-// ((Shape3D)((Group)getChild(0)).getChild(BACK)).setAppearance(ap);
-// ((Shape3D)((Group)getChild(0)).getChild(BOTTOM)).setAppearance(ap);
- ((Shape3D)getChild(TOP)).setAppearance(ap);
- ((Shape3D)getChild(LEFT)).setAppearance(ap);
- ((Shape3D)getChild(RIGHT)).setAppearance(ap);
- ((Shape3D)getChild(FRONT)).setAppearance(ap);
- ((Shape3D)getChild(BACK)).setAppearance(ap);
- ((Shape3D)getChild(BOTTOM)).setAppearance(ap);
- }
-
- /**
- * Gets the appearance of the specified part of the box.
- *
- * @param partId identifier for a given subpart of the box
- *
- * @return The appearance object associated with the partID. If an
- * invalid partId is passed in, null is returned.
- *
- * @since Java 3D 1.2.1
- */
- @Override
- public Appearance getAppearance(int partId) {
- if (partId > BOTTOM || partId < FRONT) return null;
- return getShape(partId).getAppearance();
- }
-
-
- private static final float[] verts = {
- // front face
- 1.0f, -1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f,
--1.0f, 1.0f, 1.0f,
--1.0f, -1.0f, 1.0f,
- // back face
--1.0f, -1.0f, -1.0f,
--1.0f, 1.0f, -1.0f,
- 1.0f, 1.0f, -1.0f,
- 1.0f, -1.0f, -1.0f,
- // right face
- 1.0f, -1.0f, -1.0f,
- 1.0f, 1.0f, -1.0f,
- 1.0f, 1.0f, 1.0f,
- 1.0f, -1.0f, 1.0f,
- // left face
--1.0f, -1.0f, 1.0f,
--1.0f, 1.0f, 1.0f,
--1.0f, 1.0f, -1.0f,
--1.0f, -1.0f, -1.0f,
- // top face
- 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, -1.0f,
--1.0f, 1.0f, -1.0f,
--1.0f, 1.0f, 1.0f,
- // bottom face
--1.0f, -1.0f, 1.0f,
--1.0f, -1.0f, -1.0f,
- 1.0f, -1.0f, -1.0f,
- 1.0f, -1.0f, 1.0f,
- };
-
- private static final double[] tcoords = {
- // front
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- 0.0, 0.0,
- // back
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- 0.0, 0.0,
- //right
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- 0.0, 0.0,
- // left
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- 0.0, 0.0,
- // top
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- 0.0, 0.0,
- // bottom
- 0.0, 1.0,
- 0.0, 0.0,
- 1.0, 0.0,
- 1.0, 1.0
- };
-
-
- private static final Vector3f[] normals = {
- new Vector3f( 0.0f, 0.0f, 1.0f), // front face
- new Vector3f( 0.0f, 0.0f, -1.0f), // back face
- new Vector3f( 1.0f, 0.0f, 0.0f), // right face
- new Vector3f(-1.0f, 0.0f, 0.0f), // left face
- new Vector3f( 0.0f, 1.0f, 0.0f), // top face
- new Vector3f( 0.0f, -1.0f, 0.0f), // bottom face
- };
-
-
- /**
- * Used to create a new instance of the node. This routine is called
- * by
- * For any NodeComponent objects
- * contained by the object being duplicated, each NodeComponent
- * object's
- * If the GENERATE_TEXTURE_COORDS flag is set, the texture coordinates
- * are generated such that the texture gets mapped onto the cone similarly
- * to how it gets mapped onto a cylinder, the difference being the top
- * cap is nonexistent.
- *
- * By default all primitives with the same parameters share their
- * geometry (e.g., you can have 50 shperes in your scene, but the
- * geometry is stored only once). A change to one primitive will
- * effect all shared nodes. Another implication of this
- * implementation is that the capabilities of the geometry are shared,
- * and once one of the shared nodes is live, the capabilities cannot
- * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to
- * share geometry among primitives with the same parameters.
- */
-public class Cone extends Primitive {
- float radius, height;
- int xdivisions, ydivisions;
- static final int MID_REZ_DIV_X = 15;
- static final int MID_REZ_DIV_Y = 1;
-
- /**
- * Designates the body of the cone. Used by
- * If appearance is null, the default white appearance will be used.
- * @param radius Radius
- * @param height Height
- * @param xdivision Number of divisions along X direction.
- * @param ydivision Number of divisions along the height of cone.
- * @param primflags flags
- * @param ap Appearance
- */
-
- public Cone(float radius, float height, int primflags,
- int xdivision, int ydivision,
- Appearance ap)
- {
- super();
-
- Shape3D shape[] = new Shape3D[2];
- this.radius = radius;
- this.height = height;
- xdivisions = xdivision;
- ydivisions = ydivision;
- flags = primflags;
- boolean outside = (flags & GENERATE_NORMALS_INWARD) == 0;
- boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0;
- Quadrics q = new Quadrics();
- GeomBuffer gbuf = null;
-
- GeomBuffer cache = getCachedGeometry(Primitive.CONE,
- radius, 0.0f, height,
- xdivision, ydivision, primflags);
- if (cache != null){
-// System.out.println("using cached geometry");
- shape[BODY] = new Shape3D(cache.getComputedGeometry());
- numVerts += cache.getNumVerts();
- numTris += cache.getNumTris();
- }
- else {
- // the body of the cone consists of the top of the cone and if
- // ydivisions is greater than 1, the body of the cone.
- gbuf = q.coneTop((double)(height/2.0 - height/ydivisions),
- (double)(radius/ydivisions), height/ydivisions,
- xdivisions, 1.0-1.0/(double)ydivisions,
- outside, texCoordYUp);
- shape[BODY] = new Shape3D(gbuf.getGeom(flags));
- numVerts += gbuf.getNumVerts();
- numTris += gbuf.getNumTris();
- if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
- cacheGeometry(Primitive.CONE,
- radius, 0.0f, height,
- xdivision, ydivision, primflags, gbuf);
- }
- }
-
- // only need to add a body if the ydivisions is greater than 1
- if (ydivisions > 1) {
- cache = getCachedGeometry(Primitive.CONE_DIVISIONS, radius, 0.0f,
- height, xdivision, ydivision, primflags);
- if (cache != null) {
-// System.out.println("using cached divisions");
- shape[BODY].addGeometry(cache.getComputedGeometry());
- numVerts += cache.getNumVerts();
- numTris += cache.getNumTris();
- }
- else {
- gbuf = q.coneBody(-(double)(height/2.0),
- (double)(height/2.0-height/ydivisions),
- (double)radius, (double)(radius/ydivisions),
- xdivisions, ydivisions-1, 1.0/(double)ydivisions,
- outside, texCoordYUp);
- shape[BODY].addGeometry(gbuf.getGeom(flags));
- numVerts += gbuf.getNumVerts();
- numTris += gbuf.getNumTris();
- if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
- cacheGeometry(Primitive.CONE_DIVISIONS, radius, 0.0f, height,
- xdivision, ydivision, primflags, gbuf);
- }
- }
- }
-
- if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
- (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
- (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
- }
-
- if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
- (shape[BODY]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
- }
-
- this.addChild(shape[BODY]);
-
- // Create bottom cap.
- cache = getCachedGeometry(Primitive.BOTTOM_DISK, radius,
- radius, -height/2.0f, xdivision, xdivision,
- primflags);
- if (cache != null) {
-// System.out.println("using cached bottom");
- shape[CAP] = new Shape3D(cache.getComputedGeometry());
- numVerts += cache.getNumVerts();
- numTris += cache.getNumTris();
- }
- else {
- gbuf = q.disk((double)radius, xdivision, -(double)height/2.0,
- !outside, texCoordYUp);
- shape[CAP] = new Shape3D(gbuf.getGeom(flags));
- numVerts += gbuf.getNumVerts();
- numTris += gbuf.getNumTris();
- if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
- cacheGeometry(Primitive.BOTTOM_DISK, radius, radius, -height/2.0f,
- xdivision, xdivision, primflags, gbuf);
- }
- }
-
- if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
- (shape[CAP]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
- (shape[CAP]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
- }
-
- if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
- (shape[CAP]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
- }
-
-// Transform3D t2 = new Transform3D();
-
- // Flip it to match up the texture coords.
-/* This causes the bottom not to match up for odd xdivision values
- objectMat = new Matrix4d();
- objectMat.setIdentity();
- rotMat = new Matrix4d();
- rotMat.setIdentity();
- rotMat.rotZ(Math.PI);
- objectMat.mul(objectMat, rotMat);
- t2.set(objectMat);
-*/
-
- this.addChild(shape[CAP]);
-
- if (ap == null){
- setAppearance();
- }
- else setAppearance(ap);
- }
-
- /**
- * Used to create a new instance of the node. This routine is called
- * by
- * For any NodeComponent objects
- * contained by the object being duplicated, each NodeComponent
- * object's
- * When a texture is applied to a cylinder, the texture is applied to the
- * caps and the body different. A texture is mapped CCW from the back of the
- * body. The top and bottom caps are mapped such that the texture appears
- * front facing when the caps are rotated 90 degrees toward the viewer.
- *
- * By default all primitives with the same parameters share their
- * geometry (e.g., you can have 50 shperes in your scene, but the
- * geometry is stored only once). A change to one primitive will
- * effect all shared nodes. Another implication of this
- * implementation is that the capabilities of the geometry are shared,
- * and once one of the shared nodes is live, the capabilities cannot
- * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to
- * share geometry among primitives with the same parameters.
- */
-
-public class Cylinder extends Primitive{
- float radius, height;
- int xdivisions, ydivisions;
-
- static final int MID_REZ_DIV_X = 15;
- static final int MID_REZ_DIV_Y = 1;
-
- /**
- * Designates the body of the cylinder. Used by
- * For any NodeComponent objects
- * contained by the object being duplicated, each NodeComponent
- * object's
- * Here is a sample code that use this utility to create some quads.
- *
- * Currently, you are limited to one primitive type per geom buffer. Future
- * versions will add support for mixed primitive types.
- *
- **/
-
-class GeomBuffer extends Object{
-
- //Supported Primitives
- static final int QUAD_STRIP = 0x01;
- static final int TRIANGLES = 0x02;
- static final int QUADS = 0x04;
- static final int TRIANGLE_FAN = 0x10;
- static final int TRIANGLE_STRIP = 0x20;
-
- private int flags;
-
- Point3f[] pts = null;
- Vector3f[] normals = null;
- TexCoord2f[] tcoords = null;
- int currVertCnt;
- int currPrimCnt;
- int[] currPrimType = null,
- currPrimStartVertex = null,
- currPrimEndVertex = null;
- GeometryArray geometry;
- int numVerts = 0;
- int numTris = 0;
- int numTexUnit = 1;
- int texCoordSetMap[] = null;
-
-
- static final int debug = 0;
-
- /** Creates a geometry buffer of given number of vertices
- * @param numVerts total number of vertices to allocate by this buffer.
- * This is an upper bound estimate.
- */
- GeomBuffer(int numVerts, int numTexUnit)
- {
- this.numTexUnit = numTexUnit;
- pts = new Point3f[numVerts];
- normals = new Vector3f[numVerts];
- tcoords = new TexCoord2f[numVerts];
- // max primitives is numV/3
- currPrimType = new int[numVerts/3];
- currPrimStartVertex = new int[numVerts/3];
- currPrimEndVertex = new int[numVerts/3];
- currVertCnt = 0;
- currPrimCnt = 0;
-
- texCoordSetMap = new int[numTexUnit];
- for (int i = 0; i < numTexUnit; i++)
- texCoordSetMap[i] = 0;
-
- }
-
- GeomBuffer(int numVerts)
- {
- this(numVerts, 1);
- }
-
- /*
- * Returns a Java 3D geometry array from the geometry buffer. You need to
- * call begin, vertex3d, end, etc. before calling this, of course.
- *
- * @param format vertex format.
- */
-
- GeometryArray getGeom(int format)
- {
- GeometryArray obj = null;
- flags = format;
-
- numTris = 0;
-
- //Switch based on first primitive.
- switch (currPrimType[0]){
- case TRIANGLES:
- obj = processTriangles();
- break;
- case QUADS:
- obj = processQuads();
- break;
- case QUAD_STRIP:
- case TRIANGLE_STRIP:
- obj = processQuadStrips();
- break;
- case TRIANGLE_FAN:
- obj = processTriangleFan();
- break;
- }
- if ((obj != null) && ((flags & Primitive.ENABLE_GEOMETRY_PICKING) != 0)) {
- obj.setCapability(Geometry.ALLOW_INTERSECT);
- obj.setCapability(GeometryArray.ALLOW_FORMAT_READ);
- obj.setCapability(GeometryArray.ALLOW_COUNT_READ);
- obj.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
- }
- return obj;
- }
-
-
- /**
- * Begins a new primitive given the primitive type.
- *
- * @param prim the primitive type (listed above).
- *
- **/
-
- void begin(int prim)
- {
- if (debug >= 1) System.out.println("quad");
- currPrimType[currPrimCnt] = prim;
- currPrimStartVertex[currPrimCnt] = currVertCnt;
- }
-
-
- /**
- * End of primitive.
- *
- *
- **/
- void end()
- {
- if (debug >= 1) System.out.println("end");
- currPrimEndVertex[currPrimCnt] = currVertCnt;
- currPrimCnt++;
- }
-
- void vertex3d(double x, double y, double z)
- {
-
- if (debug >= 2) System.out.println("v " + x + " " +
- y + " " +
- z);
- pts[currVertCnt] = new Point3f((float)x, (float)y, (float)z);
- currVertCnt++;
- }
-
- void normal3d(double x, double y, double z)
- {
- if (debug >= 2) System.out.println("n " + x + " " +
- y + " " + z);
- double sum = x*x+y*y+z*z;
- if (Math.abs(sum - 1.0) > 0.001){
- if (debug >= 2) System.out.println("normalizing");
- double root = Math.sqrt(sum);
- if (root > 0.000001) {
- x /= root;
- y /= root;
- z /= root;
- } else {
- y = z = 0.0; x = 1.0;
- }
- }
- normals[currVertCnt] = new Vector3f((float)x, (float)y, (float)z);
- }
-
- void texCoord2d(double s, double t)
- {
- if (debug >= 2) System.out.println("t " +
- s + " " +
- t);
- tcoords[currVertCnt] = new TexCoord2f((float)s, (float)t);
- }
-
- // Return a reference to the texture coordinates of this geom buffer.
- TexCoord2f[] getTexCoords() {
- return tcoords;
- }
-
- /**
- * Returns the Java 3D geometry gotten from calling getGeom.
- *
- **/
-
- GeometryArray getComputedGeometry()
- {
- return geometry;
- }
-
- int getNumTris()
- {
- return numTris;
- }
-
- int getNumVerts()
- {
- return numVerts;
- }
-
-
- private GeometryArray processQuadStrips()
- {
- GeometryArray obj = null;
- int i;
- int totalVerts = 0;
-
- // Calculate how many vertices needed to hold all of the individual quads
- int stripCounts[] = new int[currPrimCnt];
- for (i = 0; i < currPrimCnt; i++){
- stripCounts[i] = currPrimEndVertex[i] - currPrimStartVertex[i];
- totalVerts += stripCounts[i];
- }
-
- if (debug >= 1) System.out.println("totalVerts " + totalVerts);
-
- int tsaFlags = TriangleStripArray.COORDINATES;
- if ((flags & Primitive.GENERATE_NORMALS) != 0)
- tsaFlags |= TriangleStripArray.NORMALS;
- if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
- tsaFlags |= TriangleStripArray.TEXTURE_COORDINATE_2;
-
- // Create GeometryArray to pass back
- obj = new TriangleStripArray(totalVerts, tsaFlags,
- 1, texCoordSetMap, stripCounts);
-
- // Allocate space to store new vertex info
- Point3f[] newpts = new Point3f[totalVerts];
- Vector3f[] newnormals = new Vector3f[totalVerts];
- TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
- int currVert = 0;
-
- // Repeat for each Quad Strip
- for (i = 0; i < currPrimCnt; i++){
- // Output order for these quad arrays same as java 3d triangle strips
- for (int j = currPrimStartVertex[i] ; j < currPrimEndVertex[i] ; j++){
- outVertex(newpts, newnormals, newtcoords, currVert++,
- pts, normals, tcoords, j);
- }
-
- }
-
- numVerts = currVert;
- numTris += totalVerts - currPrimCnt * 2;
-
- obj.setCoordinates(0, newpts);
- if ((flags & Primitive.GENERATE_NORMALS) != 0)
- obj.setNormals(0, newnormals);
- if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
- obj.setTextureCoordinates(0, 0, newtcoords);
-
- geometry = obj;
- return obj;
- }
-
- private GeometryArray processQuads()
- {
- GeometryArray obj = null;
- int i;
- int totalVerts = 0;
-
- for (i = 0; i < currPrimCnt; i++){
- totalVerts += currPrimEndVertex[i] - currPrimStartVertex[i];
- }
-
- if (debug >= 1) System.out.println("totalVerts " + totalVerts);
-
- if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
- ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
- obj = new QuadArray(totalVerts,
- QuadArray.COORDINATES |
- QuadArray.NORMALS |
- QuadArray.TEXTURE_COORDINATE_2,
- 1, texCoordSetMap);
- }
- else
- if (((flags & Primitive.GENERATE_NORMALS) == 0) &&
- ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
- obj = new QuadArray(totalVerts,
- QuadArray.COORDINATES |
- QuadArray.TEXTURE_COORDINATE_2,
- 1, texCoordSetMap);
- }
- else
- if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
- ((flags & Primitive.GENERATE_TEXTURE_COORDS) == 0)){
- obj = new QuadArray(totalVerts,
- QuadArray.COORDINATES |
- QuadArray.NORMALS);
- }
- else {
- obj = new QuadArray(totalVerts,
- QuadArray.COORDINATES);
- }
-
- Point3f[] newpts = new Point3f[totalVerts];
- Vector3f[] newnormals = new Vector3f[totalVerts];
- TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
- int currVert = 0;
-
- if (debug > 1) System.out.println("total prims " + currPrimCnt);
-
- for (i = 0; i < currPrimCnt; i++){
- if (debug > 1) System.out.println("start " + currPrimStartVertex[i] +
- " end " + currPrimEndVertex[i]);
- for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i] - 3;j+=4){
- outVertex(newpts, newnormals, newtcoords, currVert++,
- pts, normals, tcoords, j);
- outVertex(newpts, newnormals, newtcoords, currVert++,
- pts, normals, tcoords, j + 1);
- outVertex(newpts, newnormals, newtcoords, currVert++,
- pts, normals, tcoords, j + 2);
- outVertex(newpts, newnormals, newtcoords, currVert++,
- pts, normals, tcoords, j + 3);
- numTris += 2;
- }
- }
- numVerts = currVert;
-
- obj.setCoordinates(0, newpts);
- if ((flags & Primitive.GENERATE_NORMALS) != 0)
- obj.setNormals(0, newnormals);
- if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
- obj.setTextureCoordinates(0, 0, newtcoords);
-
- geometry = obj;
- return obj;
- }
-
- private GeometryArray processTriangles()
- {
- GeometryArray obj = null;
- int i;
- int totalVerts = 0;
-
- for (i = 0; i < currPrimCnt; i++){
- totalVerts += currPrimEndVertex[i] - currPrimStartVertex[i];
- }
-
- if (debug >= 1) System.out.println("totalVerts " + totalVerts);
-
- if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
- ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
- obj = new TriangleArray(totalVerts,
- TriangleArray.COORDINATES |
- TriangleArray.NORMALS |
- TriangleArray.TEXTURE_COORDINATE_2,
- 1, texCoordSetMap);
- }
- else
- if (((flags & Primitive.GENERATE_NORMALS) == 0) &&
- ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
- obj = new TriangleArray(totalVerts,
- TriangleArray.COORDINATES |
- TriangleArray.TEXTURE_COORDINATE_2,
- 1, texCoordSetMap);
- }
- else
- if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
- ((flags & Primitive.GENERATE_TEXTURE_COORDS) == 0)){
- obj = new TriangleArray(totalVerts,
- TriangleArray.COORDINATES |
- TriangleArray.NORMALS);
- }
- else {
- obj = new TriangleArray(totalVerts,
- TriangleArray.COORDINATES);
- }
-
- Point3f[] newpts = new Point3f[totalVerts];
- Vector3f[] newnormals = new Vector3f[totalVerts];
- TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
- int currVert = 0;
-
- for (i = 0; i < currPrimCnt; i++){
- for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i] - 2;j+=3){
- outVertex(newpts, newnormals, newtcoords, currVert++,
- pts, normals, tcoords, j);
- outVertex(newpts, newnormals, newtcoords, currVert++,
- pts, normals, tcoords, j + 1);
- outVertex(newpts, newnormals, newtcoords, currVert++,
- pts, normals, tcoords, j + 2);
- numTris += 1;
- }
- }
- numVerts = currVert;
-
- obj.setCoordinates(0, newpts);
- if ((flags & Primitive.GENERATE_NORMALS) != 0)
- obj.setNormals(0, newnormals);
- if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
- obj.setTextureCoordinates(0, 0, newtcoords);
-
- geometry = obj;
- return obj;
- }
-
-
- private GeometryArray processTriangleFan() {
- if (debug > 0) System.out.println("processTriangleFan");
-
- GeometryArray obj = null;
- int i;
- int totalVerts = 0;
-
- int stripCounts[] = new int[currPrimCnt];
-
- // figure out how many vertices we need to hold the individual fans
- for (i = 0; i < currPrimCnt; i++) {
- stripCounts[i] = currPrimEndVertex[i] - currPrimStartVertex[i];
- totalVerts += stripCounts[i];
- }
-
- // figure out what flags we need
- int tfFlags = TriangleFanArray.COORDINATES;
- if ((flags & Primitive.GENERATE_NORMALS) != 0) {
- tfFlags |= TriangleFanArray.NORMALS;
- }
- if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) {
- tfFlags |= TriangleFanArray.TEXTURE_COORDINATE_2;
- }
-
- // create the TriangleFanArray
- obj = new TriangleFanArray(totalVerts, tfFlags, 1, texCoordSetMap,
- stripCounts);
-
- // allocate space for vertex info
- Point3f[] newpts = new Point3f[totalVerts];
- Vector3f[] newnormals = new Vector3f[totalVerts];
- TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
-
- int currVert = 0;
-
- // repeat for each fan
- for (i = 0; i < currPrimCnt; i++) {
- for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i]; j++) {
- outVertex(newpts, newnormals, newtcoords, currVert++, pts,
- normals, tcoords, j);
- }
- }
-
- for (i = 0; i < newpts.length; i++) {
- if (debug > 1) System.out.println("i = " + i + " " + newpts[i]);
- }
-
- numVerts = currVert;
- numTris = totalVerts - currPrimCnt * 2;
-
- // set the coordinates on the GeometryArray
- obj.setCoordinates(0, newpts);
-
- // set the normals and tex coords if necessary
- if ((flags & Primitive.GENERATE_NORMALS) != 0) {
- obj.setNormals(0, newnormals);
- }
- if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) {
- obj.setTextureCoordinates(0, 0, newtcoords);
- }
- geometry = obj;
- return obj;
- }
-
-
-
- void outVertex(Point3f[] dpts, Vector3f[] dnormals, TexCoord2f[] dtcoords,
- int dloc,
- Point3f[] spts, Vector3f[] snormals, TexCoord2f[] stcoords,
- int sloc)
- {
- if (debug >= 1) System.out.println("v " + spts[sloc].x + " " +
- spts[sloc].y + " " +
- spts[sloc].z);
-
- // PSP: Do we really need new points here?
-
- dpts[dloc] = new Point3f(spts[sloc]);
-
- if ((flags & Primitive.GENERATE_NORMALS) != 0){
- dnormals[dloc] = new Vector3f(snormals[sloc]);
- }
- if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0){
- if (debug >= 2) System.out.println("final out tcoord");
- dtcoords[dloc] = new TexCoord2f(stcoords[sloc]);
- }
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfo.java b/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfo.java
deleted file mode 100644
index d012176..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfo.java
+++ /dev/null
@@ -1,2838 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-import java.util.HashMap;
-
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.IndexedGeometryArray;
-import javax.media.j3d.IndexedQuadArray;
-import javax.media.j3d.IndexedTriangleArray;
-import javax.media.j3d.IndexedTriangleFanArray;
-import javax.media.j3d.IndexedTriangleStripArray;
-import javax.media.j3d.J3DBuffer;
-import javax.media.j3d.QuadArray;
-import javax.media.j3d.TriangleArray;
-import javax.media.j3d.TriangleFanArray;
-import javax.media.j3d.TriangleStripArray;
-import javax.vecmath.Color3b;
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4b;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point2f;
-import javax.vecmath.Point3d;
-import javax.vecmath.Point3f;
-import javax.vecmath.TexCoord2f;
-import javax.vecmath.TexCoord3f;
-import javax.vecmath.TexCoord4f;
-import javax.vecmath.Tuple2f;
-import javax.vecmath.Tuple3f;
-import javax.vecmath.Tuple4f;
-import javax.vecmath.Vector3f;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-/**
- * The GeometryInfo object holds data for processing by the Java3D geometry
- * utility tools.
- *
- * The Stripifier combines adjacent triangles into triangle strips for
- * more efficent rendering.
- * Geometry is loaded into a GeometryInfo in a manner similar to the
- *
- * GeometryArray methods. The constructor for the GeometryInfo takes a flag
- * that specifies the kind of data being loaded. The vertex data is
- * specified using methods that are similar to the GeometryArray methods, but
- * with fewer variations.
- * The major difference between GeometryInfo and GeometryArray is
- * that the number of vertices, vertex format, and other data are specified
- * implictly, rather than as part of the constructor. The number of verticies
- * comes from the number of coordinates passed to the setCoordinates()
- * method. The format comes from the set of data components that are
- * specified. For example, calling the setCoordinates(), setColors3() and
- * setTextureCoordinatesParames(1, 2) methods implies a
- * format of COORDINATES | COLOR_3
- * | TEXTURE_COORDINATE_2. Indexed representation is specified by calling
- * the methods that specify the indices, for example
- * setCoordinateIndices().
- * Stripped primitives are loaded using the TRIANGLE_FAN_ARRAY or
- * TRIANGLE_STRIP_ARRAY flags to the constructor. The setStripCounts()
- * method specifies the length of each strip.
- * A set of complex polygons is loaded using the POLYGON_ARRAY
- * flag to the constructor. The setStripCounts() method specifies the length
- * of each contour of the polygons. The setContourCounts() method specifies
- * the number of countours in each polygon. For example, a triangle with a
- * triangular hole would have strip counts [3, 3] (indicating two contours of
- * three points) and contour counts [2] (indicating a single polygon with two
- * contours).
- * GeometryInfo itelf contains some simple utilities, such as
- * calculating indices for non-indexed data ("indexifying") and getting rid
- * of unused data in your indexed geometry ("compacting").
- * The geometry utility tools modify the contents of the
- * GeometryInfo. After processing, the resulting geometry can be extracted
- * from the GeometryInfo by calling getGeometryArray(). If multiple tools
- * are used, the order of processing should be: generate normals, then
- * stripify. For example, to convert a general mesh of polygons without
- * normals into an optimized mesh call:
- *
- * If the GeometryArray uses the Note: If the texCoordSetMap is not set, multi-texturing is
- * turned off. Only the texture coordinate set at index 0 (if set) will be
- * used. Any other sets specified by the GeometryInfo.setTextureCoordinate*
- * methods will be ignored.
- */
- public void setTexCoordSetMap(int map[]) {
- texCoordSetMap = map;
- }
-
-
-
- /**
- * Returns a reference to the texture coordinate set map.
- * See the
- *
- * GeometryArray constructor for further details.
- */
- public int[] getTexCoordSetMap() {
- return texCoordSetMap;
- }
-
-
-
- /**
- * Sets the 2D texture coordinates for the specified set.
- * No data copying is done - a reference to user data is used.
- * @param texCoordSet The texture coordinate set for which these
- * coordinates are being specified.
- * @param texCoords Array of 2D texture coordinates.
- * @throws IllegalArgumentException if setRotationCenter()
method.
- *
- * @since Java 3D 1.2.1
- */
-public class OrbitBehavior extends ViewPlatformAWTBehavior {
-
- private Transform3D longditudeTransform = new Transform3D();
- private Transform3D latitudeTransform = new Transform3D();
- private Transform3D rotateTransform = new Transform3D();
-
- // needed for integrateTransforms but don't want to new every time
- private Transform3D temp1 = new Transform3D();
- private Transform3D temp2 = new Transform3D();
- private Transform3D translation = new Transform3D();
- private Vector3d transVector = new Vector3d();
- private Vector3d distanceVector = new Vector3d();
- private Vector3d centerVector = new Vector3d();
- private Vector3d invertCenterVector = new Vector3d();
-
- private double longditude = 0.0;
- private double latitude = 0.0;
- private double startDistanceFromCenter = 20.0;
- private double distanceFromCenter = 20.0;
- private Point3d rotationCenter = new Point3d();
- private Matrix3d rotMatrix = new Matrix3d();
- private Transform3D currentXfm = new Transform3D();
-
- private int mouseX = 0;
- private int mouseY = 0;
-
- private double rotXFactor = 1.0;
- private double rotYFactor = 1.0;
- private double transXFactor = 1.0;
- private double transYFactor = 1.0;
- private double zoomFactor = 1.0;
-
- private double xtrans = 0.0;
- private double ytrans = 0.0;
- private double ztrans = 0.0;
-
- private boolean zoomEnabled = true;
- private boolean rotateEnabled = true;
- private boolean translateEnabled = true;
- private boolean reverseRotate = false;
- private boolean reverseTrans = false;
- private boolean reverseZoom = false;
- private boolean stopZoom = false;
- private boolean proportionalZoom = false;
- private double minRadius = 0.0;
- private int leftButton = ROTATE;
- private int rightButton = TRANSLATE;
- private int middleButton = ZOOM;
-
- // the factor to be applied to wheel zooming so that it does not
- // look much different with mouse movement zooming.
- // This is a totally subjective factor.
- private float wheelZoomFactor = 50.0f;
-
- /**
- * Constructor flag to reverse the rotate behavior
- */
- public static final int REVERSE_ROTATE = 0x010;
-
- /**
- * Constructor flag to reverse the translate behavior
- */
- public static final int REVERSE_TRANSLATE = 0x020;
-
- /**
- * Constructor flag to reverse the zoom behavior
- */
- public static final int REVERSE_ZOOM = 0x040;
-
- /**
- * Constructor flag to reverse all the behaviors
- */
- public static final int REVERSE_ALL = (REVERSE_ROTATE | REVERSE_TRANSLATE |
- REVERSE_ZOOM);
-
- /**
- * Constructor flag that indicates zoom should stop when it reaches
- * the minimum orbit radius set by setMinRadius(). The minimus
- * radius default is 0.0.
- */
- public static final int STOP_ZOOM = 0x100;
-
- /**
- * Constructor flag to disable rotate
- */
- public static final int DISABLE_ROTATE = 0x200;
-
- /**
- * Constructor flag to disable translate
- */
- public static final int DISABLE_TRANSLATE = 0x400;
-
- /**
- * Constructor flag to disable zoom
- */
- public static final int DISABLE_ZOOM = 0x800;
-
- /**
- * Constructor flag to use proportional zoom, which determines
- * how much you zoom based on view's distance from the center of
- * rotation. The percentage of distance that the viewer zooms
- * is determined by the zoom factor.
- */
- public static final int PROPORTIONAL_ZOOM = 0x1000;
-
- /**
- * Used to set the fuction for a mouse button to Rotate
- */
- private static final int ROTATE = 0;
-
- /**
- * Used to set the function for a mouse button to Translate
- */
- private static final int TRANSLATE = 1;
-
- /**
- * Used to set the function for a mouse button to Zoom
- */
- private static final int ZOOM = 2;
-
- private static final double NOMINAL_ZOOM_FACTOR = .01;
- private static final double NOMINAL_PZOOM_FACTOR = 1.0;
- private static final double NOMINAL_ROT_FACTOR = .01;
- private static final double NOMINAL_TRANS_FACTOR = .01;
-
- private double rotXMul = NOMINAL_ROT_FACTOR * rotXFactor;
- private double rotYMul = NOMINAL_ROT_FACTOR * rotYFactor;
- private double transXMul = NOMINAL_TRANS_FACTOR * transXFactor;
- private double transYMul = NOMINAL_TRANS_FACTOR * transYFactor;
- private double zoomMul = NOMINAL_ZOOM_FACTOR * zoomFactor;
-
- /**
- * Parameterless constructor for this behavior. This is intended for use
- * by ConfiguredUniverse, which requires such a constructor for
- * configurable behaviors. The Canvas3D used to listen for mouse and
- * mouse motion events is obtained from the superclass
- * setViewingPlatform() method.
- * @since Java 3D 1.3
- */
- public OrbitBehavior() {
- super(MOUSE_LISTENER | MOUSE_MOTION_LISTENER | MOUSE_WHEEL_LISTENER);
- }
-
- /**
- * Creates a new OrbitBehavior
- *
- * @param c The Canvas3D to add the behavior to
- */
- public OrbitBehavior(Canvas3D c) {
- this(c, 0 );
- }
-
- /**
- * Creates a new OrbitBehavior
- *
- * @param c The Canvas3D to add the behavior to
- * @param flags The option flags
- */
- public OrbitBehavior(Canvas3D c, int flags) {
- super(c, MOUSE_LISTENER | MOUSE_MOTION_LISTENER | MOUSE_WHEEL_LISTENER | flags );
-
- if ((flags & DISABLE_ROTATE) != 0) rotateEnabled = false;
- if ((flags & DISABLE_ZOOM) != 0) zoomEnabled = false;
- if ((flags & DISABLE_TRANSLATE) != 0) translateEnabled = false;
- if ((flags & REVERSE_TRANSLATE) != 0) reverseTrans = true;
- if ((flags & REVERSE_ROTATE) != 0) reverseRotate = true;
- if ((flags & REVERSE_ZOOM) != 0) reverseZoom = true;
- if ((flags & STOP_ZOOM) != 0) stopZoom = true;
- if ((flags & PROPORTIONAL_ZOOM) !=0) {
- proportionalZoom = true;
- zoomMul = NOMINAL_PZOOM_FACTOR * zoomFactor;
- }
- }
-
- @Override
- protected synchronized void processAWTEvents( final AWTEvent[] events ) {
- motion = false;
- for(int i=0; imotion
variable will be true when the method
- * is called. If it is true when the method returns integrateTransforms
- * will be called immediately.
- *
- * The AWTEvents are presented in the array in the order in which they
- * arrived from AWT.
- */
- protected abstract void processAWTEvents( final java.awt.AWTEvent[] events );
-
- /**
- * Called once per frame (if the view is moving) to calculate the new
- * view platform transform
- */
- protected abstract void integrateTransforms();
-
- /**
- * Queue AWTEvents in a thread safe manner.
- *
- * If subclasses override this method they must call
- * super.queueAWTEvent(e)
- */
- protected void queueAWTEvent( AWTEvent e ) {
- // add new event to the queue
- // must be MT safe
- synchronized (eventQueue) {
- eventQueue.add(e);
- // Only need to post if this is the only event in the queue.
- // There have been reports that the first event after
- // setViewingPlatform() is sometimes missed, so check the
- // firstEvent flag as well.
- if (firstEvent || eventQueue.size() == 1) {
- firstEvent = false;
- postId( POST_ID );
- }
- }
- }
-
- @Override
- public void mouseClicked(final MouseEvent e) {
- queueAWTEvent( e );
- }
-
- @Override
- public void mouseEntered(final MouseEvent e) {
- queueAWTEvent( e );
- }
-
- @Override
- public void mouseExited(final MouseEvent e) {
- queueAWTEvent( e );
- }
-
- @Override
- public void mousePressed(final MouseEvent e) {
- queueAWTEvent( e );
- }
-
- @Override
- public void mouseReleased(final MouseEvent e) {
- queueAWTEvent( e );
- }
-
- @Override
- public void mouseDragged(final MouseEvent e) {
- queueAWTEvent( e );
- }
-
- @Override
- public void mouseMoved(final MouseEvent e) {
- queueAWTEvent( e );
- }
-
- @Override
- public void keyReleased(final java.awt.event.KeyEvent e) {
- queueAWTEvent( e );
- }
-
- @Override
- public void keyPressed(final java.awt.event.KeyEvent e) {
- queueAWTEvent( e );
- }
-
- @Override
- public void keyTyped(final java.awt.event.KeyEvent e) {
- queueAWTEvent( e );
- }
-
- @Override
- public void mouseWheelMoved( final java.awt.event.MouseWheelEvent e) {
- queueAWTEvent( e );
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/vp/ViewPlatformBehavior.java b/src/classes/share/com/sun/j3d/utils/behaviors/vp/ViewPlatformBehavior.java
deleted file mode 100644
index 5518eeb..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/vp/ViewPlatformBehavior.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.behaviors.vp;
-
-import javax.media.j3d.Behavior;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-
-import com.sun.j3d.utils.universe.ViewingPlatform;
-
-/**
- * Abstract class for ViewPlatformBehaviors. A ViewPlatformBehavior must
- * be added to the ViewingPlatform with the
- * ViewingPlatform.addViewPlatformBehavior() method. The ViewPlatformBehavior
- * will operate on the ViewPlatform transform (the TransformGroup return by
- * ViewingPlatform.getViewPlatformTransform()).
- * @since Java 3D 1.2.1
- */
-abstract public class ViewPlatformBehavior extends Behavior {
-
- /**
- * The ViewingPlatform for this behavior.
- */
- protected ViewingPlatform vp;
-
- /**
- * The target TransformGroup for this behavior.
- */
- protected TransformGroup targetTG;
-
- /**
- * The "home" transform for this behavior. This is a transform used to
- * position and orient the ViewingPlatform to a known point of interest.
- *
- * @since Java 3D 1.3
- */
- protected Transform3D homeTransform = null;
-
- /**
- * Sets the ViewingPlatform for this behavior. This method is called by
- * the ViewingPlatform. If a sub-calls overrides this method, it must
- * call super.setViewingPlatform(vp).SensorEventAgent
directly.
- * ConfiguredUniverse
and fully configured using the
- * ViewPlatformBehaviorProperties
command to set the properties
- * described below, but neither ConfiguredUniverse
nor
- * SimpleUniverse
are required by this behavior. Conventional
- * set
and get
accessors are provided for
- * configuring this behavior directly; these methods have the same names as
- * the properties but are prefixed with get
and set
.
- * Property values are spelled with mixed case strings while the corresponding
- * constant field names for the conventional accessors are spelled with upper
- * case strings and underscores.
- * setHotSpot
method of the Sensor
class.
- *
- *
- * GrabView
- Directly manipulates the view platform by moving
- * it in inverse response to the sensor's position and orientation,
- * producing the effect of attaching the virtual world to the sensor's
- * movements. If a button is available then this action is bound to button 0
- * by default.
- * TranslateForward
- Translates the view platform forward along
- * the direction the sensor is pointing; the virtual world appears to move
- * towards the sensor. The default is button 1 if two buttons are available.
- * Related properties are {@link #TranslationSpeed TranslationSpeed}, {@link
- * #AccelerationTime AccelerationTime}, {@link #ConstantSpeedTime
- * ConstantSpeedTime}, and {@link #FastSpeedFactor FastSpeedFactor}.
- * TranslateBackward
- Translates the view platform backwards
- * along the direction the sensor is pointing; the virtual world appears to
- * move away from the sensor. The default is button 2 if three buttons are
- * available.
- * RotateCCW
- Rotates the view platform counter-clockwise about
- * a Y axis; the virtual world appears to rotate clockwise. This action is
- * not assigned by default. Related properties are {@link #RotationSpeed
- * RotationSpeed}, {@link #RotationCoords RotationCoords}, {@link
- * #TransformCenterSource TransformCenterSource}, {@link #TransformCenter
- * TransformCenter}, and AccelerationTime
.
- * RotateCW
- Rotates the view platform clockwise about a Y axis;
- * the virtual world appears to rotate counter-clockwise. This action is not
- * assigned by default.
- * ScaleUp
- Scales the view platform larger so that the virtual
- * world appears to grow smaller. This action is not assigned by default.
- * Related properties are {@link #ScaleSpeed ScaleSpeed},
- * TransformCenterSource
, TransformCenter
, and
- * AccelerationTime
.
- * ScaleDown
- Scales the view platform smaller so that the
- * virtual world appears to grow larger. This action is not assigned by
- * default.
- *
- *
- * Rotation
- Rotates the view platform. This is the default 2D
- * valuator action set by this behavior. Related properties are
- * RotationSpeed
, RotationCoords
,
- * TransformCenterSource
, and TransformCenter
.
- * Translation
- Translates the view platform. The translation
- * occurs relative to the X and Z basis vectors of either the 6DOF sensor or
- * the view platform if one is not available. The maximum speed is equal to
- * the product of the TranslationSpeed
and
- * FastSpeedFactor
property values.
- * Scale
- Scales the view platform smaller with positive Y
- * values and larger with negative Y values. The effect is to increase the
- * apparent size of the virtual world when pushing the valuator forwards and
- * to decrease it when pushing backwards. Related properties are
- * ScaleSpeed
, TransformCenterSource
, and
- * TransformCenter
.
- * ReadAction2D
. No actions are bound by default to the 2D
- * valuator buttons.
- * None
can in general be assigned to any
- * button or read action to prevent any defaults from being bound to it.
- *
- * @see ConfiguredUniverse
- * @see SensorEventAgent
- * @since Java 3D 1.3
- */
-public class WandViewBehavior extends ViewPlatformBehavior {
- /**
- * Indicates a null configuration choice.
- */
- public static final int NONE = 0 ;
-
- /**
- * Indicates that a 6DOF sensor button action should be bound
- * to grabbing the view. The default is button 0.
- */
- public static final int GRAB_VIEW = 1 ;
-
- /**
- * Indicates that a 6DOF sensor button action should be bound
- * to translating the view forward. The default is button 1.
- */
- public static final int TRANSLATE_FORWARD = 2 ;
-
- /**
- * Indicates that a 6DOF sensor button action should be bound
- * to translating the view backward. The default is button 2.
- */
- public static final int TRANSLATE_BACKWARD = 3 ;
-
- /**
- * Indicates that a 6DOF sensor button action should be bound
- * to rotate the view plaform counter-clockwise about a Y axis.
- */
- public static final int ROTATE_CCW = 4 ;
-
- /**
- * Indicates that a 6DOF sensor button action should be bound
- * to rotate the view platform clockwise about a Y axis.
- */
- public static final int ROTATE_CW = 5 ;
-
- /**
- * Indicates that a 6DOF sensor button action should be bound
- * to scaling the view platform larger.
- */
- public static final int SCALE_UP = 6 ;
-
- /**
- * Indicates that a 6DOF sensor button action should be bound
- * to scaling the view platform smaller.
- */
- public static final int SCALE_DOWN = 7 ;
-
- /**
- * Indicates that a 2D sensor button or read action should be bound
- * to translation.
- */
- public static final int TRANSLATION = 8 ;
-
- /**
- * Indicates that a 2D sensor button or read action should be bound
- * to scaling.
- */
- public static final int SCALE = 9 ;
-
- /**
- * Indicates that a 2D sensor button or read action should be bound
- * to rotation. The default is to bind rotation to the 2D sensor reads.
- */
- public static final int ROTATION = 10 ;
-
- /**
- * Indicates that translation, rotation, or scaling speeds are
- * per frame.
- */
- public static final int PER_FRAME = 11 ;
-
- /**
- * Use to indicate that translation, rotation, or scaling speeds are per
- * second. This is the default.
- */
- public static final int PER_SECOND = 12 ;
-
- /**
- * Indicates that translation speed is in virtual world units.
- */
- public static final int VIRTUAL_UNITS = 13 ;
-
- /**
- * Indicates that translation speed is in physical world units
- * (meters per second or per frame). This is the default.
- */
- public static final int PHYSICAL_METERS = 14 ;
-
- /**
- * Indicates that rotation speed should be in radians.
- */
- public static final int RADIANS = 15 ;
-
- /**
- * Indicates that rotation speed should be in degrees. This is the
- * default.
- */
- public static final int DEGREES = 16 ;
-
- /**
- * Indicates that rotation should occur in view platform
- * coordinates.
- */
- public static final int VIEW_PLATFORM = 17 ;
-
- /**
- * Indicates that rotation should occur in head coordinates.
- */
- public static final int HEAD = 18 ;
-
- /**
- * Indicates that rotation should occur in sensor coordinates.
- * This is the default.
- */
- public static final int SENSOR = 19 ;
-
- /**
- * Indicates that rotation or scale should be about a fixed point
- * in virtual world coordinates.
- */
- public static final int VWORLD_FIXED = 20 ;
-
- /**
- * Indicates that rotation or scale should be about a 6DOF sensor
- * hotspot. This is the default.
- */
- public static final int HOTSPOT = 21 ;
-
- /**
- * Indicates that the 6DOF sensor read action should be bound to
- * displaying the sensor's echo in the virtual world. This is the
- * default.
- */
- public static final int ECHO = 22 ;
-
- /**
- * Indicates that the echo type is a gnomon displaying the
- * directions of the sensor's local coordinate system axes at the location
- * of the sensor's hotspot.
- */
- public static final int GNOMON = 23 ;
-
- /**
- * Indicates that the echo type is a beam extending from the
- * origin of the sensor's local coordinate system to its hotspot.
- */
- public static final int BEAM = 24 ;
-
- /**
- * Indicates that a button listener or read listener has not been
- * set for a particular target. This allows this behavior to use that
- * target for a default listener.
- */
- private static final int UNSET = -1 ;
-
- private View view = null ;
- private SensorEventAgent eventAgent = null ;
- private String sensor6DName = null ;
- private String sensor2DName = null ;
- private Shape3D echoGeometry = null ;
- private BranchGroup echoBranchGroup = null ;
- private TransformGroup echoTransformGroup = null ;
- private SensorReadListener echoReadListener6D = null ;
- private boolean echoBranchGroupAttached = false ;
- private WakeupCondition wakeupConditions = new WakeupOnElapsedFrames(0) ;
- private boolean configured = false ;
-
- // The rest of these private fields are all configurable through
- // ConfiguredUniverse.
- private Sensor sensor6D = null ;
- private Sensor sensor2D = null ;
- private int x2D = 3 ;
- private int y2D = 7 ;
- private double threshold2D = 0.0 ;
-
- private int readAction6D = UNSET ;
- private int readAction2D = UNSET ;
-
- private ArrayList buttonActions6D = new ArrayList() ;
- private ArrayList buttonActions2D = new ArrayList() ;
-
- private double translationSpeed = 0.1 ;
- private int translationUnits = PHYSICAL_METERS ;
- private int translationTimeBase = PER_SECOND ;
- private double accelerationTime = 1.0 ;
- private double constantSpeedTime = 8.0 ;
- private double fastSpeedFactor = 10.0 ;
-
- private double rotationSpeed = 180.0 ;
- private int rotationUnits = DEGREES ;
- private int rotationTimeBase = PER_SECOND ;
- private int rotationCoords = SENSOR ;
-
- private double scaleSpeed = 2.0 ;
- private int scaleTimeBase = PER_SECOND ;
-
- private int transformCenterSource = HOTSPOT ;
- private Point3d transformCenter = new Point3d(0.0, 0.0, 0.0) ;
-
- private int resetViewButtonCount6D = 3 ;
- private int resetViewButtonCount2D = NONE ;
-
- private int echoType = GNOMON ;
- private double echoSize = 0.01 ;
- private Color3f echoColor = null ;
- private float echoTransparency = 0.0f ;
- private Transform3D nominalSensorRotation = null ;
-
- /**
- * Parameterless constructor for this behavior. This is called when this
- * behavior is instantiated from a configuration file.
- *
(NewViewPlatformBehavior <name>
- * com.sun.j3d.utils.behaviors.vp.WandViewBehavior)
- */
- public WandViewBehavior() {
- // Create an event agent.
- eventAgent = new SensorEventAgent(this) ;
-
- // Set a default SchedulingBounds.
- setSchedulingBounds(new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
- Double.POSITIVE_INFINITY)) ;
- }
-
- /**
- * Creates a new instance with the specified sensors and echo parameters.
- * At least one sensor must be non-null
.
- * SimpleUniverse
or ConfiguredUniverse
is used
- * to set up the view side of the scene graph, or if it is otherwise to be
- * attached to a ViewingPlatform
. If this behavior is not
- * instantiated from a configuration file then it must then be explicitly
- * attached to a ViewingPlatform
instance with the
- * ViewingPlatform.setViewPlatformBehavior
method.
- *
- * @param sensor6D a six degree of freedom sensor which generates reads
- * relative to the tracker base in physical units; may be
- * null
- * @param sensor2D 2D valuator which generates X and Y reads ranging from
- * [-1.0 .. +1.0]; may be null
- * @param echoType either GNOMON
, BEAM
, or
- * NONE
for the 6DOF sensor echo
- * @param echoSize the width of the 6DOF sensor echo in physical meters;
- * ignored if echoType is NONE
- */
- public WandViewBehavior(Sensor sensor6D, Sensor sensor2D,
- int echoType, double echoSize) {
- this() ;
- this.sensor6D = sensor6D ;
- this.sensor2D = sensor2D ;
- this.echoType = echoType ;
- this.echoSize = echoSize ;
- }
-
- /**
- * Creates a new instance with the specified sensors and a 6DOF sensor
- * echo parented by the specified TransformGroup
. At least
- * one sensor must be non-null
.
- * SimpleUniverse
or ConfiguredUniverse
is used
- * to set up the view side of the scene graph, or if it is otherwise to be
- * attached to a ViewingPlatform
. If this behavior is not
- * instantiated from a configuration file then it must then be explicitly
- * attached to a ViewingPlatform
instance with the
- * ViewingPlatform.setViewPlatformBehavior
method.
- * TransformGroup
is non-null
, it
- * will be added to a new BranchGroup
and attached to the
- * ViewingPlatform
, where its transform will be updated in
- * response to the sensor reads. Capabilities to allow writing its
- * transform and to read, write, and extend its children will be set. The
- * echo geometry is assumed to incorporate the position and orientation of
- * the 6DOF sensor hotspot.
- *
- * @param sensor6D a six degree of freedom sensor which generates reads
- * relative to the tracker base in physical units; may be
- * null
- * @param sensor2D 2D valuator which generates X and Y reads ranging from
- * [-1.0 .. +1.0]; may be null
- * @param echo a TransformGroup
containing the visible echo
- * which will track the 6DOF sensor's position and orientation, or
- * null
for no echo
- */
- public WandViewBehavior(Sensor sensor6D, Sensor sensor2D,
- TransformGroup echo) {
- this() ;
- this.sensor6D = sensor6D ;
- this.sensor2D = sensor2D ;
- if (echo != null) {
- echo.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE) ;
- echo.setCapability(Group.ALLOW_CHILDREN_READ) ;
- echo.setCapability(Group.ALLOW_CHILDREN_WRITE) ;
- echo.setCapability(Group.ALLOW_CHILDREN_EXTEND) ;
- }
- this.echoTransformGroup = echo ;
- }
-
- /**
- * Creates a new instance with the specified sensors and a 6DOF sensor
- * echo parented by the specified TransformGroup
. At least
- * one sensor must be non-null
.
- * SimpleUniverse
or
- * ConfiguredUniverse
is not used to set up the view
- * side of the scene graph. The application must set up the view side
- * itself and supply references to the View
and the
- * TransformGroup
containing the view platform transform.
- * ViewingPlatform.setViewPlatformBehavior
must not
- * be called, and this behavior must be explicitly added to the virtual
- * universe by the application.
- * TransformGroup
is non-null
, it
- * will only be used to update its associated transform with the position
- * and orientation of a 6DOF sensor (if supplied). The application is
- * responsible for adding the echo to the virtual universe. The echo
- * geometry is assumed to incorporate the position and orientation of the
- * 6DOF sensor hotspot.
- *
- * @param sensor6D a six degree of freedom sensor which generates reads
- * relative to the tracker base in physical units; may be
- * null
- * @param sensor2D 2D valuator which generates X and Y reads ranging from
- * [-1.0 .. +1.0]; may be null
- * @param view a reference to the View
attached to the
- * ViewPlatform
to be manipulated by this behavior
- * @param viewTransform a TransformGroup
containing the view
- * platform transform; appropriate capabilities to update the transform
- * must be set
- * @param homeTransform a Transform3D
containing the
- * view transform to be used when the view is reset; may be
- * null
for identity
- * @param echo a TransformGroup
containing the visible echo
- * which will track the 6DOF sensor's position and orientation, or
- * null
for no echo; appropriate capabilities to update the
- * transform must be set
- */
- public WandViewBehavior(Sensor sensor6D, Sensor sensor2D,
- View view, TransformGroup viewTransform,
- Transform3D homeTransform, TransformGroup echo) {
- this() ;
- this.sensor6D = sensor6D ;
- this.sensor2D = sensor2D ;
- this.view = view ;
- this.targetTG = viewTransform ;
- this.echoTransformGroup = echo ;
-
- if (homeTransform == null)
- setHomeTransform(new Transform3D()) ;
- else
- setHomeTransform(homeTransform) ;
- }
-
- /**
- * Initializes and configures this behavior.
- * NOTE: Applications should not call this method. It is called by
- * the Java 3D behavior scheduler.
- */
- @Override
- public void initialize() {
- // Don't configure the sensors and echo after the first time.
- if (!configured) {
- configureSensorActions() ;
-
- // Configure an echo only if a ViewingPlatform is in use.
- if (vp != null) {
- if (echoTransformGroup == null &&
- sensor6D != null && readAction6D == ECHO) {
- configureEcho() ;
- }
- if (echoTransformGroup != null) {
- echoBranchGroup = new BranchGroup() ;
- echoBranchGroup.setCapability
- (BranchGroup.ALLOW_DETACH) ;
- echoBranchGroup.setCapability
- (BranchGroup.ALLOW_CHILDREN_READ) ;
- echoBranchGroup.setCapability
- (BranchGroup.ALLOW_CHILDREN_WRITE) ;
-
- echoBranchGroup.addChild(echoTransformGroup) ;
- echoBranchGroup.compile() ;
- }
- attachEcho() ;
- }
- configured = true ;
- }
- wakeupOn(wakeupConditions) ;
- }
-
- /**
- * Processes a stimulus meant for this behavior.
- * NOTE: Applications should not call this method. It is called by
- * the Java 3D behavior scheduler.
- */
- @Override
- public void processStimulus(Enumeration criteria) {
- // Invoke the sensor event dispatcher.
- eventAgent.dispatchEvents() ;
-
- // Wake up on the next frame.
- wakeupOn(wakeupConditions) ;
- }
-
- /**
- * Enables or disables this behavior. The default state is enabled.
- * @param enable true or false to enable or disable this behavior
- */
- @Override
- public void setEnable(boolean enable) {
- if (enable == getEnable()) {
- return ;
- }
- else if (enable) {
- attachEcho() ;
- }
- else {
- detachEcho() ;
- }
- super.setEnable(enable) ;
- }
-
- /**
- * Sets the ViewingPlatform
for this behavior. If a subclass
- * overrides this method, it must call
- * super.setViewingPlatform(vp)
. NOTE: Applications should
- * not call this method. It is called by the
- * ViewingPlatform
.
- */
- @Override
- public void setViewingPlatform(ViewingPlatform vp) {
- super.setViewingPlatform(vp) ;
- if (vp == null) {
- detachEcho() ;
- return ;
- }
-
- Viewer[] viewers = vp.getViewers() ;
- if (viewers != null) {
- // Get the View from the first Viewer attached to the
- // ViewingPlatform. Multiple Viewers are not supported.
- if (viewers.length != 0 && viewers[0] != null)
- view = viewers[0].getView() ;
-
- if (viewers.length > 1)
- throw new RuntimeException("multiple Viewers not supported") ;
- }
- if (view == null) {
- // Fallback to the first View attached to a live ViewPlatform.
- view = getView() ;
- }
- if (view == null) {
- // This behavior requires a view. Bail.
- throw new RuntimeException("a view is not available") ;
- }
-
- // Get the top-most TransformGroup in the ViewingPlatform.
- // ViewPlatformBehavior retrieves the bottom-most which won't work
- // if there are multiple TransformGroups.
- targetTG = vp.getMultiTransformGroup().getTransformGroup(0) ;
-
- // Should be an API for checking if homeTransform is null.
- if (homeTransform == null)
- setHomeTransform(new Transform3D()) ;
-
- attachEcho() ;
- }
-
- /**
- * Attaches the echo BranchGroup to the ViewingPlatform if appropriate.
- */
- private void attachEcho() {
- if (vp != null &&
- echoBranchGroup != null && !echoBranchGroupAttached) {
- vp.addChild(echoBranchGroup) ;
- echoBranchGroupAttached = true ;
- }
- }
-
- /**
- * Detaches the echo BranchGroup from the ViewingPlatform if appropriate.
- */
- private void detachEcho() {
- if (echoBranchGroup != null && echoBranchGroupAttached) {
- echoBranchGroup.detach() ;
- echoBranchGroupAttached = false ;
- }
- }
-
- /**
- * Creates the sensor listeners for a 6DOF sensor and/or a 2D valuator
- * sensor using the predefined button and read listeners and the
- * configured action bindings.
- * initialize
is called. This
- * method can be overridden by subclasses to modify the configured
- * bindings or introduce other configuration parameters.
- */
- protected void configureSensorActions() {
- SensorButtonListener[] sbls ;
- int buttonCount, buttonActionCount ;
-
- SimpleUniverse universe = null ;
- if (vp != null) universe = vp.getUniverse() ;
- if (universe != null && universe instanceof ConfiguredUniverse) {
- // Check if sensors were instantiated from a config file.
- Map sensorMap = ((ConfiguredUniverse)universe).getNamedSensors() ;
-
- if (sensor2D == null && sensor2DName != null) {
- sensor2D = (Sensor)sensorMap.get(sensor2DName) ;
- if (sensor2D == null)
- throw new IllegalArgumentException
- ("\nsensor " + sensor2DName + " not found") ;
- }
-
- if (sensor6D == null && sensor6DName != null) {
- sensor6D = (Sensor)sensorMap.get(sensor6DName) ;
- if (sensor6D == null)
- throw new IllegalArgumentException
- ("\nsensor " + sensor6DName + " not found") ;
- }
- }
-
- if (sensor6D != null) {
- // Assign default read action.
- if (readAction6D == UNSET)
- readAction6D = ECHO ;
-
- // Register the read listener.
- if (readAction6D == ECHO) {
- echoReadListener6D = new EchoReadListener6D() ;
- eventAgent.addSensorReadListener
- (sensor6D, echoReadListener6D) ;
- }
-
- // Check for button range.
- buttonCount = sensor6D.getSensorButtonCount() ;
- buttonActionCount = buttonActions6D.size() ;
- if (buttonActionCount > buttonCount)
- throw new IllegalArgumentException
- ("\nbutton index " + (buttonActionCount-1) +
- " >= number of buttons (" + buttonCount +")") ;
-
- // Assign default button actions.
- if (buttonCount > 2 &&
- (buttonActionCount < 3 || buttonActions6D.get(2) == null))
- setButtonAction6D(2, TRANSLATE_BACKWARD) ;
- if (buttonCount > 1 &&
- (buttonActionCount < 2 || buttonActions6D.get(1) == null))
- setButtonAction6D(1, TRANSLATE_FORWARD) ;
- if (buttonCount > 0 &&
- (buttonActionCount < 1 || buttonActions6D.get(0) == null))
- setButtonAction6D(0, GRAB_VIEW) ;
-
- buttonActionCount = buttonActions6D.size() ;
- if (buttonActionCount > 0) {
- // Set up the button listener array.
- sbls = new SensorButtonListener[buttonCount] ;
- for (int i = 0 ; i < buttonActionCount ; i++) {
- Integer button = (Integer)buttonActions6D.get(i) ;
- if (button != null) {
- int action = button.intValue() ;
- if (action == NONE)
- sbls[i] = null ;
- else if (action == GRAB_VIEW)
- sbls[i] = new GrabViewListener6D() ;
- else if (action == TRANSLATE_FORWARD)
- sbls[i] = new TranslationListener6D(false) ;
- else if (action == TRANSLATE_BACKWARD)
- sbls[i] = new TranslationListener6D(true) ;
- else if (action == ROTATE_CCW)
- sbls[i] = new RotationListener6D(false) ;
- else if (action == ROTATE_CW)
- sbls[i] = new RotationListener6D(true) ;
- else if (action == SCALE_UP)
- sbls[i] = new ScaleListener6D(false) ;
- else if (action == SCALE_DOWN)
- sbls[i] = new ScaleListener6D(true) ;
- }
- }
- // Register the button listeners.
- eventAgent.addSensorButtonListeners(sensor6D, sbls) ;
- }
-
- // Check for reset view action.
- if (resetViewButtonCount6D != NONE) {
- SensorInputAdaptor r =
- new ResetViewListener(sensor6D, resetViewButtonCount6D) ;
- eventAgent.addSensorButtonListener(sensor6D, r) ;
- eventAgent.addSensorReadListener(sensor6D, r) ;
- }
- }
-
- if (sensor2D != null) {
- // Assign default read action
- if (readAction2D == UNSET)
- readAction2D = ROTATION ;
-
- // Register the read listener.
- if (readAction2D == ROTATION) {
- SensorReadListener r =
- new RotationListener2D(sensor2D, sensor6D) ;
- eventAgent.addSensorReadListener(sensor2D, r) ;
- }
- else if (readAction2D == TRANSLATION) {
- SensorReadListener r =
- new TranslationListener2D(sensor2D, sensor6D) ;
- eventAgent.addSensorReadListener(sensor2D, r) ;
- }
- else if (readAction2D == SCALE) {
- SensorReadListener r =
- new ScaleListener2D(sensor2D, sensor6D) ;
- eventAgent.addSensorReadListener(sensor2D, r) ;
- }
-
- // Check for button range.
- buttonCount = sensor2D.getSensorButtonCount() ;
- buttonActionCount = buttonActions2D.size() ;
- if (buttonActionCount > buttonCount)
- throw new IllegalArgumentException
- ("\nbutton index " + (buttonActionCount-1) +
- " >= number of buttons (" + buttonCount +")") ;
-
- // No default button actions are defined for the 2D sensor.
- if (buttonActionCount > 0) {
- // Set up the button listener array.
- sbls = new SensorButtonListener[buttonCount] ;
- for (int i = 0 ; i < buttonActionCount ; i++) {
- Integer button = (Integer)buttonActions2D.get(i) ;
- if (button != null) {
- int action = button.intValue() ;
- if (action == NONE)
- sbls[i] = null ;
- else if (action == ROTATION)
- sbls[i] = new RotationListener2D
- (sensor2D, sensor6D) ;
- else if (action == TRANSLATION)
- sbls[i] = new TranslationListener2D
- (sensor2D, sensor6D) ;
- else if (action == SCALE)
- sbls[i] = new ScaleListener2D
- (sensor2D, sensor6D) ;
- }
- }
- // Register the button listeners.
- eventAgent.addSensorButtonListeners(sensor2D, sbls) ;
- }
-
- // Check for reset view action.
- if (resetViewButtonCount2D != NONE) {
- SensorInputAdaptor r =
- new ResetViewListener(sensor2D, resetViewButtonCount2D) ;
- eventAgent.addSensorButtonListener(sensor2D, r) ;
- eventAgent.addSensorReadListener(sensor2D, r) ;
- }
- }
- }
-
- /**
- * Creates a 6DOF sensor echo according to configuration parameters. This
- * is done only if a 6DOF sensor has been specified, the 6DOF sensor read
- * action has been set to echo the sensor position, the echo transform
- * group has not already been set, and a ViewingPlatform is in use. This
- * is invoked the first time initialize
is called to set this
- * behavior live, but before the echo transform group is added to a
- * BranchGroup
and made live. This method can be overridden
- * to support other echo geometry.
- */
- protected void configureEcho() {
- Point3d hotspot = new Point3d() ;
- sensor6D.getHotspot(hotspot) ;
-
- if (echoType == GNOMON) {
- Transform3D gnomonTransform = new Transform3D() ;
- if (nominalSensorRotation != null) {
- gnomonTransform.set(nominalSensorRotation) ;
- gnomonTransform.invert() ;
- }
- gnomonTransform.setTranslation(new Vector3d(hotspot)) ;
- echoGeometry = new SensorGnomonEcho
- (gnomonTransform, 0.1 * echoSize, 0.5 * echoSize, true) ;
- }
- else if (echoType == BEAM) {
- echoGeometry = new SensorBeamEcho(hotspot, echoSize, true) ;
- }
-
- if (echoGeometry != null) {
- Appearance a = echoGeometry.getAppearance() ;
- if (echoColor != null) {
- Material m = a.getMaterial() ;
- m.setDiffuseColor(echoColor) ;
- }
- if (echoTransparency != 0.0f) {
- TransparencyAttributes ta = a.getTransparencyAttributes() ;
- ta.setTransparencyMode(TransparencyAttributes.BLENDED) ;
- ta.setTransparency(echoTransparency) ;
- // Use order independent additive blend for gnomon.
- if (echoGeometry instanceof SensorGnomonEcho)
- ta.setDstBlendFunction(TransparencyAttributes.BLEND_ONE) ;
- }
- echoTransformGroup = new TransformGroup() ;
- echoTransformGroup.setCapability
- (TransformGroup.ALLOW_TRANSFORM_WRITE) ;
- echoTransformGroup.setCapability(Group.ALLOW_CHILDREN_READ) ;
- echoTransformGroup.setCapability(Group.ALLOW_CHILDREN_WRITE) ;
- echoTransformGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND) ;
- echoTransformGroup.addChild(echoGeometry) ;
- }
- }
-
- /**
- * A base class for implementing some of this behavior's listeners.
- */
- public class ListenerBase extends SensorInputAdaptor {
- /**
- * The initial transform from view platform coordinates to virtual
- * world coordinates, set by initAction
.
- */
- protected Transform3D viewPlatformToVworld = new Transform3D() ;
-
- /**
- * The initial transform from tracker base coordinates to virtual
- * world coordinates, set by initAction
.
- */
- protected Transform3D trackerToVworld = new Transform3D() ;
-
- /**
- * The initial transform from sensor coordinates to virtual
- * world coordinates, set by initAction
.
- */
- protected Transform3D sensorToVworld = new Transform3D() ;
-
- /**
- * The initial transform from sensor coordinates to tracker base
- * coordinates, set by initAction
.
- */
- protected Transform3D sensorToTracker = new Transform3D() ;
-
- // Private fields.
- private Transform3D trackerToSensor = new Transform3D() ;
- private boolean active = false ;
-
- // Misc. temporary objects.
- private double[] s3Tmp = new double[3] ;
- private double[] m16Tmp = new double[16] ;
- private Vector3d v3dTmp = new Vector3d() ;
- private Transform3D t3dTmp = new Transform3D() ;
-
- /**
- * Initializes the listener action. Subclasses must call this before
- * starting the action, either from pressed
or when a 2D
- * valuator exits the deadzone threshold.
- *
- * @param s reference to a 6DOF sensor if used by the listener; may
- * be null
- */
- protected void initAction(Sensor s) {
- targetTG.getTransform(viewPlatformToVworld) ;
- active = true ;
- if (s == null) return ;
-
- // Kludge to get the static trackerToVworld for this
- // frame. This is computed from the two separate sensor reads
- // below, which are close enough to identical to work. The
- // Java 3D View class needs a getTrackerBaseToVworld() method
- // (see Java 3D RFE 4676808).
- s.getRead(sensorToTracker) ;
- view.getSensorToVworld(s, sensorToVworld) ;
-
- trackerToSensor.invert(sensorToTracker) ;
- trackerToVworld.mul(sensorToVworld, trackerToSensor) ;
- }
-
- /**
- * Ends the action. Subclasses must be call this from
- * released
or when a 2D valuator enters the deadzone
- * threshold.
- *
- * @param s reference to a 6DOF sensor if used by the listener; may
- * be null
- */
- protected void endAction(Sensor s) {
- active = false ;
- }
-
- /**
- * Returns true if the listener is currently active; that is, if
- * initAction
has been called but not yet
- * endAction
.
- *
- * @return true if the listener is active, false otherwise
- */
- protected boolean isActive() {
- return active ;
- }
-
- @Override
- public void pressed(SensorEvent e) {
- initAction(e.getSensor()) ;
- }
-
- @Override
- public void released(SensorEvent e) {
- endAction(e.getSensor()) ;
- }
-
- /**
- * Gets the physical to virtual scale.
- */
- protected double getPhysicalToVirtualScale() {
- view.getCanvas3D(0).getImagePlateToVworld(t3dTmp) ;
- t3dTmp.get(m16Tmp) ;
- return Math.sqrt(m16Tmp[0]*m16Tmp[0] +
- m16Tmp[1]*m16Tmp[1] +
- m16Tmp[2]*m16Tmp[2]) ;
- }
-
- /**
- * Gets the scale from physical units to view platform units.
- */
- protected double getPhysicalToViewPlatformScale() {
- double vpToVirtualScale ;
-
- targetTG.getTransform(t3dTmp) ;
- t3dTmp.get(m16Tmp) ;
- vpToVirtualScale = Math.sqrt(m16Tmp[0]*m16Tmp[0] +
- m16Tmp[1]*m16Tmp[1] +
- m16Tmp[2]*m16Tmp[2]) ;
-
- return getPhysicalToVirtualScale() / vpToVirtualScale ;
- }
-
- /**
- * Translates a coordinate system.
- *
- * @param transform the coordinate system to be translated
- * @param translation the vector by which to translate
- */
- protected void translateTransform(Transform3D transform,
- Vector3d translation) {
- transform.get(v3dTmp) ;
- v3dTmp.add(translation) ;
- transform.setTranslation(v3dTmp) ;
- }
-
- /**
- * Transforms the target coordinate system about a center point.
- * This can be used for rotation and scaling.
- *
- * @param target the coordinate system to transform
- * @param center the center point about which to transform
- * @param transform the transform to apply
- */
- protected void transformAboutCenter
- (Transform3D target, Point3d center, Transform3D transform) {
-
- // Translate to the center.
- target.get(v3dTmp) ;
- v3dTmp.sub(center) ;
- target.setTranslation(v3dTmp) ;
-
- // Apply the transform.
- target.mul(transform, target) ;
-
- // Translate back.
- target.get(v3dTmp) ;
- v3dTmp.add(center) ;
- target.setTranslation(v3dTmp) ;
- }
-
- /**
- * Equalizes the scale factors in the view tranform, which must be
- * congruent. If successful, the ViewingPlatform
- * TransformGroup
is updated; otherwise, its transform is reset
- * to the home transform. This should be called if multiple
- * incremental scale factors are applied to the view transform.
- *
- * @param viewPlatformToVworld the view transform
- */
- protected void conditionViewScale(Transform3D viewPlatformToVworld) {
- viewPlatformToVworld.normalize() ;
- viewPlatformToVworld.get(m16Tmp) ;
-
- s3Tmp[0] = m16Tmp[0]*m16Tmp[0] +
- m16Tmp[4]*m16Tmp[4] + m16Tmp[8]*m16Tmp[8] ;
- s3Tmp[1] = m16Tmp[1]*m16Tmp[1] +
- m16Tmp[5]*m16Tmp[5] + m16Tmp[9]*m16Tmp[9] ;
- s3Tmp[2] = m16Tmp[2]*m16Tmp[2] +
- m16Tmp[6]*m16Tmp[6] + m16Tmp[10]*m16Tmp[10] ;
-
- if (s3Tmp[0] == s3Tmp[1] && s3Tmp[0] == s3Tmp[2])
- return ;
-
- s3Tmp[0] = Math.sqrt(s3Tmp[0]) ;
- s3Tmp[1] = Math.sqrt(s3Tmp[1]) ;
- s3Tmp[2] = Math.sqrt(s3Tmp[2]) ;
-
- int closestToOne = 0 ;
- if (Math.abs(s3Tmp[1] - 1.0) < Math.abs(s3Tmp[0] - 1.0))
- closestToOne = 1 ;
- if (Math.abs(s3Tmp[2] - 1.0) < Math.abs(s3Tmp[closestToOne] - 1.0))
- closestToOne = 2 ;
-
- double scale ;
- for (int i = 0 ; i < 3 ; i++) {
- if (i == closestToOne) continue ;
- scale = s3Tmp[closestToOne] / s3Tmp[i] ;
- m16Tmp[i+0] *= scale ;
- m16Tmp[i+4] *= scale ;
- m16Tmp[i+8] *= scale ;
- }
-
- // Set the view transform and bail out if unsuccessful.
- viewPlatformToVworld.set(m16Tmp) ;
- if ((viewPlatformToVworld.getType() & Transform3D.CONGRUENT) == 0)
- goHome() ;
- else
- targetTG.setTransform(viewPlatformToVworld) ;
- }
- }
-
- /**
- * Implements a 6DOF sensor button listener to directly manipulate the
- * view platform transform. The view platform moves in inverse response
- * to the sensor's position and orientation to give the effect of
- * attaching the virtual world to the sensor's echo.
- * @see #setButtonAction6D
- */
- public class GrabViewListener6D extends ListenerBase {
- private Transform3D t3d = new Transform3D() ;
- private Transform3D initialVworldToSensor = new Transform3D() ;
-
- @Override
- public void pressed(SensorEvent e) {
- initAction(e.getSensor()) ;
-
- // Save the inverse of the initial sensorToVworld.
- initialVworldToSensor.invert(sensorToVworld) ;
- }
-
- @Override
- public void dragged(SensorEvent e) {
- // Get sensor read relative to the static view at the time of the
- // button-down.
- Sensor s = e.getSensor() ;
- s.getRead(sensorToTracker) ;
- sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
-
- // Solve for T, where T x initialSensorToVworld = sensorToVworld
- t3d.mul(sensorToVworld, initialVworldToSensor) ;
-
- // Move T to the view side by inverting it, and then applying it
- // to the static view transform.
- t3d.invert() ;
- t3d.mul(viewPlatformToVworld) ;
- targetTG.setTransform(t3d) ;
- }
- }
-
- /**
- * Implements a 6DOF sensor button listener that translates the view
- * platform along the direction the sensor is pointing.
- * @see #setButtonAction6D
- * @see #setTranslationSpeed
- * @see #setAccelerationTime
- * @see #setConstantSpeedTime
- * @see #setFastSpeedFactor
- */
- public class TranslationListener6D extends ListenerBase {
- private long buttonDownTime ;
- private double speedScaled ;
- private double interval0 ;
- private double interval1 ;
- private double interval2 ;
- private Vector3d v3d = new Vector3d() ;
-
- /**
- * Construct a new translation button listener for a 6DOF sensor.
- *
- * @param reverse if true, translate the view platform backwards;
- * otherwise, translate the view platform forwards
- */
- public TranslationListener6D(boolean reverse) {
- // Compute translation speed intervals.
- interval0 = accelerationTime ;
- interval1 = interval0 + constantSpeedTime ;
- interval2 = interval1 + accelerationTime ;
-
- // Apply virtual to physical scale if needed.
- if (translationUnits == VIRTUAL_UNITS)
- speedScaled = translationSpeed / getPhysicalToVirtualScale() ;
- else
- speedScaled = translationSpeed ;
-
- if (reverse) {
- speedScaled = -speedScaled ;
- }
- }
-
- @Override
- public void pressed(SensorEvent e) {
- initAction(e.getSensor()) ;
- buttonDownTime = e.getTime() ;
- }
-
- @Override
- public void dragged(SensorEvent e) {
- long time = e.getTime() ;
- long lastTime = e.getLastTime() ;
- double currSpeed, transTime ;
- double frameTime = 1.0 ;
- if (translationTimeBase == PER_SECOND)
- frameTime = (time - lastTime) / 1e9 ;
-
- // Compute speed based on acceleration intervals.
- transTime = (time - buttonDownTime) / 1e9 ;
- if (transTime <= interval0) {
- currSpeed = (transTime / accelerationTime) * speedScaled ;
- }
- else if (transTime > interval1 && transTime < interval2) {
- currSpeed = ((((transTime-interval1) / accelerationTime) *
- (fastSpeedFactor-1.0)) + 1.0) * speedScaled ;
- }
- else if (transTime >= interval2) {
- currSpeed = fastSpeedFactor * speedScaled ;
- }
- else {
- currSpeed = speedScaled ;
- }
-
- // Transform the translation direction (0, 0, -1).
- v3d.set(0.0, 0.0, -1.0) ;
- if (nominalSensorRotation != null)
- nominalSensorRotation.transform(v3d) ;
-
- // To avoid echo frame lag, compute sensorToVworld based on
- // computed trackerToVworld. getSensorToVworld() isn't
- // current for this frame.
- Sensor s = e.getSensor() ;
- s.getRead(sensorToTracker) ;
- sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
- sensorToVworld.transform(v3d) ;
-
- // Translate the view platform.
- v3d.scale(frameTime * currSpeed) ;
- translateTransform(viewPlatformToVworld, v3d) ;
- targetTG.setTransform(viewPlatformToVworld) ;
-
- // Translate trackerToVworld.
- translateTransform(trackerToVworld, v3d) ;
-
- if (readAction6D == ECHO) {
- // Translate sensor echo to compensate for the new view
- // platform movement.
- translateTransform(sensorToVworld, v3d) ;
- updateEcho(s, sensorToVworld) ;
- }
- }
- }
-
- /**
- * Implements a 6DOF sensor button listener that rotates the view platform
- * about a Y axis. This axis can be relative to the sensor, user head, or
- * view platform. The rotation center can be the sensor hotspot or a
- * fixed point in virtual world coordinates.
- *
- * @see #setButtonAction6D
- * @see #setRotationCoords
- * @see #setTransformCenterSource
- * @see #setTransformCenter
- * @see #setRotationSpeed
- * @see #setAccelerationTime
- */
- public class RotationListener6D extends ListenerBase {
- private boolean reverse ;
- private long buttonDownTime ;
- private Vector3d axis = new Vector3d() ;
- private Point3d center = new Point3d() ;
- private Transform3D t3d = new Transform3D() ;
- private AxisAngle4d aa4d = new AxisAngle4d() ;
- private Transform3D headToVworld = new Transform3D() ;
- private double speedScaled ;
-
- @Override
- protected void initAction(Sensor s) {
- super.initAction(s) ;
- if (rotationCoords == HEAD) {
- view.setUserHeadToVworldEnable(true) ;
- }
- }
-
- @Override
- protected void endAction(Sensor s) {
- super.endAction(s) ;
- viewPlatformToVworld.normalize() ;
- targetTG.setTransform(viewPlatformToVworld) ;
- if (rotationCoords == HEAD) {
- view.setUserHeadToVworldEnable(false) ;
- }
- }
-
- /**
- * Construct a new rotation button listener for a 6DOF sensor.
- *
- * @param reverse if true, rotate clockwise; otherwise, rotate
- * counter-clockwise
- */
- public RotationListener6D(boolean reverse) {
- this.reverse = reverse ;
- if (rotationUnits == DEGREES)
- speedScaled = rotationSpeed * Math.PI / 180.0 ;
- else
- speedScaled = rotationSpeed ;
- }
-
- @Override
- public void pressed(SensorEvent e) {
- initAction(e.getSensor()) ;
- buttonDownTime = e.getTime() ;
- }
-
- @Override
- public void dragged(SensorEvent e) {
- long time = e.getTime() ;
- long lastTime = e.getLastTime() ;
- double currSpeed, transTime ;
- double frameTime = 1.0 ;
- if (rotationTimeBase == PER_SECOND)
- frameTime = (time - lastTime) / 1e9 ;
-
- // Compute speed based on acceleration interval.
- transTime = (time - buttonDownTime) / 1e9 ;
- if (transTime <= accelerationTime) {
- currSpeed = (transTime / accelerationTime) * speedScaled ;
- }
- else {
- currSpeed = speedScaled ;
- }
-
- // Set the rotation axis.
- if (reverse)
- axis.set(0.0, -1.0, 0.0) ;
- else
- axis.set(0.0, 1.0, 0.0) ;
-
- // To avoid echo frame lag, compute sensorToVworld based on
- // computed trackerToVworld. getSensorToVworld() isn't current
- // for this frame.
- Sensor s = e.getSensor() ;
- s.getRead(sensorToTracker) ;
- sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
-
- // Transform rotation axis into target coordinate system.
- if (rotationCoords == SENSOR) {
- if (nominalSensorRotation != null)
- nominalSensorRotation.transform(axis) ;
-
- sensorToVworld.transform(axis) ;
- }
- else if (rotationCoords == HEAD) {
- view.getUserHeadToVworld(headToVworld) ;
- headToVworld.transform(axis) ;
- }
- else {
- viewPlatformToVworld.transform(axis) ;
- }
-
- // Get the rotation center.
- if (transformCenterSource == HOTSPOT) {
- s.getHotspot(center) ;
- sensorToVworld.transform(center) ;
- }
- else {
- center.set(transformCenter) ;
- }
-
- // Construct origin-based rotation about axis.
- aa4d.set(axis, currSpeed * frameTime) ;
- t3d.set(aa4d) ;
-
- // Apply the rotation to the view platform.
- transformAboutCenter(viewPlatformToVworld, center, t3d) ;
- targetTG.setTransform(viewPlatformToVworld) ;
-
- // Apply the rotation to trackerToVworld.
- transformAboutCenter(trackerToVworld, center, t3d) ;
-
- if (readAction6D == ECHO) {
- // Transform sensor echo to compensate for the new view
- // platform movement.
- transformAboutCenter(sensorToVworld, center, t3d) ;
- updateEcho(s, sensorToVworld) ;
- }
- }
- }
-
- /**
- * Implements a 6DOF sensor button listener that scales the view platform.
- * The center of scaling can be the sensor hotspot or a fixed location in
- * virtual world coordinates.
- *
- * @see #setButtonAction6D
- * @see #setTransformCenterSource
- * @see #setTransformCenter
- * @see #setScaleSpeed
- * @see #setAccelerationTime
- */
- public class ScaleListener6D extends ListenerBase {
- private double direction ;
- private long buttonDownTime ;
- private Point3d center = new Point3d() ;
- private Transform3D t3d = new Transform3D() ;
-
- @Override
- protected void endAction(Sensor s) {
- super.endAction(s) ;
- conditionViewScale(viewPlatformToVworld) ;
- }
-
- /**
- * Construct a new scale button listener for a 6DOF sensor.
- *
- * @param reverse if true, scale the view platform smaller; otherwise,
- * scale the view platform larger
- */
- public ScaleListener6D(boolean reverse) {
- if (reverse)
- direction = -1.0 ;
- else
- direction = 1.0 ;
- }
-
- @Override
- public void pressed(SensorEvent e) {
- initAction(e.getSensor()) ;
- buttonDownTime = e.getTime() ;
- }
-
- @Override
- public void dragged(SensorEvent e) {
- long time = e.getTime() ;
- long lastTime = e.getLastTime() ;
- double scale, exp, transTime ;
- double frameTime = 1.0 ;
- if (scaleTimeBase == PER_SECOND)
- frameTime = (time - lastTime) / 1e9 ;
-
- // Compute speed based on acceleration interval.
- transTime = (time - buttonDownTime) / 1e9 ;
- if (transTime <= accelerationTime) {
- exp = (transTime / accelerationTime) * frameTime * direction ;
- }
- else {
- exp = frameTime * direction ;
- }
- scale = Math.pow(scaleSpeed, exp) ;
-
- // To avoid echo frame lag, compute sensorToVworld based on
- // computed trackerToVworld. getSensorToVworld() isn't current
- // for this frame.
- Sensor s = e.getSensor() ;
- s.getRead(sensorToTracker) ;
- sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
-
- // Get the scale center.
- if (transformCenterSource == HOTSPOT) {
- s.getHotspot(center) ;
- sensorToVworld.transform(center) ;
- }
- else {
- center.set(transformCenter) ;
- }
-
- // Apply the scale to the view platform.
- t3d.set(scale) ;
- transformAboutCenter(viewPlatformToVworld, center, t3d) ;
-
- // Incremental scaling at the extremes can lead to numerical
- // instability, so catch BadTransformException to prevent the
- // behavior thread from being killed. Using a cumulative scale
- // matrix avoids this problem to a better extent, but causes the
- // 6DOF sensor hotspot center to jitter excessively.
- try {
- targetTG.setTransform(viewPlatformToVworld) ;
- }
- catch (BadTransformException bt) {
- conditionViewScale(viewPlatformToVworld) ;
- }
-
- // Apply the scale to trackerToVworld.
- transformAboutCenter(trackerToVworld, center, t3d) ;
-
- if (readAction6D == ECHO) {
- // Scale sensor echo to compensate for the new view
- // platform scale.
- transformAboutCenter(sensorToVworld, center, t3d) ;
- updateEcho(s, sensorToVworld) ;
- }
- }
- }
-
- /**
- * Implements a 6DOF sensor read listener that updates the orientation and
- * position of the sensor's echo in the virtual world.
- *
- * @see #setEchoType
- * @see #setEchoSize
- * @see #setReadAction6D
- * @see SensorGnomonEcho
- * @see SensorBeamEcho
- */
- public class EchoReadListener6D implements SensorReadListener {
- private Transform3D sensorToVworld = new Transform3D() ;
-
- @Override
- public void read(SensorEvent e) {
- Sensor s = e.getSensor() ;
- view.getSensorToVworld(s, sensorToVworld) ;
- updateEcho(s, sensorToVworld) ;
- }
- }
-
- /**
- * Implements a 2D valuator listener that rotates the view platform. The
- * X and Y values from the valuator should have a continuous range from
- * -1.0 to +1.0, although the rotation speed can be scaled to compensate
- * for a different range. The X and Y values are found in the sensor's
- * read matrix at the indices specified by
- * setMatrixIndices2D
, with defaults of 3 and 7 respectively.
- * setRotationCoords
has been called with the value
- * SENSOR
, then the rotation is applied in the 6DOF sensor's
- * coordinate system; otherwise the rotation is applied either in head
- * coordinates or in view platform coordinates. If a 6DOF sensor is
- * provided and setTransformCenterSource
has been called with
- * the value HOTSPOT
, then rotation is about the 6DOF
- * sensor's hotspot; otherwise, the rotation center is the value set by
- * setTransformCenter
.
- *
- * @see #setReadAction2D
- * @see #setButtonAction2D
- * @see #setRotationCoords
- * @see #setTransformCenterSource
- * @see #setTransformCenter
- * @see #setRotationSpeed
- * @see #setThreshold2D
- * @see #setMatrixIndices2D
- */
- public class RotationListener2D extends ListenerBase {
- private Sensor sensor2D, sensor6D ;
- private double[] m = new double[16] ;
- private Vector3d axis = new Vector3d() ;
- private Point3d center = new Point3d() ;
- private Transform3D t3d = new Transform3D() ;
- private AxisAngle4d aa4d = new AxisAngle4d() ;
- private Transform3D sensor2DRead = new Transform3D() ;
- private Transform3D headToVworld = new Transform3D() ;
- private double speedScaled ;
-
- @Override
- protected void initAction(Sensor s) {
- super.initAction(s) ;
- if (rotationCoords == HEAD) {
- view.setUserHeadToVworldEnable(true) ;
- }
- if (s != null && readAction6D == ECHO) {
- // Disable the 6DOF echo. It will be updated in this action.
- eventAgent.removeSensorReadListener(s, echoReadListener6D) ;
- }
- }
-
- @Override
- protected void endAction(Sensor s) {
- super.endAction(s) ;
- viewPlatformToVworld.normalize() ;
- targetTG.setTransform(viewPlatformToVworld) ;
- if (rotationCoords == HEAD) {
- view.setUserHeadToVworldEnable(false) ;
- }
- if (s != null && readAction6D == ECHO) {
- eventAgent.addSensorReadListener(s, echoReadListener6D) ;
- }
- }
-
- /**
- * Construct an instance of this class with the specified sensors.
- *
- * @param sensor2D the 2D valuator whose X and Y values drive the
- * rotation
- * @param sensor6D the 6DOF sensor to use if the rotation coordinate
- * system is set to SENSOR
or the rotation center source
- * is HOTSPOT
; may be null
- */
- public RotationListener2D(Sensor sensor2D, Sensor sensor6D) {
- this.sensor2D = sensor2D ;
- this.sensor6D = sensor6D ;
-
- if (rotationUnits == DEGREES)
- speedScaled = rotationSpeed * Math.PI / 180.0 ;
- else
- speedScaled = rotationSpeed ;
- }
-
- @Override
- public void read(SensorEvent e) {
- sensor2D.getRead(sensor2DRead) ;
- sensor2DRead.get(m) ;
-
- if (m[x2D] > threshold2D || m[x2D] < -threshold2D ||
- m[y2D] > threshold2D || m[y2D] < -threshold2D) {
- // Initialize action on threshold crossing.
- if (!isActive()) initAction(sensor6D) ;
-
- // m[x2D] is the X valuator value and m[y2D] is the Y valuator
- // value. Use these to construct the rotation axis.
- double length = Math.sqrt(m[x2D]*m[x2D] + m[y2D]*m[y2D]) ;
- double iLength = 1.0/length ;
- axis.set(m[y2D]*iLength, -m[x2D]*iLength, 0.0) ;
-
- if (sensor6D != null) {
- // To avoid echo frame lag, compute sensorToVworld based
- // on computed trackerToVworld. getSensorToVworld() isn't
- // current for this frame.
- sensor6D.getRead(sensorToTracker) ;
- sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
- }
-
- // Transform rotation axis into target coordinate system.
- if (sensor6D != null && rotationCoords == SENSOR) {
- if (nominalSensorRotation != null)
- nominalSensorRotation.transform(axis) ;
-
- sensorToVworld.transform(axis) ;
- }
- else if (rotationCoords == HEAD) {
- view.getUserHeadToVworld(headToVworld) ;
- headToVworld.transform(axis) ;
- }
- else {
- viewPlatformToVworld.transform(axis) ;
- }
-
- // Get the rotation center.
- if (transformCenterSource == HOTSPOT && sensor6D != null) {
- sensor6D.getHotspot(center) ;
- sensorToVworld.transform(center) ;
- }
- else {
- center.set(transformCenter) ;
- }
-
- double frameTime = 1.0 ;
- if (rotationTimeBase == PER_SECOND)
- frameTime = (e.getTime() - e.getLastTime()) / 1e9 ;
-
- // Construct origin-based rotation about axis.
- aa4d.set(axis, speedScaled * frameTime * length) ;
- t3d.set(aa4d) ;
-
- // Apply the rotation to the view platform.
- transformAboutCenter(viewPlatformToVworld, center, t3d) ;
- targetTG.setTransform(viewPlatformToVworld) ;
-
- if (sensor6D != null) {
- // Apply the rotation to trackerToVworld.
- transformAboutCenter(trackerToVworld, center, t3d) ;
- }
-
- if (sensor6D != null && readAction6D == ECHO) {
- // Transform sensor echo to compensate for the new view
- // platform movement.
- transformAboutCenter(sensorToVworld, center, t3d) ;
- updateEcho(sensor6D, sensorToVworld) ;
- }
- }
- else {
- // Initialize action on next threshold crossing.
- if (isActive()) endAction(sensor6D) ;
- }
- }
-
- @Override
- public void pressed(SensorEvent e) {
- initAction(sensor6D) ;
- }
-
- @Override
- public void released(SensorEvent e) {
- if (isActive()) endAction(sensor6D) ;
- }
-
- @Override
- public void dragged(SensorEvent e) {
- read(e) ;
- }
- }
-
- /**
- * Implements a 2D valuator listener that translates the view platform.
- * The X and Y values from the valuator should have a continuous range
- * from -1.0 to +1.0, although the translation speed can be scaled to
- * compensate for a different range. The X and Y values are found in the
- * sensor's read matrix at the indices specified by
- * setMatrixIndices2D
, with defaults of 3 and 7 respectively.
- * null
- */
- public TranslationListener2D(Sensor sensor2D, Sensor sensor6D) {
- this.sensor2D = sensor2D ;
- this.sensor6D = sensor6D ;
-
- // Apply virtual to physical scale if needed.
- if (translationUnits == VIRTUAL_UNITS)
- speedScaled = translationSpeed *
- fastSpeedFactor / getPhysicalToVirtualScale() ;
- else
- speedScaled = translationSpeed * fastSpeedFactor ;
-
- // Apply physical to view platform scale if needed.
- if (sensor6D == null)
- speedScaled *= getPhysicalToViewPlatformScale() ;
- }
-
- @Override
- public void read(SensorEvent e) {
- sensor2D.getRead(sensor2DRead) ;
- sensor2DRead.get(m) ;
-
- if (m[x2D] > threshold2D || m[x2D] < -threshold2D ||
- m[y2D] > threshold2D || m[y2D] < -threshold2D) {
- // Initialize action on threshold crossing.
- if (!isActive()) initAction(sensor6D) ;
-
- // m[x2D] is the X valuator value and m[y2D] is the Y valuator
- // value. Use these to construct the translation vector.
- double length = Math.sqrt(m[x2D]*m[x2D] + m[y2D]*m[y2D]) ;
- double iLength = 1.0/length ;
- v3d.set(m[x2D]*iLength, 0.0, -m[y2D]*iLength) ;
-
- // Transform translation vector into target coordinate system.
- if (sensor6D != null) {
- if (nominalSensorRotation != null)
- nominalSensorRotation.transform(v3d) ;
-
- // To avoid echo frame lag, compute sensorToVworld based
- // on computed trackerToVworld. getSensorToVworld() isn't
- // current for this frame.
- sensor6D.getRead(sensorToTracker) ;
- sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
- sensorToVworld.transform(v3d) ;
- }
- else {
- viewPlatformToVworld.transform(v3d) ;
- }
-
- double frameTime = 1.0 ;
- if (translationTimeBase == PER_SECOND)
- frameTime = (e.getTime() - e.getLastTime()) / 1e9 ;
-
- v3d.scale(frameTime * speedScaled * length) ;
-
- // Translate the view platform.
- translateTransform(viewPlatformToVworld, v3d) ;
- targetTG.setTransform(viewPlatformToVworld) ;
-
- if (sensor6D != null) {
- // Apply the translation to trackerToVworld.
- translateTransform(trackerToVworld, v3d) ;
- }
-
- if (sensor6D != null && readAction6D == ECHO) {
- // Translate sensor echo to compensate for the new view
- // platform movement.
- translateTransform(sensorToVworld, v3d) ;
- updateEcho(sensor6D, sensorToVworld) ;
- }
- }
- else {
- // Initialize action on next threshold crossing.
- if (isActive()) endAction(sensor6D) ;
- }
- }
-
- @Override
- public void pressed(SensorEvent e) {
- initAction(sensor6D) ;
- }
-
- @Override
- public void released(SensorEvent e) {
- if (isActive()) endAction(sensor6D) ;
- }
-
- @Override
- public void dragged(SensorEvent e) {
- read(e) ;
- }
- }
-
- /**
- * Implements a 2D valuator listener that scales the view platform.
- * Pushing the valuator forwards gives the appearance of the virtual world
- * increasing in size, while pushing the valuator backwards makes the
- * virtual world appear to shrink. The X and Y values from the valuator
- * should have a continuous range from -1.0 to +1.0, although the scale
- * speed can be adjusted to compensate for a different range.
- * setTransformCenterSource
has been
- * called with the value HOTSPOT
, then scaling is about the
- * 6DOF sensor's hotspot; otherwise, the scaling center is the value set
- * by setTransformCenter
.
- *
- * @see #setReadAction2D
- * @see #setButtonAction2D
- * @see #setScaleSpeed
- * @see #setTransformCenter
- * @see #setThreshold2D
- * @see #setMatrixIndices2D
- */
- public class ScaleListener2D extends ListenerBase {
- private Sensor sensor2D, sensor6D ;
- private double[] m = new double[16] ;
- private Point3d center = new Point3d() ;
- private Transform3D t3d = new Transform3D() ;
- private Transform3D sensor2DRead = new Transform3D() ;
-
- @Override
- protected void initAction(Sensor s) {
- super.initAction(s) ;
- if (s != null && readAction6D == ECHO) {
- // Disable the 6DOF echo. It will be updated in this action.
- eventAgent.removeSensorReadListener(s, echoReadListener6D) ;
- }
- }
-
- @Override
- protected void endAction(Sensor s) {
- super.endAction(s) ;
- conditionViewScale(viewPlatformToVworld) ;
- if (s != null && readAction6D == ECHO) {
- // Enable the 6DOF sensor echo.
- eventAgent.addSensorReadListener(s, echoReadListener6D) ;
- }
- }
-
- /**
- * Construct an instance of this class with the specified sensors.
- *
- * @param sensor2D the 2D valuator whose Y value drive the scaling
- * @param sensor6D the 6DOF sensor to use if the rotation/scale center
- * source is HOTSPOT
; may be null
- */
- public ScaleListener2D(Sensor sensor2D, Sensor sensor6D) {
- this.sensor2D = sensor2D ;
- this.sensor6D = sensor6D ;
- }
-
- @Override
- public void read(SensorEvent e) {
- sensor2D.getRead(sensor2DRead) ;
- sensor2DRead.get(m) ;
-
- if (m[y2D] > threshold2D || m[y2D] < -threshold2D) {
- // Initialize action on threshold crossing.
- if (!isActive()) initAction(sensor6D) ;
-
- if (sensor6D != null) {
- // To avoid echo frame lag, compute sensorToVworld based
- // on computed trackerToVworld. getSensorToVworld() isn't
- // current for this frame.
- sensor6D.getRead(sensorToTracker) ;
- sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
- }
-
- // Get the scale center.
- if (sensor6D != null && transformCenterSource == HOTSPOT) {
- sensor6D.getHotspot(center) ;
- sensorToVworld.transform(center) ;
- }
- else {
- center.set(transformCenter) ;
- }
-
- // Compute incremental scale for this frame.
- double frameTime = 1.0 ;
- if (scaleTimeBase == PER_SECOND)
- frameTime = (e.getTime() - e.getLastTime()) / 1e9 ;
-
- // Map range: [-1.0 .. 0 .. 1.0] to:
- // [scaleSpeed**frameTime .. 1 .. 1.0/(scaleSpeed**frameTime)]
- double scale = Math.pow(scaleSpeed, (-m[y2D]*frameTime)) ;
-
- // Apply the scale to the view platform.
- t3d.set(scale) ;
- transformAboutCenter(viewPlatformToVworld, center, t3d) ;
-
- // Incremental scaling at the extremes can lead to numerical
- // instability, so catch BadTransformException to prevent the
- // behavior thread from being killed. Using a cumulative
- // scale matrix avoids this problem to a better extent, but
- // causes the 6DOF sensor hotspot center to jitter
- // excessively.
- try {
- targetTG.setTransform(viewPlatformToVworld) ;
- }
- catch (BadTransformException bt) {
- conditionViewScale(viewPlatformToVworld) ;
- }
-
- if (sensor6D != null) {
- // Apply the scale to trackerToVworld.
- transformAboutCenter(trackerToVworld, center, t3d) ;
- }
-
- if (sensor6D != null && readAction6D == ECHO) {
- // Scale sensor echo to compensate for the new view
- // platform scale.
- transformAboutCenter(sensorToVworld, center, t3d) ;
- updateEcho(sensor6D, sensorToVworld) ;
- }
- }
- else {
- // Initialize action on next threshold crossing.
- if (isActive()) endAction(sensor6D) ;
- }
- }
-
- @Override
- public void pressed(SensorEvent e) {
- initAction(sensor6D) ;
- }
-
- @Override
- public void released(SensorEvent e) {
- if (isActive()) endAction(sensor6D) ;
- }
-
- @Override
- public void dragged(SensorEvent e) {
- read(e) ;
- }
- }
-
- /**
- * Resets the view back to the home transform when a specified number of
- * buttons are down simultaneously.
- *
- * @see #setResetViewButtonCount6D
- * @see ViewPlatformBehavior#setHomeTransform
- * ViewPlatformBehavior.setHomeTransform
- */
- public class ResetViewListener extends SensorInputAdaptor {
- private int resetCount ;
- private int[] buttonState = null ;
- private boolean goHomeNextRead = false ;
-
- /**
- * Creates a sensor listener that resets the view when the specified
- * number of buttons are down simultaneously.
- *
- * @param s the sensor to listen to
- * @param count the number of buttons that must be down simultaneously
- */
- public ResetViewListener(Sensor s, int count) {
- resetCount = count ;
- buttonState = new int[s.getSensorButtonCount()] ;
- }
-
- @Override
- public void pressed(SensorEvent e) {
- int count = 0 ;
- e.getButtonState(buttonState) ;
- for (int i = 0 ; i < buttonState.length ; i++)
- if (buttonState[i] == 1) count++ ;
-
- if (count >= resetCount)
- // Ineffectual to reset immediately while other listeners may
- // be setting the view transform.
- goHomeNextRead = true ;
- }
-
- @Override
- public void read(SensorEvent e) {
- if (goHomeNextRead) {
- goHome() ;
- goHomeNextRead = false ;
- }
- }
- }
-
- /**
- * Updates the echo position and orientation. The echo is placed at the
- * sensor hotspot position if applicable. This implementation assumes the
- * hotspot position and orientation have been incorporated into the echo
- * geometry.
- *
- * @param sensor the sensor to be echoed
- * @param sensorToVworld transform from sensor coordinates to virtual
- * world coordinates
- * @see #setEchoType
- * @see #setEchoSize
- * @see #setReadAction6D
- * @see SensorGnomonEcho
- * @see SensorBeamEcho
- */
- protected void updateEcho(Sensor sensor, Transform3D sensorToVworld) {
- echoTransformGroup.setTransform(sensorToVworld) ;
- }
-
- /**
- * Property which sets a 6DOF sensor for manipulating the view platform.
- * This sensor must generate 6 degree of freedom orientation and position
- * data in physical meters relative to the sensor's tracker base.
- * ViewingPlatform
is being used and that the
- * sensor name can be looked up from a ConfiguredUniverse
- * reference retrieved from ViewingPlatform.getUniverse
. The
- * second form is preferred and accepts the Sensor reference directly.
- *
(ViewPlatformBehaviorProperty <name>
- * Sensor6D <sensorName>)
- *
(ViewPlatformBehaviorProperty
- * <name> Sensor6D (Sensor <sensorName>))
- *
- * @param sensor array of length 1 containing a String
or
- * a Sensor
- */
- public void Sensor6D(Object[] sensor) {
- if (sensor.length != 1)
- throw new IllegalArgumentException
- ("Sensor6D requires a single name or Sensor instance") ;
-
- if (sensor[0] instanceof String)
- sensor6DName = (String)sensor[0] ;
- else if (sensor[0] instanceof Sensor)
- sensor6D = (Sensor)sensor[0] ;
- else
- throw new IllegalArgumentException
- ("Sensor6D must be a name or a Sensor instance") ;
- }
-
- /**
- * Returns a reference to the 6DOF sensor used for manipulating the view
- * platform.
- *
- * @return the 6DOF sensor
- */
- public Sensor getSensor6D() {
- return sensor6D ;
- }
-
- /**
- * Property which sets a 2D sensor for manipulating the view platform.
- * This is intended to support devices which incorporate a separate 2D
- * valuator along with the 6DOF sensor. The X and Y values from the
- * valuator should have a continuous range from -1.0 to +1.0, although
- * rotation, translation, and scaling speeds can be scaled to compensate
- * for a different range. The X and Y values are found in the sensor's
- * read matrix at the indices specified by the
- * MatrixIndices2D
property, with defaults of 3 and 7
- * (the X and Y translation components) respectively.
- * ViewingPlatform
is being used and that the
- * sensor name can be looked up from a ConfiguredUniverse
- * reference retrieved from ViewingPlatform.getUniverse
. The
- * second form is preferred and accepts the Sensor reference directly.
- *
(ViewPlatformBehaviorProperty <name>
- * Sensor2D <sensorName>)
- *
(ViewPlatformBehaviorProperty
- * <name> Sensor2D (Sensor <sensorName>))
- *
- * @param sensor array of length 1 containing a String
or
- * a Sensor
- */
- public void Sensor2D(Object[] sensor) {
- if (sensor.length != 1)
- throw new IllegalArgumentException
- ("Sensor2D requires a single name or Sensor instance") ;
-
- if (sensor[0] instanceof String)
- sensor2DName = (String)sensor[0] ;
- else if (sensor[0] instanceof Sensor)
- sensor2D = (Sensor)sensor[0] ;
- else
- throw new IllegalArgumentException
- ("Sensor2D must be a name or a Sensor instance") ;
- }
-
- /**
- * Returns a reference to the 2D valuator used for manipulating the view
- * platform.
- *
- * @return the 2D valuator
- */
- public Sensor getSensor2D() {
- return sensor2D ;
- }
-
- /**
- * Property which sets a button action for the 6DOF sensor. The choices
- * are TranslateForward
, TranslateBackward
,
- * GrabView
, RotateCCW
, RotateCW
,
- * ScaleUp
, ScaleDown
, or None
. By
- * default, button 0 is bound to GrabView
, button 1 is bound
- * to TranslateForward
, and button 2 is bound to
- * TranslateBackward
. If there are fewer than three buttons
- * available, then the default button actions with the lower button
- * indices have precedence. A value of None
indicates that
- * no default action is to be associated with the specified button.
- * TranslateForward
moves the view platform forward along the
- * direction the sensor is pointing. TranslateBackward
does
- * the same, in the opposite direction. GrabView
directly
- * manipulates the view by moving it in inverse response to the sensor's
- * position and orientation. RotateCCW
and
- * RotateCW
rotate about a Y axis, while ScaleUp
- * and ScaleDown
scale the view platform larger and smaller.
- * ArrayOutOfBoundsException
- * when the behavior is initialized or attached to a
- * ViewingPlatform
.
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * ButtonAction6D <button index>
- * [GrabView | TranslateForward | TranslateBackward | RotateCCW |
- * RotateCW | ScaleUp | ScaleDown | None])
- *
- * @param action array of length 2 containing a Double
and a
- * String
.
- * @see #setButtonAction6D
- * @see #Sensor6D Sensor6D
- * @see #TranslationSpeed TranslationSpeed
- * @see #AccelerationTime AccelerationTime
- * @see #ConstantSpeedTime ConstantSpeedTime
- * @see #FastSpeedFactor FastSpeedFactor
- * @see #RotationSpeed RotationSpeed
- * @see #RotationCoords RotationCoords
- * @see #ScaleSpeed ScaleSpeed
- * @see #TransformCenterSource TransformCenterSource
- * @see #TransformCenter TransformCenter
- * @see GrabViewListener6D
- * @see TranslationListener6D
- * @see RotationListener6D
- * @see ScaleListener6D
- */
- public void ButtonAction6D(Object[] action) {
- if (! (action.length == 2 &&
- action[0] instanceof Double && action[1] instanceof String))
- throw new IllegalArgumentException
- ("\nButtonAction6D must be a number and a string") ;
-
- int button = ((Double)action[0]).intValue() ;
- String actionString = (String)action[1] ;
-
- if (actionString.equals("GrabView"))
- setButtonAction6D(button, GRAB_VIEW) ;
- else if (actionString.equals("TranslateForward"))
- setButtonAction6D(button, TRANSLATE_FORWARD) ;
- else if (actionString.equals("TranslateBackward"))
- setButtonAction6D(button, TRANSLATE_BACKWARD) ;
- else if (actionString.equals("RotateCCW"))
- setButtonAction6D(button, ROTATE_CCW) ;
- else if (actionString.equals("RotateCW"))
- setButtonAction6D(button, ROTATE_CW) ;
- else if (actionString.equals("ScaleUp"))
- setButtonAction6D(button, SCALE_UP) ;
- else if (actionString.equals("ScaleDown"))
- setButtonAction6D(button, SCALE_DOWN) ;
- else if (actionString.equals("None"))
- setButtonAction6D(button, NONE) ;
- else
- throw new IllegalArgumentException
- ("\nButtonAction6D must be GrabView, TranslateForward, " +
- "TranslateBackward, RotateCCW, RotateCW, ScaleUp, " +
- "ScaleDown, or None") ;
- }
-
- /**
- * Sets a button action for the 6DOF sensor. The choices are
- * TRANSLATE_FORWARD
, TRANSLATE_BACKWARD
,
- * GRAB_VIEW
, ROTATE_CCW
,
- * ROTATE_CW
, SCALE_UP
, SCALE_DOWN
,
- * or NONE
. By default, button 0 is bound to
- * GRAB_VIEW
, button 1 is bound to
- * TRANSLATE_FORWARD
, and button 2 is bound to
- * TRANSLATE_BACKWARD
. If there are fewer than three buttons
- * available, then the default button actions with the lower button
- * indices have precedence. A value of NONE
indicates that
- * no default action is to be associated with the specified button.
- * TRANSLATE_FORWARD
moves the view platform forward along
- * the direction the sensor is pointing. TRANSLATE_BACKWARD
- * does the same, in the opposite direction. GRAB_VIEW
- * directly manipulates the view by moving it in inverse response to the
- * sensor's position and orientation. ROTATE_CCW
and
- * ROTATE_CW
rotate about a Y axis, while
- * SCALE_UP
and SCALE_DOWN
scale the view
- * platform larger and smaller.
- * ArrayOutOfBoundsException
- * when the behavior is initialized or attached to a
- * ViewingPlatform
.
- * SensorEventAgent
used by this behavior directly.
- *
- * @param button index of the button to bind
- * @param action either TRANSLATE_FORWARD
,
- * TRANSLATE_BACKWARD
, GRAB_VIEW
,
- * ROTATE_CCW
, ROTATE_CW
,
- * ,
SCALE_UPSCALE_DOWN
, or NONE
- * @see #setTranslationSpeed
- * @see #setAccelerationTime
- * @see #setConstantSpeedTime
- * @see #setFastSpeedFactor
- * @see #setRotationSpeed
- * @see #setRotationCoords
- * @see #setScaleSpeed
- * @see #setTransformCenterSource
- * @see #setTransformCenter
- * @see #getSensorEventAgent
- * @see GrabViewListener6D
- * @see TranslationListener6D
- * @see RotationListener6D
- * @see ScaleListener6D
- */
- public synchronized void setButtonAction6D(int button, int action) {
- if (! (action == TRANSLATE_FORWARD || action == TRANSLATE_BACKWARD ||
- action == GRAB_VIEW || action == ROTATE_CCW ||
- action == ROTATE_CW || action == SCALE_UP ||
- action == SCALE_DOWN || action == NONE))
- throw new IllegalArgumentException
- ("\naction must be TRANSLATE_FORWARD, TRANSLATE_BACKWARD, " +
- "GRAB_VIEW, ROTATE_CCW, ROTATE_CW, SCALE_UP, SCALE_DOWN, " +
- "or NONE") ;
-
- while (button >= buttonActions6D.size()) {
- buttonActions6D.add(null) ;
- }
- buttonActions6D.set(button, new Integer(action)) ;
- }
-
-
- /**
- * Gets the action associated with the specified button on the 6DOF sensor.
- *
- * @return the action associated with the button
- */
- public int getButtonAction6D(int button) {
- if (button >= buttonActions6D.size())
- return NONE ;
-
- Integer i = (Integer)buttonActions6D.get(button) ;
- if (i == null)
- return NONE ;
- else
- return i.intValue() ;
- }
-
- /**
- * Property which sets the action to be bound to 2D valuator reads. This
- * action will be performed on each frame whenever no button actions have
- * been invoked and the valuator read value is greater than the threshold
- * range specified by the Threshold2D
property.
- * MatrixIndices2D
, with
- * defaults of 3 and 7 respectively.
- * Rotation
rotates the view
- * platform in the direction the valuator is pushed. The rotation
- * coordinate system is set by the RotationCoords
property,
- * with a default of Sensor
. The rotation occurs about a
- * point in the virtual world set by the
- * TransformCenterSource
and TransformCenter
- * properties, with the default set to rotate about the hotspot of a 6DOF
- * sensor, if one is available, or about the origin of the virtual world
- * if not. The rotation speed is scaled by the valuator read value up to
- * the maximum speed set with the RotationSpeed
property; the
- * default is 180 degrees per second.
- * Translation
moves the view platform in
- * the direction the valuator is pushed. The translation occurs along the
- * X and Z basis vectors of either a 6DOF sensor or the view platform if a
- * 6DOF sensor is not specified. The translation speed is scaled by the
- * valuator read value up to a maximum set by the product of the
- * TranslationSpeed
and FastSpeedFactor
property
- * values.
- * Scale
, then the view platform
- * is scaled smaller or larger when the valuator is pushed forward or
- * backward. The scaling occurs about a point in the virtual world set by
- * the TransformCenterSource
and TransformCenter
- * properties. The scaling speed is set with the ScaleSpeed
- * property, with a default scale factor of 2.0 per second at the extreme
- * negative range of -1.0, and a factor of 0.5 per second at the extreme
- * positive range of +1.0.
- * None
prevents Rotation
from being
- * bound to the 2D valuator reads.
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * ReadAction2D [Rotation | Translation | Scale | None])
- *
- * @param action array of length 1 containing a String
- * @see #setReadAction2D
- * @see #RotationCoords RotationCoords
- * @see #RotationSpeed RotationSpeed
- * @see #TransformCenterSource TransformCenterSource
- * @see #TransformCenter TransformCenter
- * @see #TranslationSpeed TranslationSpeed
- * @see #FastSpeedFactor FastSpeedFactor
- * @see #ScaleSpeed ScaleSpeed
- * @see #MatrixIndices2D MatrixIndices2D
- * @see RotationListener2D
- * @see TranslationListener2D
- * @see ScaleListener2D
- */
- public void ReadAction2D(Object[] action) {
- if (! (action.length == 1 && action[0] instanceof String))
- throw new IllegalArgumentException
- ("\nReadAction2D must be a String") ;
-
- String actionString = (String)action[0] ;
-
- if (actionString.equals("Rotation"))
- setReadAction2D(ROTATION) ;
- else if (actionString.equals("Translation"))
- setReadAction2D(TRANSLATION) ;
- else if (actionString.equals("Scale"))
- setReadAction2D(SCALE) ;
- else if (actionString.equals("None"))
- setReadAction2D(NONE) ;
- else
- throw new IllegalArgumentException
- ("\nReadAction2D must be Rotation, Translation, Scale, " +
- "or None") ;
- }
-
- /**
- * Sets the action to be bound to 2D valuator reads. This action will be
- * performed on each frame whenever no button actions have been invoked
- * and the valuator read value is greater than the threshold range
- * specified by setThreshold2D
.
- * setMatrixIndices2D
- * method, with defaults of 3 and 7 respectively.
- * ROTATION
rotates the view platform
- * in the direction the valuator is pushed. The rotation coordinate
- * system is set by setRotationCoords
, with a default of
- * SENSOR
. The rotation occurs about a point in the virtual
- * world set by setTransformCenterSource
and
- * setTransformCenter
, with the default set to rotate about
- * the hotspot of a 6DOF sensor, if one is available, or about the origin
- * of the virtual world if not. The rotation speed is scaled by the
- * valuator read value up to the maximum speed set with
- * setRotationSpeed
; the default is 180 degrees per second.
- * TRANSLATION
moves the view platform in the
- * direction the valuator is pushed. The translation occurs along the X
- * and Z basis vectors of either a 6DOF sensor or the view platform if a
- * 6DOF sensor is not specified. The translation speed is scaled by the
- * valuator read value up to a maximum set by the product of the
- * setTranslationSpeed
and setFastSpeedFactor
- * values.
- * SCALE
, then the view platform is scaled
- * smaller or larger when the valuator is pushed forward or backward. The
- * scaling occurs about a point in the virtual world set by
- * setTransformCenterSource
and
- * setTransformCenter
. The scaling speed is set with
- * setScaleSpeed
, with a default scale factor of 2.0 per
- * second at the extreme negative range of -1.0, and a factor of 0.5 per
- * second at the extreme positive range of +1.0.
- * NONE
prevents ROTATION
from being
- * bound by default to the 2D valuator reads.
- * SensorEventAgent
used by this behavior directly.
- *
- * @param action either ROTATION
, TRANSLATION
,
- * SCALE
, or NONE
- * @see #setRotationCoords
- * @see #setRotationSpeed
- * @see #setTransformCenterSource
- * @see #setTransformCenter
- * @see #setTranslationSpeed
- * @see #setFastSpeedFactor
- * @see #setScaleSpeed
- * @see #setMatrixIndices2D
- * @see #getSensorEventAgent
- * @see RotationListener2D
- * @see TranslationListener2D
- * @see ScaleListener2D
- */
- public void setReadAction2D(int action) {
- if (! (action == ROTATION || action == TRANSLATION ||
- action == SCALE || action == NONE))
- throw new IllegalArgumentException
- ("\nReadAction2D must be ROTATION, TRANSLATION, SCALE, " +
- "or NONE") ;
-
- this.readAction2D = action ;
- }
-
- /**
- * Gets the configured 2D valuator read action.
- *
- * @return the action associated with the sensor read
- */
- public int getReadAction2D() {
- if (readAction2D == UNSET)
- return NONE ;
- else
- return readAction2D ;
- }
-
- /**
- * Property which sets a button action for the 2D valuator. The possible
- * values are Rotation
, Translation
,
- * Scale
, or None
, with a default of
- * None
. These actions are the same as those for
- * ReadAction2D
.
- * ArrayOutOfBoundsException
- * when the behavior is initialized or attached to a
- * ViewingPlatform
.
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * ButtonAction2D <button index>
- * [Rotation | Translation | Scale | None])
- *
- * @param action array of length 2 containing a Double
and a
- * String
.
- * @see #setButtonAction2D
- * @see #ReadAction2D ReadAction2D
- * @see #RotationCoords RotationCoords
- * @see #RotationSpeed RotationSpeed
- * @see #TransformCenterSource TransformCenterSource
- * @see #TransformCenter TransformCenter
- * @see #TranslationSpeed TranslationSpeed
- * @see #FastSpeedFactor FastSpeedFactor
- * @see #ScaleSpeed ScaleSpeed
- * @see #MatrixIndices2D MatrixIndices2D
- * @see RotationListener2D
- * @see TranslationListener2D
- * @see ScaleListener2D
- */
- public void ButtonAction2D(Object[] action) {
- if (! (action.length == 2 &&
- action[0] instanceof Double && action[1] instanceof String))
- throw new IllegalArgumentException
- ("\nButtonAction2D must be a number and a string") ;
-
- int button = ((Double)action[0]).intValue() ;
- String actionString = (String)action[1] ;
-
- if (actionString.equals("Rotation"))
- setButtonAction2D(button, ROTATION) ;
- else if (actionString.equals("Translation"))
- setButtonAction2D(button, TRANSLATION) ;
- else if (actionString.equals("Scale"))
- setButtonAction2D(button, SCALE) ;
- else if (actionString.equals("None"))
- setButtonAction2D(button, NONE) ;
- else
- throw new IllegalArgumentException
- ("\nButtonAction2D must be Rotation, Translation, Scale " +
- "or None") ;
- }
-
- /**
- * Sets a button action for the 2D valuator. The possible values are
- * ROTATION
, TRANSLATION
, SCALE
, or
- * NONE
, with a default of NONE
. These actions
- * are the same as those for setReadAction2D
.
- * ArrayOutOfBoundsException
- * when the behavior is initialized or attached to a
- * ViewingPlatform
.
- * SensorEventAgent
used by this behavior directly.
- *
- * @param button index of the button to bind
- * @param action either ROTATION
, TRANSLATION
,
- * SCALE
, or NONE
- * @see #setReadAction2D
- * @see #setRotationCoords
- * @see #setRotationSpeed
- * @see #setTransformCenterSource
- * @see #setTransformCenter
- * @see #setTranslationSpeed
- * @see #setFastSpeedFactor
- * @see #setScaleSpeed
- * @see #setMatrixIndices2D
- * @see #getSensorEventAgent
- * @see RotationListener2D
- * @see TranslationListener2D
- * @see ScaleListener2D
- */
- public synchronized void setButtonAction2D(int button, int action) {
- if (! (action == ROTATION || action == TRANSLATION ||
- action == SCALE || action == NONE))
- throw new IllegalArgumentException
- ("\naction must be ROTATION, TRANSLATION, SCALE, or NONE") ;
-
- while (button >= buttonActions2D.size()) {
- buttonActions2D.add(null) ;
- }
- buttonActions2D.set(button, new Integer(action)) ;
- }
-
-
- /**
- * Gets the action associated with the specified button on the 2D valuator.
- *
- * @return the action associated with the button
- */
- public int getButtonAction2D(int button) {
- if (button >= buttonActions2D.size())
- return NONE ;
-
- Integer i = (Integer)buttonActions2D.get(button) ;
- if (i == null)
- return NONE ;
- else
- return i.intValue() ;
- }
-
- /**
- * Property which sets the action to be bound to 6DOF sensor reads. This
- * action will be performed every frame whenever a button action has not
- * been invoked.
- * Echo
, which displays a geometric
- * representation of the sensor's current position and orientation in the
- * virtual world. A value of None
indicates that no default
- * action is to be applied to the sensor's read.
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * ReadAction6D [Echo | None])
- *
- * @param action array of length 1 containing a String
- * @see #setReadAction6D
- * @see EchoReadListener6D
- */
- public void ReadAction6D(Object[] action) {
- if (! (action.length == 1 && action[0] instanceof String))
- throw new IllegalArgumentException
- ("\nReadAction6D must be a String") ;
-
- String actionString = (String)action[0] ;
-
- if (actionString.equals("Echo"))
- setReadAction6D(ECHO) ;
- else if (actionString.equals("None"))
- setReadAction6D(NONE) ;
- else
- throw new IllegalArgumentException
- ("\nReadAction6D must be Echo or None") ;
- }
-
- /**
- * Sets the action to be bound to 6DOF sensor reads. This action will be
- * performed every frame whenever a button action has not been invoked.
- * ECHO
, which displays a geometric
- * representation of the sensor's current position and orientation in the
- * virtual world. A value of NONE
indicates that no default
- * action is to be associated with the sensor's read.
- * SensorEventAgent
used by this behavior directly.
- *
- * @param action either ECHO
or NONE
- * @see EchoReadListener6D
- * @see #getSensorEventAgent
- */
- public void setReadAction6D(int action) {
- if (! (action == ECHO || action == NONE))
- throw new IllegalArgumentException
- ("\naction must be ECHO or NONE") ;
-
- this.readAction6D = action ;
- }
-
- /**
- * Gets the configured 6DOF sensor read action.
- *
- * @return the configured 6DOF sensor read action
- */
- public int getReadAction6D() {
- if (readAction6D == UNSET)
- return NONE ;
- else
- return readAction6D ;
- }
-
- /**
- * Property which sets the normal translation speed. The default is 0.1
- * meters/second in physical units. This property is set in the
- * configuration file read by ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * TranslationSpeed <speed> [PhysicalMeters | VirtualUnits]
- * [PerFrame | PerSecond])
- *
- * @param speed array of length 3; first element is a Double
- * for the speed, the second is a String
for the units, and
- * the third is a String
for the time base
- * @see #setTranslationSpeed
- */
- public void TranslationSpeed(Object[] speed) {
- if (! (speed.length == 3 && speed[0] instanceof Double &&
- speed[1] instanceof String && speed[2] instanceof String))
- throw new IllegalArgumentException
- ("\nTranslationSpeed must be number, units, and time base") ;
-
- double v = ((Double)speed[0]).doubleValue() ;
- String unitsString = (String)speed[1] ;
- String timeBaseString = (String)speed[2] ;
- int units, timeBase ;
-
- if (unitsString.equals("PhysicalMeters"))
- units = PHYSICAL_METERS ;
- else if (unitsString.equals("VirtualUnits"))
- units = VIRTUAL_UNITS ;
- else
- throw new IllegalArgumentException
- ("\nTranslationSpeed units must be " +
- "PhysicalMeters or VirtualUnits") ;
-
- if (timeBaseString.equals("PerFrame"))
- timeBase = PER_FRAME ;
- else if (timeBaseString.equals("PerSecond"))
- timeBase = PER_SECOND ;
- else
- throw new IllegalArgumentException
- ("\ntime base must be PerFrame or PerSecond") ;
-
- setTranslationSpeed(v, units, timeBase) ;
- }
-
- /**
- * Sets the normal translation speed. The default is 0.1 physical
- * meters/second.
- *
- * @param speed how fast to translate
- * @param units either PHYSICAL_METERS
or
- * VIRTUAL_UNITS
- * @param timeBase either PER_SECOND
or
- * PER_FRAME
- */
- public void setTranslationSpeed(double speed, int units, int timeBase) {
- this.translationSpeed = speed ;
-
- if (units == PHYSICAL_METERS || units == VIRTUAL_UNITS)
- this.translationUnits = units ;
- else
- throw new IllegalArgumentException
- ("\ntranslation speed units must be " +
- "PHYSICAL_METERS or VIRTUAL_UNITS") ;
-
- if (timeBase == PER_FRAME || timeBase == PER_SECOND)
- this.translationTimeBase = timeBase ;
- else
- throw new IllegalArgumentException
- ("\ntranslation time base must be PER_FRAME or PER_SECOND") ;
- }
-
- /**
- * Gets the normal speed at which to translate the view platform.
- *
- * @return the normal translation speed
- */
- public double getTranslationSpeed() {
- return translationSpeed ;
- }
-
- /**
- * Gets the translation speed units.
- *
- * @return the translation units
- */
- public int getTranslationUnits() {
- return translationUnits ;
- }
-
- /**
- * Gets the time base for translation speed.
- *
- * @return the translation time base
- */
- public int getTranslationTimeBase() {
- return translationTimeBase ;
- }
-
- /**
- * Property which sets the time interval for accelerating to the
- * translation, rotation, or scale speeds and for transitioning between
- * the normal and fast translation speeds. The default is 1 second. This
- * property is set in the configuration file read by
- * ConfiguredUniverse
.
(ViewPlatformBehaviorProperty <name>
- * AccelerationTime <seconds>)
- *
- * @param time array of length 1 containing a Double
- * @see #setAccelerationTime
- */
- public void AccelerationTime(Object[] time) {
- if (! (time.length == 1 && time[0] instanceof Double))
- throw new IllegalArgumentException
- ("\nAccelerationTime must be a number") ;
-
- setAccelerationTime(((Double)time[0]).doubleValue()) ;
- }
-
- /**
- * Sets the time interval for accelerating to the translation, rotation,
- * or scale speeds and for transitioning between the normal and fast
- * translation speeds. The default is 1 second.
- *
- * @param time number of seconds to accelerate to normal or fast speed
- */
- public void setAccelerationTime(double time) {
- this.accelerationTime = time ;
- }
-
- /**
- * Gets the time interval for accelerating to normal speed and for
- * transitioning between the normal and fast translation speeds.
- *
- * @return the acceleration time
- */
- public double getAccelerationTime() {
- return accelerationTime ;
- }
-
- /**
- * Property which sets the time interval for which the translation occurs
- * at the normal speed. The default is 8 seconds. This property is set
- * in the configuration file read by ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * ConstantSpeedTime <seconds>)
- *
- * @param time array of length 1 containing a Double
- * @see #setConstantSpeedTime
- */
- public void ConstantSpeedTime(Object[] time) {
- if (! (time.length == 1 && time[0] instanceof Double))
- throw new IllegalArgumentException
- ("\nConstantSpeedTime must be a number") ;
-
- setConstantSpeedTime(((Double)time[0]).doubleValue()) ;
- }
-
- /**
- * Sets the time interval for which the translation occurs at the normal
- * speed. The default is 8 seconds.
- *
- * @param time number of seconds to translate at a constant speed
- */
- public void setConstantSpeedTime(double time) {
- this.constantSpeedTime = time ;
- }
-
- /**
- * Gets the time interval for which the translation occurs at the
- * normal speed.
- *
- * @return the constant speed time
- */
- public double getConstantSpeedTime() {
- return constantSpeedTime ;
- }
-
- /**
- * Property which sets the fast translation speed factor. The default is
- * 10 times the normal speed. This property is set in the configuration
- * file read by ConfiguredUniverse.
- *
(ViewPlatformBehaviorProperty <name>
- * FastSpeedFactor <factor>)
- *
- * @param factor array of length 1 containing a Double
- * @see #setFastSpeedFactor
- */
- public void FastSpeedFactor(Object[] factor) {
- if (! (factor.length == 1 && factor[0] instanceof Double))
- throw new IllegalArgumentException
- ("\nFastSpeedFactor must be a number") ;
-
- setFastSpeedFactor(((Double)factor[0]).doubleValue()) ;
- }
-
- /**
- * Sets the fast translation speed factor. The default is 10 times the
- * normal speed.
- *
- * @param factor scale by which the normal translation speed is multiplied
- */
- public void setFastSpeedFactor(double factor) {
- this.fastSpeedFactor = factor ;
- }
-
- /**
- * Gets the factor by which the normal translation speed is multiplied
- * after the constant speed time interval.
- *
- * @return the fast speed factor
- */
- public double getFastSpeedFactor() {
- return fastSpeedFactor ;
- }
-
- /**
- * Property which sets the threshold for 2D valuator reads. The default
- * is 0.0. It can be set higher to handle noisy valuators. This property
- * is set in the configuration file read by
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * Threshold2D <threshold>)
- *
- * @param threshold array of length 1 containing a Double
- * @see #setThreshold2D
- */
- public void Threshold2D(Object[] threshold) {
- if (! (threshold.length == 1 && threshold[0] instanceof Double))
- throw new IllegalArgumentException
- ("\nThreshold2D must be a number") ;
-
- setThreshold2D(((Double)threshold[0]).doubleValue()) ;
- }
-
- /**
- * Sets the threshold for 2D valuator reads. The default is 0.0. It can
- * be set higher to handle noisy valuators.
- *
- * @param threshold if the absolute values of both the X and Y valuator
- * reads are less than this value then the values are ignored
- */
- public void setThreshold2D(double threshold) {
- this.threshold2D = threshold ;
- }
-
- /**
- * Gets the 2D valuator threshold.
- *
- * @return the threshold value
- */
- public double getThreshold2D() {
- return threshold2D ;
- }
-
- /**
- * Property which specifies where to find the X and Y values in the matrix
- * read generated by a 2D valuator. The defaults are along the
- * translation components of the matrix, at indices 3 and 7. This
- * property is set in the configuration file read by
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * MatrixIndices2D <X index> <Y index>)
- *
- * @param indices array of length 2 containing Doubles
- * @see #setMatrixIndices2D
- */
- public void MatrixIndices2D(Object[] indices) {
- if (! (indices.length == 2 &&
- indices[0] instanceof Double && indices[1] instanceof Double))
- throw new IllegalArgumentException
- ("\nMatrixIndices2D must be a numbers") ;
-
- setMatrixIndices2D(((Double)indices[0]).intValue(),
- ((Double)indices[1]).intValue()) ;
- }
-
- /**
- * Specifies where to find the X and Y values in the matrix read generated
- * by a 2D valuator. The defaults are along the translation components of
- * the matrix, at indices 3 and 7.
- *
- * @param xIndex index of the X valuator value
- * @param yIndex index of the Y valuator value
- */
- public void setMatrixIndices2D(int xIndex, int yIndex) {
- this.x2D = xIndex ;
- this.y2D = yIndex ;
- }
-
- /**
- * Gets the index where the X value of a 2D valuator read matrix can be
- * found.
- *
- * @return the X index in the read matrix
- */
- public int getMatrixXIndex2D() {
- return x2D ;
- }
-
- /**
- * Gets the index where the Y value of a 2D valuator read matrix can be
- * found.
- *
- * @return the Y index in the read matrix
- */
- public int getMatrixYIndex2D() {
- return y2D ;
- }
-
- /**
- * Property which sets the rotation speed. The default is 180
- * degrees/second. This property is set in the configuration file read by
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * RotationSpeed <speed> [Degrees | Radians]
- * [PerFrame | PerSecond])
- *
- * @param speed array of length 3; first element is a Double
- * for the speed, the second is a String
for the units, and
- * the third is a String
for the time base
- * @see #setRotationSpeed
- */
- public void RotationSpeed(Object[] speed) {
- if (! (speed.length == 3 && speed[0] instanceof Double &&
- speed[1] instanceof String && speed[2] instanceof String))
- throw new IllegalArgumentException
- ("\nRotationSpeed must be number, units, and time base") ;
-
- double v = ((Double)speed[0]).doubleValue() ;
- String unitsString = (String)speed[1] ;
- String timeBaseString = (String)speed[2] ;
- int units, timeBase ;
-
- if (unitsString.equals("Degrees"))
- units = DEGREES ;
- else if (unitsString.equals("Radians"))
- units = RADIANS ;
- else
- throw new IllegalArgumentException
- ("\nRotationSpeed units must be Degrees or Radians") ;
-
- if (timeBaseString.equals("PerFrame"))
- timeBase = PER_FRAME ;
- else if (timeBaseString.equals("PerSecond"))
- timeBase = PER_SECOND ;
- else
- throw new IllegalArgumentException
- ("\nRotationSpeed time base must be PerFrame or PerSecond") ;
-
- setRotationSpeed(v, units, timeBase) ;
- }
-
- /**
- * Sets the rotation speed. The default is 180 degrees/second.
- *
- * @param speed how fast to rotate
- * @param units either DEGREES
or RADIANS
- * @param timeBase either PER_SECOND
or PER_FRAME
- */
- public void setRotationSpeed(double speed, int units, int timeBase) {
- this.rotationSpeed = speed ;
-
- if (units == DEGREES || units == RADIANS)
- this.rotationUnits = units ;
- else
- throw new IllegalArgumentException
- ("\nrotation speed units must be DEGREES or RADIANS") ;
-
- if (timeBase == PER_FRAME || timeBase == PER_SECOND)
- this.rotationTimeBase = timeBase ;
- else
- throw new IllegalArgumentException
- ("\nrotation time base must be PER_FRAME or PER_SECOND") ;
- }
-
- /**
- * Gets the rotation speed.
- *
- * @return the rotation speed
- */
- public double getRotationSpeed() {
- return rotationSpeed ;
- }
-
- /**
- * Gets the rotation speed units
- *
- * @return the rotation units
- */
- public int getRotationUnits() {
- return rotationUnits ;
- }
-
- /**
- * Gets the time base for rotation speed.
- *
- * @return the rotation time base
- */
- public int getRotationTimeBase() {
- return rotationTimeBase ;
- }
-
- /**
- * Property which sets the rotation coordinate system. The default is
- * Sensor
, which means that the rotation axis is parallel to
- * the XY plane of the current orientation of a specified 6DOF sensor. A
- * value of ViewPlatform
means the rotation axis is parallel
- * to the XY plane of the view platform. The latter is also the fallback
- * if a 6DOF sensor is not specified. If the value is Head
,
- * then the rotation occurs in head coordinates.
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * RotationCoords [Sensor | ViewPlatform | Head])
- *
- * @param coords array of length 1 containing a String
- * @see #setRotationCoords
- */
- public void RotationCoords(Object[] coords) {
- if (! (coords.length == 1 && coords[0] instanceof String))
- throw new IllegalArgumentException
- ("\nRotationCoords must be a String") ;
-
- String coordsString = (String)coords[0] ;
-
- if (coordsString.equals("Sensor"))
- setRotationCoords(SENSOR) ;
- else if (coordsString.equals("ViewPlatform"))
- setRotationCoords(VIEW_PLATFORM) ;
- else if (coordsString.equals("Head"))
- setRotationCoords(HEAD) ;
- else
- throw new IllegalArgumentException
- ("\nRotationCoords must be Sensor, ViewPlatform, or Head") ;
- }
-
- /**
- * Sets the rotation coordinate system. The default is
- * SENSOR
, which means that the rotation axis is parallel to
- * the XY plane of the current orientation of a specified 6DOF sensor. A
- * value of VIEW_PLATFORM
means the rotation axis is parallel
- * to the XY plane of the view platform. The latter is also the fallback
- * if a 6DOF sensor is not specified. If the value is HEAD
,
- * then rotation occurs in head coordinates.
- *
- * @param coords either SENSOR
, VIEW_PLATFORM
, or
- * HEAD
- */
- public void setRotationCoords(int coords) {
- if (! (coords == SENSOR || coords == VIEW_PLATFORM || coords == HEAD))
- throw new IllegalArgumentException
- ("\nrotation coordinates be SENSOR, VIEW_PLATFORM, or HEAD") ;
-
- this.rotationCoords = coords ;
- }
-
- /**
- * Gets the rotation coordinate system.
- *
- * @return the rotation coordinate system
- */
- public int getRotationCoords() {
- return rotationCoords ;
- }
-
- /**
- * Property which sets the scaling speed. The default is 2.0 per second,
- * which means magnification doubles the apparent size of the virtual
- * world every second, and minification halves the apparent size of the
- * virtual world every second.
- * Math.pow(scaleSpeed,
- * frameTime)
, where frameTime
is the time in seconds
- * that the last frame took to render if the time base is
- * PerSecond
, or 1.0 if the time base is
- * PerFrame
. If scaling is performed with the 2D valuator,
- * then the valuator's Y value as specified by
- * MatrixIndices2D
is an additional scale applied to the
- * exponent. If scaling is performed by the 6DOF sensor, then the scale
- * speed can be inverted with a negative exponent by using the appropriate
- * listener constructor flag.
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * ScaleSpeed <speed> [PerFrame | PerSecond])
- *
- * @param speed array of length 2; first element is a Double
- * for the speed, and the second is a String
for the time
- * base
- * @see #setScaleSpeed
- */
- public void ScaleSpeed(Object[] speed) {
- if (! (speed.length == 2 &&
- speed[0] instanceof Double && speed[1] instanceof String))
- throw new IllegalArgumentException
- ("\nScalingSpeed must be a number and a string") ;
-
- double v = ((Double)speed[0]).doubleValue() ;
- String timeBaseString = (String)speed[2] ;
- int timeBase ;
-
- if (timeBaseString.equals("PerFrame"))
- timeBase = PER_FRAME ;
- else if (timeBaseString.equals("PerSecond"))
- timeBase = PER_SECOND ;
- else
- throw new IllegalArgumentException
- ("\nScalingSpeed time base must be PerFrame or PerSecond") ;
-
- setScaleSpeed(v, timeBase) ;
- }
-
- /**
- * Sets the scaling speed. The default is 2.0 per second, which means
- * magnification doubles the apparent size of the virtual world every
- * second, and minification halves the apparent size of the virtual world
- * every second.
- * Math.pow(scaleSpeed,
- * frameTime)
, where frameTime
is the time in seconds
- * that the last frame took to render if the time base is
- * PER_SECOND
, or 1.0 if the time base is
- * PER_FRAME
. If scaling is performed with the 2D valuator,
- * then the valuator's Y value as specified by
- * setMatrixIndices2D
is an additional scale applied to the
- * exponent. If scaling is performed by the 6DOF sensor, then the scale
- * speed can be inverted with a negative exponent by using the appropriate
- * listener constructor flag.
- *
- * @param speed specifies the scale speed
- * @param timeBase either PER_SECOND
or PER_FRAME
- */
- public void setScaleSpeed(double speed, int timeBase) {
- this.scaleSpeed = speed ;
-
- if (timeBase == PER_FRAME || timeBase == PER_SECOND)
- this.scaleTimeBase = timeBase ;
- else
- throw new IllegalArgumentException
- ("\nscaling time base must be PER_FRAME or PER_SECOND") ;
- }
-
- /**
- * Gets the scaling speed.
- *
- * @return the scaling speed
- */
- public double getScaleSpeed() {
- return scaleSpeed ;
- }
-
- /**
- * Gets the time base for scaling speed.
- *
- * @return the scaling time base
- */
- public int getScaleTimeBase() {
- return scaleTimeBase ;
- }
-
- /**
- * Property which sets the source of the center of rotation and scale.
- * The default is Hotspot
, which means the center of rotation
- * or scale is a 6DOF sensor's current hotspot location. The alternative
- * is VworldFixed
, which uses the fixed virtual world
- * coordinates specified by the TransformCenter
property as
- * the center. The latter is also the fallback if a 6DOF sensor is not
- * specified. This property is set in the configuration file read by
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * TransformCenterSource [Hotspot | VworldFixed])
- *
- * @param source array of length 1 containing a String
- * @see #setTransformCenterSource
- */
- public void TransformCenterSource(Object[] source) {
- if (! (source.length == 1 && source[0] instanceof String))
- throw new IllegalArgumentException
- ("\nTransformCenterSource must be a String") ;
-
- String sourceString = (String)source[0] ;
-
- if (sourceString.equals("Hotspot"))
- setTransformCenterSource(HOTSPOT) ;
- else if (sourceString.equals("VworldFixed"))
- setTransformCenterSource(VWORLD_FIXED) ;
- else
- throw new IllegalArgumentException
- ("\nTransformCenterSource must be Hotspot or " +
- "VworldFixed") ;
- }
-
- /**
- * Sets the source of the center of rotation and scale. The default is
- * HOTSPOT
, which means the center of rotation or scale is a
- * 6DOF sensor's current hotspot location. The alternative is
- * VWORLD_FIXED
, which uses the fixed virtual world
- * coordinates specified by setTransformCenter
as the center.
- * The latter is also the fallback if a 6DOF sensor is not specified.
- * HOTSPOT
or VWORLD_FIXED
- */
- public void setTransformCenterSource(int source) {
- if (! (source == HOTSPOT || source == VWORLD_FIXED))
- throw new IllegalArgumentException
- ("\nrotation/scale center source must be HOTSPOT or " +
- "VWORLD_FIXED") ;
-
- this.transformCenterSource = source ;
- }
-
- /**
- * Gets the rotation/scale center source.
- *
- * @return the rotation/scale center source
- */
- public int getTransformCenterSource() {
- return transformCenterSource ;
- }
-
- /**
- * Property which sets the center of rotation and scale if the
- * TransformCenterSource
property is VworldFixed
- * or if a 6DOF sensor is not specified. The default is (0.0, 0.0, 0.0)
- * in virtual world coordinates. This property is set in the
- * configuration file read by ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * TransformCenter <Point3d>)
- *
- * @param center array of length 1 containing a Point3d
- * @see #setTransformCenter
- */
- public void TransformCenter(Object[] center) {
- if (! (center.length == 1 && center[0] instanceof Point3d))
- throw new IllegalArgumentException
- ("\nTransformCenter must be a Point3d") ;
-
- setTransformCenter((Point3d)center[0]) ;
- }
-
- /**
- * Sets the center of rotation and scale if
- * setTransformCenterSource
is called with
- * VWORLD_FIXED
or if a 6DOF sensor is not specified. The
- * default is (0.0, 0.0, 0.0) in virtual world coordinates.
- * Point3d
to receive a copy of the
- * rotation/scale center
- */
- public void getTransformCenter(Point3d center) {
- center.set(transformCenter) ;
- }
-
- /**
- * Property which sets the nominal sensor rotation. The default is the
- * identity transform.
- * InputDevice
supporting the
- * sensor handles its orientation. The NominalSensorRotation
- * property can be used to correct the alignment by specifying the
- * rotation needed to transform vectors from the nominal sensor coordinate
- * system, aligned with the image plate coordinate system as described
- * above, to the sensor's actual local coordinate system.
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * NominalSensorRotation [<Matrix4d> |
- * <Matrix3d>])
- *
- * @param matrix array of length 1 containing a Matrix4d
or
- * Matrix3d
- * @see #setNominalSensorRotation
- */
- public void NominalSensorRotation(Object[] matrix) {
- if (! (matrix.length == 1 && (matrix[0] instanceof Matrix3d ||
- matrix[0] instanceof Matrix4d)))
- throw new IllegalArgumentException
- ("\nNominalSensorRotation must be a Matrix3d or Matrix4d") ;
-
- Transform3D t3d = new Transform3D() ;
-
- if (matrix[0] instanceof Matrix3d)
- t3d.set((Matrix3d)matrix[0]) ;
- else
- t3d.set((Matrix4d)matrix[0]) ;
-
- setNominalSensorRotation(t3d) ;
- }
-
- /**
- * Sets the nominal sensor transform. The default is the identity
- * transform.
- * InputDevice
supporting the
- * sensor handles its orientation. setNominalSensorRotation
- * can be called to correct the alignment by specifying the rotation
- * needed to transform vectors from the nominal sensor coordinate system,
- * aligned with the image plate coordinate system as described above, to
- * the sensor's actual local coordinate system.
- * null
for
- * identity.
- */
- public void setNominalSensorRotation(Transform3D transform) {
- if (transform == null) {
- nominalSensorRotation = null ;
- return ;
- }
-
- if (nominalSensorRotation == null)
- nominalSensorRotation = new Transform3D() ;
-
- // Set transform and make sure it is a rotation only.
- nominalSensorRotation.set(transform) ;
- nominalSensorRotation.setTranslation(new Vector3d()) ;
- }
-
- /**
- * Gets the nominal sensor transform.
- *
- * @param t3d Transform3D
to receive a copy of the
- * nominal sensor transform
- */
- public void getNominalSensorRotation(Transform3D t3d) {
- if (nominalSensorRotation != null) {
- t3d.set(nominalSensorRotation);
- } else {
- t3d.setIdentity();
- }
- }
-
- /**
- * Property which sets the number of buttons to be pressed simultaneously
- * on the 6DOF sensor in order to reset the view back to the home
- * transform. The value must be greater than 1; the default is 3. A
- * value of None
disables this action. This property is set
- * in the configuration file read by ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * ResetViewButtonCount6D [<count> | None])
- *
- * @param count array of length 1 containing a Double
or
- * String
- * @see #setResetViewButtonCount6D
- * @see ViewPlatformBehavior#setHomeTransform
- * ViewPlatformBehavior.setHomeTransform
- */
- public void ResetViewButtonCount6D(Object[] count) {
- if (! (count.length == 1 &&
- (count[0] instanceof Double || count[0] instanceof String)))
- throw new IllegalArgumentException
- ("\nResetViewButtonCount6D must be a number or None") ;
-
- if (count[0] instanceof String) {
- String s = (String)count[0] ;
- if (s.equals("None"))
- setResetViewButtonCount6D(NONE) ;
- else
- throw new IllegalArgumentException
- ("\nResetViewButtonCount6D string value must be None") ;
- }
- else {
- setResetViewButtonCount6D(((Double)count[0]).intValue()) ;
- }
- }
-
- /**
- * Sets the number of buttons to be pressed simultaneously
- * on the 6DOF sensor in order to reset the view back to the home
- * transform. The value must be greater than 1; the default is 3. A
- * value of NONE
disables this action.
- *
- * @param count either NONE
or button count > 1
- * @see ViewPlatformBehavior#setHomeTransform
- * ViewPlatformBehavior.setHomeTransform
- */
- public void setResetViewButtonCount6D(int count) {
- if (count == NONE || count > 1) {
- resetViewButtonCount6D = count ;
- }
- else {
- throw new IllegalArgumentException
- ("reset view button count must be > 1") ;
- }
- }
-
- /**
- * Gets the number of buttons to be pressed simultaneously on the 6DOF
- * sensor in order to reset the view back to the home transform. A value
- * of NONE
indicates this action is disabled.
- *
- * @return the number of buttons to press simultaneously for a view reset
- */
- public int getResetViewButtonCount6D() {
- return resetViewButtonCount6D ;
- }
-
- /**
- * Property which sets the number of buttons to be pressed simultaneously
- * on the 2D valuator in order to reset the view back to the home
- * transform. The value must be greater than 1; the default is
- * None
. A value of None
disables this action.
- * This property is set in the configuration file read by
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * ResetViewButtonCount2D [<count> | None])
- *
- * @param count array of length 1 containing a Double
or
- * String
- * @see #setResetViewButtonCount2D
- * @see ViewPlatformBehavior#setHomeTransform
- * ViewPlatformBehavior.setHomeTransform
- */
- public void ResetViewButtonCount2D(Object[] count) {
- if (! (count.length == 1 &&
- (count[0] instanceof Double || count[0] instanceof String)))
- throw new IllegalArgumentException
- ("\nResetViewButtonCount2D must be a number or None") ;
-
- if (count[0] instanceof String) {
- String s = (String)count[0] ;
- if (s.equals("None"))
- setResetViewButtonCount2D(NONE) ;
- else
- throw new IllegalArgumentException
- ("\nResetViewButtonCount2D string value must be None") ;
- }
- else {
- setResetViewButtonCount2D(((Double)count[0]).intValue()) ;
- }
- }
-
- /**
- * Sets the number of buttons to be pressed simultaneously on the 2D
- * valuator in order to reset the view back to the home transform. The
- * value must be greater than 1; the default is NONE
. A
- * value of NONE
disables this action.
- *
- * @param count either NONE
or button count > 1
- * @see ViewPlatformBehavior#setHomeTransform
- * ViewPlatformBehavior.setHomeTransform
- */
- public void setResetViewButtonCount2D(int count) {
- if (count == NONE || count > 1) {
- resetViewButtonCount2D = count ;
- }
- else {
- throw new IllegalArgumentException
- ("reset view button count must be > 1") ;
- }
- }
-
- /**
- * Gets the number of buttons to be pressed simultaneously on the 2D
- * valuator in order to reset the view back to the home transform. A value
- * of NONE
indicates this action is disabled.
- *
- * @return the number of buttons to press simultaneously for a view reset
- */
- public int getResetViewButtonCount2D() {
- return resetViewButtonCount2D ;
- }
-
- /**
- * Property which sets the 6DOF sensor echo type. The default is
- * Gnomon
, which displays an object with points indicating
- * the direction of each of the sensor's coordinate system axes at the
- * location of the sensor's hotspot. The alternative is
- * Beam
, which displays a beam from the sensor's origin to
- * the location of the sensor's hotspot; the hotspot must not be (0, 0, 0)
- * or an IllegalArgumentException
will result. The width of
- * each of these echo types is specified by the EchoSize
- * property. The EchoType
property is set in the
- * configuration file read by ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * EchoType [Gnomon | Beam | None])
- *
- * @param type array of length 1 containing a String
- * @see #setEchoType
- */
- public void EchoType(Object[] type) {
- if (! (type.length == 1 && type[0] instanceof String))
- throw new IllegalArgumentException
- ("\nEchoType must be a String") ;
-
- String typeString = (String)type[0] ;
-
- if (typeString.equals("Gnomon"))
- setEchoType(GNOMON) ;
- else if (typeString.equals("Beam"))
- setEchoType(BEAM) ;
- else if (typeString.equals("None"))
- setEchoType(NONE) ;
- else
- throw new IllegalArgumentException
- ("\nEchoType must be Gnomon, Beam, or None") ;
- }
-
- /**
- * Sets the 6DOF sensor echo type. The default is GNOMON
,
- * which displays an object with points indicating the direction of each
- * of the sensor's coordinate axes at the location of the sensor's
- * hotspot. The alternative is BEAM
, which displays a beam
- * from the sensor's origin to the location of the sensor's hotspot; the
- * hotspot must not be (0, 0, 0) or an
- * IllegalArgumentException
will result. The width of each
- * of these echo types is specified by setEchoSize
.
- *
- * @param type GNOMON
, BEAM
, or
- * NONE
are recognized
- */
- public void setEchoType(int type) {
- this.echoType = type ;
- }
-
- /**
- * Gets the echo type.
- *
- * @return the echo type
- */
- public int getEchoType() {
- return echoType ;
- }
-
- /**
- * Property which sets the size of the 6DOF sensor echo in physical
- * meters. This is used for the width of the gnomon and beam echoes. The
- * default is 1 centimeter. This property is set in the configuration
- * file read by ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * EchoSize <size>)
- *
- * @param echoSize array of length 1 containing a Double
- * @see #setEchoSize
- */
- public void EchoSize(Object[] echoSize) {
- if (! (echoSize.length == 1 && echoSize[0] instanceof Double))
- throw new IllegalArgumentException
- ("\nEchoSize must be a Double") ;
-
- setEchoSize(((Double)echoSize[0]).doubleValue()) ;
- }
-
- /**
- * Sets the size of the 6DOF sensor echo in physical meters. This is used
- * for the width of the gnomon and beam echoes. The default is 1
- * centimeter.
- *
- * @param echoSize the size in meters
- */
- public void setEchoSize(double echoSize) {
- this.echoSize = echoSize ;
- }
-
- /**
- * Gets the size of the 6DOF sensor echo in meters.
- *
- * @return the echo size
- */
- public double getEchoSize() {
- return echoSize ;
- }
-
- /**
- * Property which sets the color of the 6DOF sensor echo. The default is
- * white. This property is set in the configuration file read by
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * EchoColor <red> <green> <blue>)
- *
- * @param color array of length 3 containing Doubles
- * @see #setEchoColor
- */
- public void EchoColor(Object[] color) {
- if (! (color.length == 3 && color[0] instanceof Double &&
- color[1] instanceof Double && color[2] instanceof Double))
- throw new IllegalArgumentException
- ("\nEchoColor must be 3 numbers for red, green, and blue") ;
-
- setEchoColor(new Color3f(((Double)color[0]).floatValue(),
- ((Double)color[1]).floatValue(),
- ((Double)color[2]).floatValue())) ;
- }
-
- /**
- * Sets the color of the 6DOF sensor echo. The default is white. This
- * can be called to set the color before or after the echo geometry is
- * created.
- *
- * @param color the echo color
- */
- public void setEchoColor(Color3f color) {
- if (echoColor == null)
- echoColor = new Color3f(color) ;
- else
- echoColor.set(color) ;
-
- if (echoGeometry != null) {
- Appearance a = echoGeometry.getAppearance() ;
- Material m = a.getMaterial() ;
- m.setDiffuseColor(echoColor) ;
- }
- }
-
- /**
- * Gets the 6DOF sensor echo color.
- *
- * @param color the Color3f
into which to copy the echo color
- */
- public void getEchoColor(Color3f color) {
- if (echoColor == null)
- color.set(1.0f, 1.0f, 1.0f) ;
- else
- color.set(echoColor) ;
- }
-
- /**
- * Property which sets the 6DOF sensor echo transparency. The default is
- * opaque. A value of 0.0 is fully opaque and 1.0 is fully transparent.
- * This property is set in the configuration file read by
- * ConfiguredUniverse
.
- *
(ViewPlatformBehaviorProperty <name>
- * EchoTransparency <transparency>)
- *
- * @param transparency array of length 1 containing a Double
- * @see #setEchoTransparency
- */
- public void EchoTransparency(Object[] transparency) {
- if (! (transparency.length == 1 && transparency[0] instanceof Double))
- throw new IllegalArgumentException
- ("\nEchoTransparency must be a number") ;
-
- setEchoTransparency(((Double)transparency[0]).floatValue()) ;
- }
-
- /**
- * Sets the 6DOF sensor echo transparency. The default is opaque. A
- * value of 0.0 is fully opaque and 1.0 is fully transparent. This can be
- * called to set the transparency before or after the echo geometry is
- * created.
- *
- * @param transparency the transparency value
- */
- public void setEchoTransparency(float transparency) {
- echoTransparency = transparency ;
-
- if (echoGeometry != null) {
- Appearance a = echoGeometry.getAppearance() ;
- TransparencyAttributes ta = a.getTransparencyAttributes() ;
- if (echoTransparency == 0.0f) {
- ta.setTransparencyMode(TransparencyAttributes.NONE) ;
- ta.setTransparency(0.0f) ;
- }
- else {
- ta.setTransparencyMode(TransparencyAttributes.BLENDED) ;
- ta.setTransparency(echoTransparency) ;
- // Use order independent additive blend for gnomon.
- if (echoGeometry instanceof SensorGnomonEcho)
- ta.setDstBlendFunction(TransparencyAttributes.BLEND_ONE) ;
- }
- }
- }
-
- /**
- * Gets the 6DOF sensor echo transparency value.
- *
- * @return the transparency value
- */
- public float getEchoTransparency() {
- return echoTransparency ;
- }
-
- /**
- * Sets the transform group containing a 6DOF sensor's echo geometry.
- * This is used to specify a custom echo. Its transform will be
- * manipulated to represent the position and orientation of the 6DOF
- * sensor. Capabilities to allow writing its transform and to read,
- * write, and extend its children will be set.
- * TransformGroup
containing the
- * echo geometry
- */
- public void setEchoTransformGroup(TransformGroup echo) {
- echo.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE) ;
- echo.setCapability(Group.ALLOW_CHILDREN_READ) ;
- echo.setCapability(Group.ALLOW_CHILDREN_WRITE) ;
- echo.setCapability(Group.ALLOW_CHILDREN_EXTEND) ;
- this.echoTransformGroup = echo ;
- }
-
- /**
- * Gets the transform group containing a 6DOF sensor's echo geometry.
- * Capabilities to write its transform and read, write, and extend its
- * children are granted.
- *
- * @return the echo's transform group
- */
- public TransformGroup getEchoTransformGroup() {
- return echoTransformGroup ;
- }
-
- /**
- * Gets the Shape3D
defining the 6DOF sensor's echo geometry
- * and appearance. The returned Shape3D
allows appearance
- * read and write. If a custom echo was supplied by providing the echo
- * transform group directly then the return value will be
- * null
.
- *
- * @return the echo geometry, or null
if a custom echo was
- * supplied
- */
- public Shape3D getEchoGeometry() {
- return echoGeometry ;
- }
-
- /**
- * Gets the SensorEventAgent
used by this behavior. Sensor
- * event generation is delegated to this agent. This can be accessed to
- * manipulate the sensor button and read action bindings directly.
- *
- * @return the sensor event agent
- */
- public SensorEventAgent getSensorEventAgent() {
- return eventAgent ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/behaviors/vp/package.html b/src/classes/share/com/sun/j3d/utils/behaviors/vp/package.html
deleted file mode 100644
index 4900193..0000000
--- a/src/classes/share/com/sun/j3d/utils/behaviors/vp/package.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-com.sun.j3d.utils.geometry.compression
-instead.cloneTree
to duplicate the current node.
- * cloneNode
should be overridden by any user subclassed
- * objects. All subclasses must have their cloneNode
- * method consist of the following lines:
- *
- * @param forceDuplicate when set to
- * public Node cloneNode(boolean forceDuplicate) {
- * UserSubClass usc = new UserSubClass();
- * usc.duplicateNode(this, forceDuplicate);
- * return usc;
- * }
- *
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.
- *
- * @see Node#cloneTree
- * @see Node#duplicateNode
- * @see NodeComponent#setDuplicateOnCloneTree
- */
- @Override
- public Node cloneNode(boolean forceDuplicate) {
- Box b = new Box(xDim, yDim, zDim, flags, getAppearance());
- 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.
- * 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
.
- *
- * @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.
- *
- * @see Node#cloneTree
- * @see Node#cloneNode
- * @see NodeComponent#setDuplicateOnCloneTree
- */
- @Override
- public void duplicateNode(Node originalNode, boolean forceDuplicate) {
- super.duplicateNode(originalNode, forceDuplicate);
- }
-
- /**
- * Returns the X-dimension size of the Box
- *
- * @since Java 3D 1.2.1
- */
- public float getXdimension() {
- return xDim;
- }
-
- /**
- * Returns the Y-dimension size of the Box
- *
- * @since Java 3D 1.2.1
- */
- public float getYdimension() {
- return yDim;
- }
-
- /**
- * Returns the Z-dimension size of the Box
- *
- * @since Java 3D 1.2.1
- */
- public float getZdimension() {
- return zDim;
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Bridge.java b/src/classes/share/com/sun/j3d/utils/geometry/Bridge.java
deleted file mode 100644
index 2dfb7ec..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Bridge.java
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-
-class Bridge {
-
- static void constructBridges(Triangulator triRef, int loopMin, int loopMax) {
- int i, j, numDist, numLeftMost;
-
- int[] i0 = new int[1];
- int[] ind0 = new int[1];
- int[] i1 = new int[1];
- int[] ind1 = new int[1];
-
- int[] iTmp = new int[1];
- int[] indTmp = new int[1];
-
- if(triRef.noHashingEdges != true)
- System.out.println("Bridge:constructBridges noHashingEdges is false");
- if(loopMax <= loopMin)
- System.out.println("Bridge:constructBridges loopMax<=loopMin");
- if(loopMin < 0)
- System.out.println("Bridge:constructBridges loopMin<0");
- if(loopMax > triRef.numLoops)
- System.out.println("Bridge:constructBridges loopMax>triRef.numLoops");
-
- numLeftMost = loopMax - loopMin - 1;
-
- if (numLeftMost > triRef.maxNumLeftMost) {
- triRef.maxNumLeftMost = numLeftMost;
- triRef.leftMost = new Left[numLeftMost];
- }
-
- // For each contour, find the left-most vertex. (we will use the fact
- // that the vertices appear in sorted order!)
- findLeftMostVertex(triRef, triRef.loops[loopMin], ind0, i0);
- j = 0;
- for (i = loopMin + 1; i < loopMax; ++i) {
- findLeftMostVertex(triRef, triRef.loops[i], indTmp, iTmp);
- triRef.leftMost[j] = new Left();
- triRef.leftMost[j].ind = indTmp[0];
- triRef.leftMost[j].index = iTmp[0];
-
- ++j;
- }
-
- // sort the inner contours according to their left-most vertex
- sortLeft(triRef.leftMost, numLeftMost);
-
- // construct bridges. every bridge will eminate at the left-most point of
- // its corresponding inner loop.
- numDist = triRef.numPoints + 2 * triRef.numLoops;
- triRef.maxNumDist = numDist;
- triRef.distances = new Distance[numDist];
- for (int k = 0; k < triRef.maxNumDist; k++)
- triRef.distances[k] = new Distance();
-
-
- for (j = 0; j < numLeftMost; ++j) {
- if (!findBridge(triRef, ind0[0], i0[0], triRef.leftMost[j].index, ind1, i1)) {
- // if (verbose)
- // fprintf(stderr, "\n\n***** yikes! the loops intersect! *****\n");
- }
- if (i1[0] == triRef.leftMost[j].index)
- // the left-most node of the hole coincides with a node of the
- // boundary
- simpleBridge(triRef, ind1[0], triRef.leftMost[j].ind);
- else
- // two bridge edges need to be inserted
- insertBridge(triRef, ind1[0], i1[0], triRef.leftMost[j].ind,
- triRef.leftMost[j].index);
- }
-
- }
-
-
- /**
- * We try to find a vertex i1 on the loop which contains i such that i1
- * is close to start, and such that i1, start is a valid diagonal.
- */
- static boolean findBridge(Triangulator triRef, int ind, int i, int start,
- int[] ind1, int[] i1) {
- int i0, i2, j, numDist = 0;
- int ind0, ind2;
- BBox bb;
- Distance old[] = null;
- boolean convex, coneOk;
-
- // sort the points according to their distance from start.
- ind1[0] = ind;
- i1[0] = i;
- if (i1[0] == start) return true;
- if (numDist >= triRef.maxNumDist) {
- // System.out.println("(1) Expanding distances array ...");
- triRef.maxNumDist += triRef.INC_DIST_BK;
- old = triRef.distances;
- triRef.distances = new Distance[triRef.maxNumDist];
- System.arraycopy(old, 0, triRef.distances, 0, old.length);
- for (int k = old.length; k < triRef.maxNumDist; k++)
- triRef.distances[k] = new Distance();
- }
-
- triRef.distances[numDist].dist = Numerics.baseLength(triRef.points[start],
- triRef.points[i1[0]]);
- triRef.distances[numDist].ind = ind1[0];
- ++numDist;
-
-
- ind1[0] = triRef.fetchNextData(ind1[0]);
- i1[0] = triRef.fetchData(ind1[0]);
- while (ind1[0] != ind) {
- if (i1[0] == start) return true;
- if (numDist >= triRef.maxNumDist) {
- // System.out.println("(2) Expanding distances array ...");
- triRef.maxNumDist += triRef.INC_DIST_BK;
- old = triRef.distances;
- triRef.distances = new Distance[triRef.maxNumDist];
- System.arraycopy(old, 0, triRef.distances, 0, old.length);
- for (int k = old.length; k < triRef.maxNumDist; k++)
- triRef.distances[k] = new Distance();
- }
-
- triRef.distances[numDist].dist = Numerics.baseLength(triRef.points[start],
- triRef.points[i1[0]]);
- triRef.distances[numDist].ind = ind1[0];
- ++numDist;
- ind1[0] = triRef.fetchNextData(ind1[0]);
- i1[0] = triRef.fetchData(ind1[0]);
- }
-
- // qsort(distances, num_dist, sizeof(distance), &d_comp);
- sortDistance(triRef.distances, numDist);
-
- // find a valid diagonal. note that no node with index i1 > start can
- // be feasible!
- for (j = 0; j < numDist; ++j) {
- ind1[0] = triRef.distances[j].ind;
- i1[0] = triRef.fetchData(ind1[0]);
- if (i1[0] <= start) {
- ind0 = triRef.fetchPrevData(ind1[0]);
- i0 = triRef.fetchData(ind0);
- ind2 = triRef.fetchNextData(ind1[0]);
- i2 = triRef.fetchData(ind2);
- convex = triRef.getAngle(ind1[0]) > 0;
-
- coneOk = Numerics.isInCone(triRef, i0, i1[0], i2, start, convex);
- if (coneOk) {
- bb = new BBox(triRef, i1[0], start);
- if (!NoHash.noHashEdgeIntersectionExists(triRef, bb, -1, -1, ind1[0], -1))
- return true;
- }
- }
- }
-
- // the left-most point of the hole does not lie within the outer
- // boundary! what is the best bridge in this case??? I make a
- // brute-force decision... perhaps this should be refined during a
- // revision of the code...
- for (j = 0; j < numDist; ++j) {
- ind1[0] = triRef.distances[j].ind;
- i1[0] = triRef.fetchData(ind1[0]);
- ind0 = triRef.fetchPrevData(ind1[0]);
- i0 = triRef.fetchData(ind0);
- ind2 = triRef.fetchNextData(ind1[0]);
- i2 = triRef.fetchData(ind2);
- bb = new BBox(triRef, i1[0], start);
- if (!NoHash.noHashEdgeIntersectionExists(triRef, bb, -1, -1, ind1[0], -1))
- return true;
- }
-
- // still no diagonal??? yikes! oh well, this polygon is messed up badly!
- ind1[0] = ind;
- i1[0] = i;
-
- return false;
- }
-
-
- static void findLeftMostVertex(Triangulator triRef, int ind, int[] leftInd,
- int[] leftI) {
- int ind1, i1;
-
- ind1 = ind;
- i1 = triRef.fetchData(ind1);
- leftInd[0] = ind1;
- leftI[0] = i1;
- ind1 = triRef.fetchNextData(ind1);
- i1 = triRef.fetchData(ind1);
- while (ind1 != ind) {
- if (i1 < leftI[0]) {
- leftInd[0] = ind1;
- leftI[0] = i1;
- }
- else if (i1 == leftI[0]) {
- if (triRef.getAngle(ind1) < 0) {
- leftInd[0] = ind1;
- leftI[0] = i1;
- }
- }
- ind1 = triRef.fetchNextData(ind1);
- i1 = triRef.fetchData(ind1);
- }
-
- }
-
- static void simpleBridge(Triangulator triRef, int ind1, int ind2) {
- int prev, next;
- int i1, i2, prv, nxt;
- int angle;
-
-
- // change the links
- triRef.rotateLinks(ind1, ind2);
-
- // reset the angles
- i1 = triRef.fetchData(ind1);
- next = triRef.fetchNextData(ind1);
- nxt = triRef.fetchData(next);
- prev = triRef.fetchPrevData(ind1);
- prv = triRef.fetchData(prev);
- angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind1);
- triRef.setAngle(ind1, angle);
-
- i2 = triRef.fetchData(ind2);
- next = triRef.fetchNextData(ind2);
- nxt = triRef.fetchData(next);
- prev = triRef.fetchPrevData(ind2);
- prv = triRef.fetchData(prev);
- angle = Numerics.isConvexAngle(triRef, prv, i2, nxt, ind2);
- triRef.setAngle(ind2, angle);
-
- }
-
-
- static void insertBridge(Triangulator triRef, int ind1, int i1,
- int ind3, int i3) {
- int ind2, ind4, prev, next;
- int prv, nxt, angle;
- int vcntIndex;
-
- // duplicate nodes in order to form end points of the bridge edges
- ind2 = triRef.makeNode(i1);
- triRef.insertAfter(ind1, ind2);
-
- // Need to get the original data, before setting it.
-
- vcntIndex = triRef.list[ind1].getCommonIndex();
-
- triRef.list[ind2].setCommonIndex(vcntIndex);
-
-
- ind4 = triRef.makeNode(i3);
- triRef.insertAfter(ind3, ind4);
-
- vcntIndex = triRef.list[ind3].getCommonIndex();
- triRef.list[ind4].setCommonIndex(vcntIndex);
-
- // insert the bridge edges into the boundary loops
- triRef.splitSplice(ind1, ind2, ind3, ind4);
-
- // reset the angles
- next = triRef.fetchNextData(ind1);
- nxt = triRef.fetchData(next);
- prev = triRef.fetchPrevData(ind1);
- prv = triRef.fetchData(prev);
- angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind1);
- triRef.setAngle(ind1, angle);
-
- next = triRef.fetchNextData(ind2);
- nxt = triRef.fetchData(next);
- prev = triRef.fetchPrevData(ind2);
- prv = triRef.fetchData(prev);
- angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind2);
- triRef.setAngle(ind2, angle);
-
- next = triRef.fetchNextData(ind3);
- nxt = triRef.fetchData(next);
- prev = triRef.fetchPrevData(ind3);
- prv = triRef.fetchData(prev);
- angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind3);
- triRef.setAngle(ind3, angle);
-
- next = triRef.fetchNextData(ind4);
- nxt = triRef.fetchData(next);
- prev = triRef.fetchPrevData(ind4);
- prv = triRef.fetchData(prev);
- angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind4);
- triRef.setAngle(ind4, angle);
-
- }
-
-
- static int l_comp(Left a, Left b) {
- if (a.index < b.index) return -1;
- else if (a.index > b.index) return 1;
- else return 0;
- }
-
- static int d_comp(Distance a, Distance b) {
- if (a.dist < b.dist) return -1;
- else if (a.dist > b.dist) return 1;
- else return 0;
- }
-
-
- static void sortLeft(Left[] lefts, int numPts) {
- int i,j;
- Left swap = new Left();
-
- for (i = 0; i < numPts; i++){
- for (j = i + 1; j < numPts; j++){
- if (l_comp(lefts[i], lefts[j]) > 0){
- swap.copy(lefts[i]);
- lefts[i].copy(lefts[j]);
- lefts[j].copy(swap);
- }
- }
- }
- }
-
-
- static void sortDistance(Distance[] distances, int numPts) {
- int i,j;
- Distance swap = new Distance();
-
- for (i = 0; i < numPts; i++){
- for (j = i + 1; j < numPts; j++){
- if (d_comp(distances[i], distances[j]) > 0){
- swap.copy(distances[i]);
- distances[i].copy(distances[j]);
- distances[j].copy(swap);
- }
- }
- }
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Clean.java b/src/classes/share/com/sun/j3d/utils/geometry/Clean.java
deleted file mode 100644
index d4137df..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Clean.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-import javax.vecmath.Point2f;
-
-class Clean {
-
- static void initPUnsorted(Triangulator triRef, int number) {
- if (number > triRef.maxNumPUnsorted) {
- triRef.maxNumPUnsorted = number;
- triRef.pUnsorted = new Point2f[triRef.maxNumPUnsorted];
- for(int i = 0; igetShape
.
- *
- * @see Cone#getShape
- */
- public static final int BODY = 0;
-
- /**
- * Designates the end-cap of the cone. Used by getShape
.
- *
- * @see Cone#getShape
- */
- public static final int CAP = 1;
-
- /**
- * Constructs a default Cone of radius of 1.0 and height
- * of 2.0. Resolution defaults to 15 divisions along X and axis
- * and 1 along the Y axis. Normals are generated, texture
- * coordinates are not.
- */
- public Cone(){
- this(1.0f, 2.0f, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, null);
- }
-
- /**
- *
- * Constructs a default Cone of a given radius and height. Normals
- * are generated, texture coordinates are not.
- * @param radius Radius
- * @param height Height
- */
- public Cone (float radius, float height)
- {
- this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, null);
- }
-
- /**
- *
- * Constructs a default cone of a given radius, height,
- * and appearance. Normals are generated, texture coordinates are not.
- * @param radius Radius
- * @param height Height
- * @param ap Appearance
- *
- * @since Java 3D 1.2.1
- */
- public Cone (float radius, float height, Appearance ap)
- {
- this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, ap);
- }
-
- /**
- *
- * Constructs a default cone of a given radius, height,
- * primitive flags, and appearance.
- * @param radius Radius
- * @param height Height
- * @param primflags Primitive flags
- * @param ap Appearance
- */
- public Cone (float radius, float height, int primflags, Appearance ap)
- {
- this(radius, height, primflags, MID_REZ_DIV_X, MID_REZ_DIV_Y, ap);
- }
-
- /**
- * Obtains the Shape3D node associated with one of the parts of the
- * cone (the body or the cap). This allows users to modify the appearance
- * or geometry of individual parts.
- * @param partId The part to return (BODY or CAP).
- * @return The Shape3D object associated with the partId. If an
- * invalid partId is passed in, null is returned.
- */
- @Override
- public Shape3D getShape(int partId){
- if (partId > CAP || partId < BODY) return null;
- return (Shape3D)getChild(partId);
- }
-
-
- /**
- * Sets appearance of the cone. This will set each part of the
- * cone (cap & body) to the same appearance. To set each
- * part's appearance separately, use getShape(partId) to get the
- * individual shape and call shape.setAppearance(ap).
- */
- @Override
- public void setAppearance(Appearance ap){
- ((Shape3D)getChild(BODY)).setAppearance(ap);
- ((Shape3D)getChild(CAP)).setAppearance(ap);
- }
-
- /**
- * Gets the appearance of the specified part of the cone.
- *
- * @param partId identifier for a given subpart of the cone
- *
- * @return The appearance object associated with the partID. If an
- * invalid partId is passed in, null is returned.
- *
- * @since Java 3D 1.2.1
- */
- @Override
- public Appearance getAppearance(int partId) {
- if (partId > CAP || partId < BODY) return null;
- return getShape(partId).getAppearance();
- }
-
-
- /**
- * Constructs a customized Cone of a given radius, height, flags,
- * resolution (X and Y dimensions), and appearance. The
- * resolution is defined in terms of number of subdivisions
- * along the object's X axis (width) and Y axis (height). More divisions
- * lead to finer tesselated objects.
- * cloneTree
to duplicate the current node.
- * cloneNode
should be overridden by any user subclassed
- * objects. All subclasses must have their cloneNode
- * method consist of the following lines:
- *
- * @param forceDuplicate when set to
- * public Node cloneNode(boolean forceDuplicate) {
- * UserSubClass usc = new UserSubClass();
- * usc.duplicateNode(this, forceDuplicate);
- * return usc;
- * }
- *
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.
- *
- * @see Node#cloneTree
- * @see Node#duplicateNode
- * @see NodeComponent#setDuplicateOnCloneTree
- */
- @Override
- public Node cloneNode(boolean forceDuplicate) {
- Cone c = new Cone(radius, height, flags, xdivisions,
- ydivisions, getAppearance());
- c.duplicateNode(this, forceDuplicate);
- return c;
- }
-
- /**
- * 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.
- * 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
.
- *
- * @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.
- *
- * @see Node#cloneTree
- * @see Node#cloneNode
- * @see NodeComponent#setDuplicateOnCloneTree
- */
- @Override
- public void duplicateNode(Node originalNode, boolean forceDuplicate) {
- super.duplicateNode(originalNode, forceDuplicate);
- }
-
- /**
- * Returns the radius of the cone
- *
- * @since Java 3D 1.2.1
- */
- public float getRadius() {
- return radius;
- }
-
- /**
- * Returns the height of the cone
- *
- * @since Java 3D 1.2.1
- */
- public float getHeight() {
- return height;
- }
-
- /**
- * Returns the number divisions along the X direction
- *
- * @since Java 3D 1.2.1
- */
- public int getXdivisions() {
- return xdivisions;
- }
-
- /**
- * Returns the number of divisions along the height of the cone
- *
- * @since Java 3D 1.2.1
- */
- public int getYdivisions() {
- return ydivisions;
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Cylinder.java b/src/classes/share/com/sun/j3d/utils/geometry/Cylinder.java
deleted file mode 100644
index b40b27b..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Cylinder.java
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry;
-
-import javax.media.j3d.Appearance;
-import javax.media.j3d.Node;
-import javax.media.j3d.NodeComponent;
-import javax.media.j3d.Shape3D;
-
-/**
- * Cylinder is a geometry primitive defined with a radius and a height.
- * It is a capped cylinder centered at the origin with its central axis
- * aligned along the Y-axis.
- * getShape
.
- *
- * @see Cylinder#getShape
- */
- public static final int BODY = 0;
-
- /**
- * Designates the top end-cap of the cylinder.
- * Used by getShape
.
- *
- * @see Cylinder#getShape
- */
- public static final int TOP = 1;
-
- /**
- * Designates the bottom end-cap of the cylinder.
- * Used by getShape
.
- *
- * @see Cylinder#getShape
- */
- public static final int BOTTOM = 2;
-
- /**
- * Constructs a default cylinder of radius of 1.0 and height
- * of 2.0. Normals are generated by default, texture
- * coordinates are not. Resolution defaults to 15 divisions
- * along X axis and 1 along the Y axis.
- */
- public Cylinder() {
- this(1.0f, 2.0f, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, null);
- }
-
- /**
- * Constructs a default cylinder of a given radius and height.
- * Normals are generated by default, texture coordinates are not.
- * @param radius Radius
- * @param height Height
- */
- public Cylinder (float radius, float height) {
- this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y,
- null);
- }
-
- /**
- * Constructs a default cylinder of a given radius, height, and
- * appearance. Normals are generated by default, texture
- * coordinates are not.
- * @param radius Radius
- * @param height Height
- * @param ap Appearance
- */
- public Cylinder (float radius, float height, Appearance ap)
- {
- this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y,
- ap);
- }
-
- /**
- *
- * Constructs a default cylinder of a given radius, height,
- * primitive flags and appearance.
- * @param radius Radius
- * @param height Height
- * @param primflags Flags
- * @param ap Appearance
- */
- public Cylinder (float radius, float height, int primflags, Appearance ap)
- {
- this(radius, height, primflags, MID_REZ_DIV_X, MID_REZ_DIV_Y, ap);
- }
-
- /**
- * Obtains the Shape3D node associated with a given part of the cylinder.
- * This allows users to modify the appearance or geometry
- * of individual parts.
- * @param partId The part to return (BODY, TOP, or BOTTOM).
- * @return The Shape3D object associated with the partID. If an
- * invalid partId is passed in, null is returned.
- */
- @Override
- public Shape3D getShape(int partId){
- if (partId > BOTTOM || partId < BODY) return null;
- return (Shape3D)getChild(partId);
- }
-
- /** Sets appearance of the cylinder. This will set each part of the
- * cylinder (TOP,BOTTOM,BODY) to the same appearance. To set each
- * part's appearance separately, use getShape(partId) to get the
- * individual shape and call shape.setAppearance(ap).
- */
- @Override
- public void setAppearance(Appearance ap) {
- ((Shape3D)getChild(BODY)).setAppearance(ap);
- ((Shape3D)getChild(TOP)).setAppearance(ap);
- ((Shape3D)getChild(BOTTOM)).setAppearance(ap);
- }
-
- /**
- * Gets the appearance of the specified part of the cylinder.
- *
- * @param partId identifier for a given subpart of the cylinder
- *
- * @return The appearance object associated with the partID. If an
- * invalid partId is passed in, null is returned.
- *
- * @since Java 3D 1.2.1
- */
- @Override
- public Appearance getAppearance(int partId) {
- if (partId > BOTTOM || partId < BODY) return null;
- return getShape(partId).getAppearance();
- }
-
-
- /**
- * Constructs a customized cylinder of a given radius, height,
- * resolution (X and Y dimensions), and appearance. The
- * resolution is defined in terms of number of subdivisions
- * along the object's X axis (width) and Y axis (height). More divisions
- * lead to more finely tesselated objects.
- * @param radius Radius
- * @param height Height
- * @param xdivision Number of divisions along X direction.
- * @param ydivision Number of divisions along height of cylinder.
- * @param primflags Primitive flags.
- * @param ap Appearance
- */
- public Cylinder(float radius, float height, int primflags,
- int xdivision, int ydivision, Appearance ap) {
- super();
-
- this.radius = radius;
- this.height = height;
- this.xdivisions = xdivision;
- this.ydivisions = ydivision;
- flags = primflags;
- boolean outside = (flags & GENERATE_NORMALS_INWARD) == 0;
- boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0;
- // Create many body of the cylinder.
- Quadrics q = new Quadrics();
- GeomBuffer gbuf = null;
- Shape3D shape[] = new Shape3D[3];
-
- GeomBuffer cache = getCachedGeometry(Primitive.CYLINDER,
- (float)BODY, radius, height,
- xdivision, ydivision, primflags);
- if (cache != null){
-// System.out.println("using cached geometry");
- shape[BODY] = new Shape3D(cache.getComputedGeometry());
- numVerts += cache.getNumVerts();
- numTris += cache.getNumTris();
- }
- else {
- gbuf = q.cylinder((double)height, (double)radius,
- xdivision, ydivision, outside, texCoordYUp);
- shape[BODY] = new Shape3D(gbuf.getGeom(flags));
- numVerts += gbuf.getNumVerts();
- numTris += gbuf.getNumTris();
- if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0)
- cacheGeometry(Primitive.CYLINDER,
- (float)BODY, radius, height,
- xdivision, ydivision, primflags, gbuf);
- }
-
- if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
- (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
- (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
- }
-
- if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
- (shape[BODY]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
- }
-
- this.addChild(shape[BODY]);
-
- // Create top of cylinder
- cache = getCachedGeometry(Primitive.TOP_DISK, radius, radius,
- height/2.0f, xdivision, xdivision, primflags);
- if (cache != null) {
-// System.out.println("using cached top");
- shape[TOP] = new Shape3D(cache.getComputedGeometry());
- numVerts += cache.getNumVerts();
- numTris += cache.getNumTris();
- }
- else {
- gbuf = q.disk((double)radius, xdivision, height/2.0,
- outside, texCoordYUp);
- shape[TOP] = new Shape3D(gbuf.getGeom(flags));
- numVerts += gbuf.getNumVerts();
- numTris += gbuf.getNumTris();
- if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
- cacheGeometry(Primitive.TOP_DISK, radius, radius,
- height/2.0f, xdivision, xdivision,
- primflags, gbuf);
- }
- }
-
- if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
- (shape[TOP]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
- (shape[TOP]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
- }
-
- if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
- (shape[TOP]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
- }
-
- this.addChild(shape[TOP]);
-
- // Create bottom
- cache = getCachedGeometry(Primitive.BOTTOM_DISK, radius, radius,
- -height/2.0f, xdivision, xdivision,
- primflags);
- if (cache != null) {
-// System.out.println("using cached bottom");
- shape[BOTTOM] = new Shape3D(cache.getComputedGeometry());
- numVerts += cache.getNumVerts();
- numTris += cache.getNumTris();
- }
- else {
- gbuf = q.disk((double)radius, xdivision, -height/2.0, !outside, texCoordYUp);
- shape[BOTTOM] = new Shape3D(gbuf.getGeom(flags));
- numVerts += gbuf.getNumVerts();
- numTris += gbuf.getNumTris();
- if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
- cacheGeometry(Primitive.BOTTOM_DISK, radius, radius,
- -height/2.0f, xdivision, xdivision,
- primflags, gbuf);
- }
- }
-
- if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
- (shape[BOTTOM]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
- (shape[BOTTOM]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
- }
-
- if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
- (shape[BOTTOM]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
- }
-
- this.addChild(shape[BOTTOM]);
-
- // Set Appearance
- if (ap == null){
- setAppearance();
- }
- else setAppearance(ap);
- }
-
- /**
- * Used to create a new instance of the node. This routine is called
- * by cloneTree
to duplicate the current node.
- * cloneNode
should be overridden by any user subclassed
- * objects. All subclasses must have their cloneNode
- * method consist of the following lines:
- *
- * @param forceDuplicate when set to
- * public Node cloneNode(boolean forceDuplicate) {
- * UserSubClass usc = new UserSubClass();
- * usc.duplicateNode(this, forceDuplicate);
- * return usc;
- * }
- *
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.
- *
- * @see Node#cloneTree
- * @see Node#duplicateNode
- * @see NodeComponent#setDuplicateOnCloneTree
- */
- @Override
- public Node cloneNode(boolean forceDuplicate) {
- Cylinder c = new Cylinder(radius, height, flags, xdivisions,
- ydivisions, getAppearance());
- c.duplicateNode(this, forceDuplicate);
- return c;
- }
-
- /**
- * 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.
- * 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
.
- *
- * @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.
- *
- * @see Node#cloneTree
- * @see Node#cloneNode
- * @see NodeComponent#setDuplicateOnCloneTree
- */
- @Override
- public void duplicateNode(Node originalNode, boolean forceDuplicate) {
- super.duplicateNode(originalNode, forceDuplicate);
- }
-
- /**
- * Returns the radius of the cylinder
- *
- * @since Java 3D 1.2.1
- */
- public float getRadius() {
- return radius;
- }
-
- /**
- * Returns the height of the cylinder
- *
- * @since Java 3D 1.2.1
- */
- public float getHeight() {
- return height;
- }
-
- /**
- * Returns the number divisions along the X direction
- *
- * @since Java 3D 1.2.1
- */
- public int getXdivisions() {
- return xdivisions;
- }
-
- /**
- * Returns the number of divisions along the height of the cylinder
- *
- * @since Java 3D 1.2.1
- */
- public int getYdivisions() {
- return ydivisions;
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Degenerate.java b/src/classes/share/com/sun/j3d/utils/geometry/Degenerate.java
deleted file mode 100644
index 960437f..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Degenerate.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-
-class Degenerate {
-
- /**
- * This function checks whether the triangle i1, i2, i3 is an ear, where
- * the vertex i4 lies on at least one of the two edges i1, i2 or i3, i1.
- * basically, we can cut the polygon at i4 into two pieces. the polygon
- * touches at i4 back to back if following the next-pointers in one
- * subpolygon and following the prev-pointers in the other subpolygon yields
- * the same orientation for both subpolygons. otherwise, i4 forms a
- * bottle neck of the polygon, and i1, i2, i3 is no valid ear.
- *
- * Note that this function may come up with the incorrect answer if the
- * polygon has self-intersections.
- */
- static boolean handleDegeneracies(Triangulator triRef, int i1, int ind1, int i2,
- int i3, int i4, int ind4) {
- int i0, i5;
- int type[] = new int[1];
- int ind0, ind2, ind5;
- boolean flag;
- double area = 0.0, area1 = 0, area2 = 0.0;
-
- /* assert(InPointsList(i1));
- assert(InPointsList(i2));
- assert(InPointsList(i3));
- assert(InPointsList(i4));
- */
-
- // first check whether the successor or predecessor of i4 is inside the
- // triangle, or whether any of the two edges incident at i4 intersects
- // i2, i3.
- ind5 = triRef.fetchPrevData(ind4);
- i5 = triRef.fetchData(ind5);
-
- // assert(ind4 != ind5);
- //assert(InPointsList(i5));
- if ((i5 != i2) && (i5 != i3)) {
- flag = Numerics.vtxInTriangle(triRef, i1, i2, i3, i5, type);
- if (flag && (type[0] == 0)) return true;
- if (i2 <= i3) {
- if (i4 <= i5)
- flag = Numerics.segIntersect(triRef, i2, i3, i4, i5, -1);
- else
- flag = Numerics.segIntersect(triRef, i2, i3, i5, i4, -1);
- }
- else {
- if (i4 <= i5)
- flag = Numerics.segIntersect(triRef, i3, i2, i4, i5, -1);
- else
- flag = Numerics.segIntersect(triRef, i3, i2, i5, i4, -1);
- }
- if (flag)
- return true;
- }
-
- ind5 = triRef.fetchNextData(ind4);
- i5 = triRef.fetchData(ind5);
- // assert(ind4 != ind5);
- // assert(InPointsList(i5));
- if ((i5 != i2) && (i5 != i3)) {
- flag = Numerics.vtxInTriangle(triRef, i1, i2, i3, i5, type);
- if (flag && (type[0] == 0)) return true;
- if (i2 <= i3) {
- if (i4 <= i5) flag = Numerics.segIntersect(triRef, i2, i3, i4, i5, -1);
- else flag = Numerics.segIntersect(triRef, i2, i3, i5, i4, -1);
- }
- else {
- if (i4 <= i5) flag = Numerics.segIntersect(triRef, i3, i2, i4, i5, -1);
- else flag = Numerics.segIntersect(triRef, i3, i2, i5, i4, -1);
- }
- if (flag) return true;
- }
-
- i0 = i1;
- ind0 = ind1;
- ind1 = triRef.fetchNextData(ind1);
- i1 = triRef.fetchData(ind1);
- while (ind1 != ind4) {
- ind2 = triRef.fetchNextData(ind1);
- i2 = triRef.fetchData(ind2);
- area = Numerics.stableDet2D(triRef, i0, i1, i2);
- area1 += area;
- ind1 = ind2;
- i1 = i2;
- }
-
- ind1 = triRef.fetchPrevData(ind0);
- i1 = triRef.fetchData(ind1);
- while (ind1 != ind4) {
- ind2 = triRef.fetchPrevData(ind1);
- i2 = triRef.fetchData(ind2);
- area = Numerics.stableDet2D(triRef, i0, i1, i2);
- area2 += area;
- ind1 = ind2;
- i1 = i2;
- }
-
- if (Numerics.le(area1, triRef.ZERO) && Numerics.le(area2, triRef.ZERO))
- return false;
- else if (Numerics.ge(area1, triRef.ZERO) && Numerics.ge(area2, triRef.ZERO))
- return false;
- else
- return true;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Desperate.java b/src/classes/share/com/sun/j3d/utils/geometry/Desperate.java
deleted file mode 100644
index 4bbcc66..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Desperate.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-import javax.vecmath.Point2f;
-
-class Desperate {
-
- /**
- * the functions in this file try to ensure that we always end up with
- * something that (topologically) is a triangulation.
- *
- * the more desperate we get, the more aggressive means we choose for making
- * diagonals "valid".
- */
- static boolean desperate(Triangulator triRef, int ind, int i, boolean[] splitted) {
- int[] i1 = new int[1];
- int[] i2 = new int[1];
- int[] i3 = new int[1];
- int[] i4 = new int[1];
- int[] ind1 = new int[1];
- int[] ind2 = new int[1];
- int[] ind3 = new int[1];
- int[] ind4 = new int[1];
-
- splitted[0] = false;
-
- // check whether there exist consecutive vertices i1, i2, i3, i4 such
- // that i1, i2 and i3, i4 intersect
- if (existsCrossOver(triRef, ind, ind1, i1, ind2, i2, ind3, i3, ind4, i4)) {
- // insert two new diagonals around the cross-over without checking
- // whether they are intersection-free
- handleCrossOver(triRef, ind1[0], i1[0], ind2[0], i2[0], ind3[0], i3[0],
- ind4[0], i4[0]);
- return false;
- }
-
- NoHash.prepareNoHashEdges(triRef, i, i+1);
-
- // check whether there exists a valid diagonal that splits the polygon
- // into two parts
- if (existsSplit(triRef, ind, ind1, i1, ind2, i2)) {
- // break up the polygon by inserting this diagonal (which can't be an
- // ear -- otherwise, we would not have ended up in this part of the
- // code). then, let's treat the two polygons separately. hopefully,
- // this will help to handle self-overlapping polygons in the "correct"
- // way.
- handleSplit(triRef, ind1[0], i1[0], ind2[0], i2[0]);
- splitted[0] = true;
- return false;
- }
-
- return true;
- }
-
-
- static boolean existsCrossOver(Triangulator triRef, int ind, int[] ind1, int[] i1,
- int[] ind2, int[] i2, int[] ind3, int[] i3,
- int[] ind4, int[] i4) {
- BBox bb1, bb2;
-
- ind1[0] = ind;
- i1[0] = triRef.fetchData(ind1[0]);
- ind2[0] = triRef.fetchNextData(ind1[0]);
- i2[0] = triRef.fetchData(ind2[0]);
- ind3[0] = triRef.fetchNextData(ind2[0]);
- i3[0] = triRef.fetchData(ind3[0]);
- ind4[0] = triRef.fetchNextData(ind3[0]);
- i4[0] = triRef.fetchData(ind4[0]);
-
- do {
- bb1 = new BBox(triRef, i1[0], i2[0]);
- bb2 = new BBox(triRef, i3[0], i4[0]);
- if (bb1.BBoxOverlap(bb2)) {
- if (Numerics.segIntersect(triRef, bb1.imin, bb1.imax, bb2.imin, bb2.imax, -1))
- return true;
- }
- ind1[0] = ind2[0];
- i1[0] = i2[0];
- ind2[0] = ind3[0];
- i2[0] = i3[0];
- ind3[0] = ind4[0];
- i3[0] = i4[0];
- ind4[0] = triRef.fetchNextData(ind3[0]);
- i4[0] = triRef.fetchData(ind4[0]);
-
- } while (ind1[0] != ind);
-
- return false;
- }
-
-
- static void handleCrossOver(Triangulator triRef, int ind1, int i1, int ind2,
- int i2, int ind3, int i3, int ind4, int i4) {
- double ratio1, ratio4;
- boolean first;
- int angle1, angle4;
-
- // which pair of triangles shall I insert?? we can use either i1, i2, i3
- // and i1, i3, i4, or we can use i2, i3, i4 and i1, i2, i4...
- angle1 = triRef.getAngle(ind1);
- angle4 = triRef.getAngle(ind4);
- if (angle1 < angle4) first = true;
- else if (angle1 > angle4) first = false;
- else if (triRef.earsSorted) {
- ratio1 = Numerics.getRatio(triRef, i3, i4, i1);
- ratio4 = Numerics.getRatio(triRef, i1, i2, i4);
- if (ratio4 < ratio1) first = false;
- else first = true;
- }
- else {
- first = true;
- }
-
- if (first) {
- // first clip i1, i2, i3, then clip i1, i3, i4
- triRef.deleteLinks(ind2);
- // StoreTriangle(GetOriginal(ind1), GetOriginal(ind2), GetOriginal(ind3));
- triRef.storeTriangle(ind1, ind2, ind3);
- triRef.setAngle(ind3, 1);
- Heap.insertIntoHeap(triRef, 0.0, ind3, ind1, ind4);
- }
- else {
- // first clip i2, i3, i4, then clip i1, i2, i4
- triRef.deleteLinks(ind3);
- //StoreTriangle(GetOriginal(ind2), GetOriginal(ind3), GetOriginal(ind4));
- triRef.storeTriangle(ind2, ind3, ind4);
- triRef.setAngle(ind2, 1);
- Heap.insertIntoHeap(triRef, 0.0, ind2, ind1, ind4);
- }
- }
-
-
- static boolean letsHope(Triangulator triRef, int ind) {
- int ind0, ind1, ind2;
- int i0, i1, i2;
-
- // let's clip the first convex corner. of course, we know that this is no
- // ear in an ideal world. but this polygon isn't ideal, either!
- ind1 = ind;
- i1 = triRef.fetchData(ind1);
-
- do {
- if (triRef.getAngle(ind1) > 0) {
- ind0 = triRef.fetchPrevData(ind1);
- i0 = triRef.fetchData(ind0);
- ind2 = triRef.fetchNextData(ind1);
- i2 = triRef.fetchData(ind2);
- Heap.insertIntoHeap(triRef, 0.0, ind1, ind0, ind2);
- return true;
- }
- ind1 = triRef.fetchNextData(ind1);
- i1 = triRef.fetchData(ind1);
- } while (ind1 != ind);
-
- // no convex corners? so, let's cheat! this code won't stop without some
- // triangulation... ;-) g-i-g-o? right! perhaps, this is what you
- // call a robust code?!
- triRef.setAngle(ind, 1);
- ind0 = triRef.fetchPrevData(ind);
- i0 = triRef.fetchData(ind0);
- ind2 = triRef.fetchNextData(ind);
- i2 = triRef.fetchData(ind2);
- Heap.insertIntoHeap(triRef, 0.0, ind, ind0, ind2);
- i1 = triRef.fetchData(ind);
-
- return true;
-
- // see, we never have to return "false"...
- /*
- return false;
- */
- }
-
-
- static boolean existsSplit(Triangulator triRef, int ind, int[] ind1, int[] i1,
- int[] ind2, int[] i2) {
- int ind3, ind4, ind5;
- int i3, i4, i5;
-
- if (triRef.numPoints > triRef.maxNumDist) {
- // System.out.println("Desperate: Expanding distances array ...");
- triRef.maxNumDist = triRef.numPoints;
- triRef.distances = new Distance[triRef.maxNumDist];
- for (int k = 0; k < triRef.maxNumDist; k++)
- triRef.distances[k] = new Distance();
- }
- ind1[0] = ind;
- i1[0] = triRef.fetchData(ind1[0]);
- ind4 = triRef.fetchNextData(ind1[0]);
- i4 = triRef.fetchData(ind4);
- // assert(*ind1 != ind4);
- ind5 = triRef.fetchNextData(ind4);
- i5 = triRef.fetchData(ind5);
- // assert(*ind1 != *ind2);
- ind3 = triRef.fetchPrevData(ind1[0]);
- i3 = triRef.fetchData(ind3);
- // assert(*ind2 != ind3);
- if (foundSplit(triRef, ind5, i5, ind3, ind1[0], i1[0], i3, i4, ind2, i2))
- return true;
- i3 = i1[0];
- ind1[0] = ind4;
- i1[0] = i4;
- ind4 = ind5;
- i4 = i5;
- ind5 = triRef.fetchNextData(ind4);
- i5 = triRef.fetchData(ind5);
-
- while (ind5 != ind) {
- if (foundSplit(triRef, ind5, i5, ind, ind1[0], i1[0], i3, i4, ind2, i2))
- return true;
- i3 = i1[0];
- ind1[0] = ind4;
- i1[0] = i4;
- ind4 = ind5;
- i4 = i5;
- ind5 = triRef.fetchNextData(ind4);
- i5 = triRef.fetchData(ind5);
- }
-
- return false;
- }
-
-
- /**
- * This function computes the winding number of a polygon with respect to a
- * point p. no care is taken to handle cases where p lies on the
- * boundary of the polygon. (this is no issue in our application, as we will
- * always compute the winding number with respect to the mid-point of a
- * valid diagonal.)
- */
- static int windingNumber(Triangulator triRef, int ind, Point2f p) {
- double angle;
- int ind2;
- int i1, i2, number;
-
- i1 = triRef.fetchData(ind);
- ind2 = triRef.fetchNextData(ind);
- i2 = triRef.fetchData(ind2);
- angle = Numerics.angle(triRef, p, triRef.points[i1], triRef.points[i2]);
- while (ind2 != ind) {
- i1 = i2;
- ind2 = triRef.fetchNextData(ind2);
- i2 = triRef.fetchData(ind2);
- angle += Numerics.angle(triRef, p, triRef.points[i1], triRef.points[i2]);
- }
-
- angle += Math.PI;
- number = (int)(angle / (Math.PI*2.0));
-
- return number;
- }
-
-
-
-
- static boolean foundSplit(Triangulator triRef, int ind5, int i5, int ind, int ind1,
- int i1, int i3, int i4, int[] ind2, int[] i2) {
- Point2f center;
- int numDist = 0;
- int j, i6, i7;
- int ind6, ind7;
- BBox bb;
- boolean convex, coneOk;
-
- // Sort the points according to their distance from i1
- do {
- // assert(numDist < triRef.maxNumDist);
- triRef.distances[numDist].dist = Numerics.baseLength(triRef.points[i1],
- triRef.points[i5]);
- triRef.distances[numDist].ind = ind5;
- ++numDist;
- ind5 = triRef.fetchNextData(ind5);
- i5 = triRef.fetchData(ind5);
- } while (ind5 != ind);
-
- Bridge.sortDistance(triRef.distances, numDist);
-
- // find a valid diagonal.
- for (j = 0; j < numDist; ++j) {
- ind2[0] = triRef.distances[j].ind;
- i2[0] = triRef.fetchData(ind2[0]);
- if (i1 != i2[0]) {
- ind6 = triRef.fetchPrevData(ind2[0]);
- i6 = triRef.fetchData(ind6);
- ind7 = triRef.fetchNextData(ind2[0]);
- i7 = triRef.fetchData(ind7);
-
- convex = triRef.getAngle(ind2[0]) > 0;
- coneOk = Numerics.isInCone(triRef, i6, i2[0], i7, i1, convex);
- if (coneOk) {
- convex = triRef.getAngle(ind1) > 0;
- coneOk = Numerics.isInCone(triRef, i3, i1, i4, i2[0], convex);
- if (coneOk) {
- bb = new BBox(triRef, i1, i2[0]);
- if (!NoHash.noHashEdgeIntersectionExists(triRef, bb, -1, -1, ind1, -1)) {
- // check whether this is a good diagonal; we do not want a
- // diagonal that may create figure-8's!
- center = new Point2f();
- Basic.vectorAdd2D(triRef.points[i1], triRef.points[i2[0]], center);
- Basic.multScalar2D(0.5, center);
- if (windingNumber(triRef, ind, center) == 1) return true;
- }
- }
- }
- }
- }
-
- return false;
- }
-
-
- static void handleSplit(Triangulator triRef, int ind1, int i1, int ind3, int i3) {
- int ind2, ind4, prev, next;
- int prv, nxt, angle;
- int vIndex, comIndex = -1;
-
- // duplicate nodes in order to form end points of the new diagonal
- ind2 = triRef.makeNode(i1);
- triRef.insertAfter(ind1, ind2);
-
- // Need to get the original data, before setting it.
-
- comIndex = triRef.list[ind1].getCommonIndex();
-
- triRef.list[ind2].setCommonIndex(comIndex);
-
- ind4 = triRef.makeNode(i3);
- triRef.insertAfter(ind3, ind4);
-
- comIndex = triRef.list[ind3].getCommonIndex();
- triRef.list[ind4].setCommonIndex(comIndex);
-
- // insert the diagonal into the boundary loop, thus splitting the loop
- // into two loops
- triRef.splitSplice(ind1, ind2, ind3, ind4);
-
- // store pointers to the two new loops
- triRef.storeChain(ind1);
- triRef.storeChain(ind3);
-
- // reset the angles
- next = triRef.fetchNextData(ind1);
- nxt = triRef.fetchData(next);
- prev = triRef.fetchPrevData(ind1);
- prv = triRef.fetchData(prev);
- angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind1);
- triRef.setAngle(ind1, angle);
-
- next = triRef.fetchNextData(ind2);
- nxt = triRef.fetchData(next);
- prev = triRef.fetchPrevData(ind2);
- prv = triRef.fetchData(prev);
- angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind2);
- triRef.setAngle(ind2, angle);
-
- next = triRef.fetchNextData(ind3);
- nxt = triRef.fetchData(next);
- prev = triRef.fetchPrevData(ind3);
- prv = triRef.fetchData(prev);
- angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind3);
- triRef.setAngle(ind3, angle);
-
- next = triRef.fetchNextData(ind4);
- nxt = triRef.fetchData(next);
- prev = triRef.fetchPrevData(ind4);
- prv = triRef.fetchData(prev);
- angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind4);
- triRef.setAngle(ind4, angle);
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Distance.java b/src/classes/share/com/sun/j3d/utils/geometry/Distance.java
deleted file mode 100644
index be3d3d1..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Distance.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-class Distance extends Object {
- int ind;
- double dist;
-
- Distance() {
- }
-
- void copy(Distance d) {
- ind = d.ind;
- dist = d.dist;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/EarClip.java b/src/classes/share/com/sun/j3d/utils/geometry/EarClip.java
deleted file mode 100644
index d7be619..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/EarClip.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-
-class EarClip {
-
- /**
- * Classifies all the internal angles of the loop referenced by ind.
- * the following classification is used:
- * 0 ... if angle is 180 degrees
- * 1 ... if angle between 0 and 180 degrees
- * 2 ... if angle is 0 degrees
- * -1 ... if angle between 180 and 360 degrees
- * -2 ... if angle is 360 degrees
- */
- static void classifyAngles(Triangulator triRef, int ind) {
- int ind0, ind1, ind2;
- int i0, i1, i2;
- int angle;
-
- ind1 = ind;
- i1 = triRef.fetchData(ind1);
- ind0 = triRef.fetchPrevData(ind1);
- i0 = triRef.fetchData(ind0);
-
- do {
- ind2 = triRef.fetchNextData(ind1);
- i2 = triRef.fetchData(ind2);
- angle = Numerics.isConvexAngle(triRef, i0, i1, i2, ind1);
- triRef.setAngle(ind1, angle);
- i0 = i1;
- i1 = i2;
- ind1 = ind2;
- } while (ind1 != ind);
-
- }
-
-
- static void classifyEars(Triangulator triRef, int ind) {
- int ind1;
- int i1;
- int[] ind0, ind2;
- double[] ratio;
-
- ind0 = new int[1];
- ind2 = new int[1];
- ratio = new double[1];
-
- Heap.initHeap(triRef);
-
- ind1 = ind;
- i1 = triRef.fetchData(ind1);
-
- do {
- if ((triRef.getAngle(ind1) > 0) &&
- isEar(triRef, ind1, ind0, ind2, ratio)) {
-
- Heap.dumpOnHeap(triRef, ratio[0], ind1, ind0[0], ind2[0]);
- }
- ind1 = triRef.fetchNextData(ind1);
- i1 = triRef.fetchData(ind1);
- } while (ind1 != ind);
-
- // Not using sorted_ear so don't have to do MakeHeap();
- // MakeHeap();
-
- // Heap.printHeapData(triRef);
-
- }
-
-
- /**
- * This function checks whether a diagonal is valid, that is, whether it is
- * locally within the polygon, and whether it does not intersect any other
- * segment of the polygon. also, some degenerate cases get a special
- * handling.
- */
- static boolean isEar(Triangulator triRef, int ind2, int[] ind1, int[] ind3,
- double[] ratio) {
- int i0, i1, i2, i3, i4;
- int ind0, ind4;
- BBox bb;
- boolean convex, coneOk;
-
- i2 = triRef.fetchData(ind2);
- ind3[0] = triRef.fetchNextData(ind2);
- i3 = triRef.fetchData(ind3[0]);
- ind4 = triRef.fetchNextData(ind3[0]);
- i4 = triRef.fetchData(ind4);
- ind1[0] = triRef.fetchPrevData(ind2);
- i1 = triRef.fetchData(ind1[0]);
- ind0 = triRef.fetchPrevData(ind1[0]);
- i0 = triRef.fetchData(ind0);
-
- /*
- System.out.println("isEar : i0 " + i0 + " i1 " + i1 + " i2 " + i2 +
- " i3 " + i3 + " i4 " + i4);
- */
-
- if ((i1 == i3) || (i1 == i2) || (i2 == i3) || (triRef.getAngle(ind2) == 2)) {
- // oops, this is not a simple polygon!
- ratio[0] = 0.0;
- return true;
- }
-
- if (i0 == i3) {
- // again, this is not a simple polygon!
- if ((triRef.getAngle(ind0) < 0) || (triRef.getAngle(ind3[0]) < 0)) {
- ratio[0] = 0.0;
- return true;
- }
- else
- return false;
- }
-
- if (i1 == i4) {
- // again, this is not a simple polygon!
- if ((triRef.getAngle(ind1[0]) < 0) || (triRef.getAngle(ind4) < 0)) {
- ratio[0] = 0.0;
- return true;
- }
- else
- return false;
- }
-
- // check whether the new diagonal i1, i3 locally is within the polygon
- convex = triRef.getAngle(ind1[0]) > 0;
- coneOk = Numerics.isInCone(triRef, i0, i1, i2, i3, convex);
- // System.out.println("isEar :(1) convex " + convex + " coneOk " + coneOk );
-
- if (!coneOk) return false;
- convex = triRef.getAngle(ind3[0]) > 0;
- coneOk = Numerics.isInCone(triRef, i2, i3, i4, i1, convex);
- // System.out.println("isEar :(2) convex " + convex + " coneOk " + coneOk );
-
- if (coneOk) {
- // check whether this diagonal is a valid diagonal. this translates to
- // checking either condition CE1 or CE2 (see my paper). If CE1 is to
- // to be checked, then we use a BV-tree or a grid. Otherwise, we use
- // "buckets" (i.e., a grid) or no hashing at all.
- bb = new BBox(triRef, i1, i3);
- // use CE2 + no_hashing
- if(!NoHash.noHashIntersectionExists(triRef, i2, ind2, i3, i1, bb)) {
- if (triRef.earsSorted) {
- // determine the quality of the triangle
- ratio[0] = Numerics.getRatio(triRef, i1, i3, i2);
- }
- else {
- ratio[0] = 1.0;
- }
- return true;
- }
- }
-
- // System.out.println("isEar : false");
- return false;
- }
-
-
-
- /**
- * This is the main function that drives the ear-clipping. it obtains an ear
- * from set of ears maintained in a priority queue, clips this ear, and
- * updates all data structures appropriately. (ears are arranged in the
- * priority queue (i.e., heap) according to a quality criterion that tries
- * to avoid skinny triangles.)
- */
- static boolean clipEar(Triangulator triRef, boolean[] done) {
-
- int ind0, ind1, ind3, ind4;
-
- int i0, i1, i2, i3, i4;
- int angle1, angle3;
-
- double ratio[] = new double[1];
- int index0[] = new int[1];
- int index1[] = new int[1];
- int index2[] = new int[1];
- int index3[] = new int[1];
- int index4[] = new int[1];
- int ind2[] = new int[1];
-
- int testCnt = 0;
-
- // Heap.printHeapData(triRef);
-
- do {
-
- // System.out.println("In clipEarloop " + testCnt++);
-
- if (!Heap.deleteFromHeap(triRef, ind2, index1, index3))
- // no ear exists?!
- return false;
-
- // get the successors and predecessors in the list of nodes and check
- // whether the ear still is part of the boundary
- ind1 = triRef.fetchPrevData(ind2[0]);
- i1 = triRef.fetchData(ind1);
- ind3 = triRef.fetchNextData(ind2[0]);
- i3 = triRef.fetchData(ind3);
-
- } while ((index1[0] != ind1) || (index3[0] != ind3));
-
- //System.out.println("Out of clipEarloop ");
-
- i2 = triRef.fetchData(ind2[0]);
-
- // delete the clipped ear from the list of nodes, and update the bv-tree
- triRef.deleteLinks(ind2[0]);
-
- // store the ear in a list of ears which have already been clipped
- // StoreTriangle(GetOriginal(ind1), GetOriginal(ind2), GetOriginal(ind3));
- triRef.storeTriangle(ind1, ind2[0], ind3);
-
- /* */
- /* update the angle classification at ind1 and ind3 */
- /* */
- ind0 = triRef.fetchPrevData(ind1);
- i0 = triRef.fetchData(ind0);
- if (ind0 == ind3) {
- // nothing left
- done[0] = true;
- return true;
- }
- angle1 = Numerics.isConvexAngle(triRef, i0, i1, i3, ind1);
-
- ind4 = triRef.fetchNextData(ind3);
- i4 = triRef.fetchData(ind4);
-
- angle3 = Numerics.isConvexAngle(triRef, i1, i3, i4, ind3);
-
- if (i1 != i3) {
- if ((angle1 >= 0) && (triRef.getAngle(ind1) < 0))
- NoHash.deleteReflexVertex(triRef, ind1);
- if ((angle3 >= 0) && (triRef.getAngle(ind3) < 0))
- NoHash.deleteReflexVertex(triRef, ind3);
- }
- else {
- if ((angle1 >= 0) && (triRef.getAngle(ind1) < 0))
- NoHash.deleteReflexVertex(triRef, ind1);
- else if ((angle3 >= 0) && (triRef.getAngle(ind3) < 0))
- NoHash.deleteReflexVertex(triRef, ind3);
-
- }
-
- triRef.setAngle(ind1, angle1);
- triRef.setAngle(ind3, angle3);
-
- // check whether either of ind1 and ind3 is an ear. (the "ratio" is
- // the length of the triangle's longest side divided by the length of the
- // height normal onto this side; it is used as a quality criterion.)
- if (angle1 > 0) {
- if (isEar(triRef, ind1, index0, index2, ratio)) {
- // insert the new ear into the priority queue of ears
- Heap.insertIntoHeap(triRef, ratio[0], ind1, index0[0], index2[0]);
- }
- }
-
- if (angle3 > 0) {
- if(isEar(triRef, ind3, index2, index4, ratio)) {
- Heap.insertIntoHeap(triRef, ratio[0], ind3, index2[0], index4[0]);
- }
- }
-
- // check whether the triangulation is finished.
- ind0 = triRef.fetchPrevData(ind1);
- i0 = triRef.fetchData(ind0);
- ind4 = triRef.fetchNextData(ind3);
- i4 = triRef.fetchData(ind4);
- if (ind0 == ind4) {
- // only one triangle left -- clip it!
- triRef.storeTriangle(ind1, ind3, ind4);
- done[0] = true;
- }
- else {
- done[0] = false;
- }
-
- return true;
- }
-
-}
-
-
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Edge.java b/src/classes/share/com/sun/j3d/utils/geometry/Edge.java
deleted file mode 100644
index 1841a0e..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Edge.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry;
-
-// Class created so that the two vertex indices that make up an
-// edge can be hashed.
-class Edge {
-
- public int v1;
- public int v2;
- private static final int HASHCONST = 0xEDCBA987;
-
- @Override
- public int hashCode()
- {
- return ((v1 * HASHCONST) << 2) ^ (v2 * HASHCONST);
- } // end of Edge.hashCode
-
- @Override
- public boolean equals(Object x)
- {
- if (!(x instanceof Edge)) return false;
- Edge e = (Edge)x;
- return (v1 == e.v1) && (v2 == e.v2);
- } // End of Edge.equals
-
- @Override
- public String toString()
- {
- return "(" + v1 + ", " + v2 + ")";
- } // End of toString
-
- public Edge(int a, int b)
- {
- v1 = a;
- v2 = b;
- }
-
- public Edge(Edge e)
- {
- v1 = e.v1;
- v2 = e.v2;
- }
-
- public Edge()
- {
- }
-} // end of class Edge
-
-// End of file Edge.java
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/EdgeTable.java b/src/classes/share/com/sun/j3d/utils/geometry/EdgeTable.java
deleted file mode 100644
index 337f353..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/EdgeTable.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry;
-
-import java.util.HashMap;
-import java.util.Iterator;
-
-class EdgeTable {
-
- private HashMap edgeTable;
- private static final int DEBUG = 0;
-
-
-
- Integer get(int a, int b)
- {
- return (Integer)edgeTable.get(new Edge(a, b));
- } // End of get()
-
-
- Integer get(Edge e)
- {
- return (Integer)edgeTable.get(e);
- } // End of get()
-
-
-
- // This function creates a table used to connect the triangles.
- // Here's how it works. If a triangle is made of indices 12,
- // 40, and 51, then edge(12, 40) gets 51, edge(40, 51) gets 12,
- // and edge(51, 12) gets 40. This lets us quickly move from
- // triangle to triangle without saving a lot of extra data.
- EdgeTable(int triangleIndices[])
- {
- // We'll have one edge for each vertex
- edgeTable = new HashMap(triangleIndices.length * 2);
-
- // Fill in table
- Edge e;
- for (int t = 0 ; t < triangleIndices.length ; t += 3) {
- // Put all 3 edges of triangle into table
- for (int v = 0 ; v < 3 ; v++) {
- e = new Edge(triangleIndices[t + v],
- triangleIndices[t + ((v + 1) % 3)]);
-
- if (edgeTable.get(e) != null) {
- if ((DEBUG & 1) != 0) {
- System.out.println("EdgeTable Error: duplicate edge (" +
- triangleIndices[t + v] + ", " +
- triangleIndices[t + ((v + 1) % 3)] + ").");
- }
- } else {
- // Store index of 3rd vertex (across from edge)
- edgeTable.put(e, new Integer(t + ((v + 2) % 3)));
- }
- }
- }
-
- if ((DEBUG & 1) != 0) {
- System.out.println("Edge Table:");
- Iterator list = edgeTable.keySet().iterator();
- while (list.hasNext()) {
- Edge edge = (Edge)list.next();
- System.out.println(" (" + edge.v1 + ", " + edge.v2 + ") = " +
- get(edge.v1, edge.v2));
- }
- }
- } // End of constructor EdgeTable
-
-} // End of class EdgeTable
-
-// End of file EdgeTable.java
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/GeomBuffer.java b/src/classes/share/com/sun/j3d/utils/geometry/GeomBuffer.java
deleted file mode 100644
index 57e4d96..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/GeomBuffer.java
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry;
-
-import javax.media.j3d.Geometry;
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.QuadArray;
-import javax.media.j3d.TriangleArray;
-import javax.media.j3d.TriangleFanArray;
-import javax.media.j3d.TriangleStripArray;
-import javax.vecmath.Point3f;
-import javax.vecmath.TexCoord2f;
-import javax.vecmath.Vector3f;
-
-/**
- * GeomBuffer allows OpenGL-like input of geometry data. It outputs
- * Java 3D geometry array objects. This utility is to simplify porting
- * of OpenGL programs to Java 3D.
- *
- * Notice, that you only need to specify some upperbound on the number of
- * points you'll use at the beginning (100 in this case).
- *
- *
- * GeomBuffer gbuf = new GeomBuffer(100);
- * gbuf.begin(GeomBuffer.QUADS);
- *
- * for (int i = 0; i < 5; i++){
- * gbuf.normal3d(0.0, 1.0, 0.0);
- * gbuf.vertex3d(1.0, 1.0, 0.0);
- *
- * gbuf.normal3d(0.0, 1.0, 0.0);
- * gbuf.vertex3d(0.0, 1.0, 0.0);
- *
- * gbuf.normal3d(0.0, 1.0, 0.0);
- * gbuf.vertex3d(0.0, 0.0, 0.0);
- *
- * gbuf.normal3d(0.0, 1.0, 0.0);
- * gbuf.vertex3d(1.0, 0.0, 0.0);
- * }
- * gbuf.end();
- * Shape3D shape = new Shape3D(gbuf.getGeom(GeomBuffer.GENERATE_NORMALS));
- *
- *
- * The NormalGenerator adds normals to geometry without normals.
- *
- * Also, the GeometryCompressor can take a set of GeometryInfo objects in a
- * CompressionSteam and generate a CompressedGeometry object from the
- * geometry.
- *
- * @see NormalGenerator
- * @see Stripifier
- * @see com.sun.j3d.utils.compression.CompressionStream
- * @see com.sun.j3d.utils.compression.GeometryCompressor
- * @see javax.media.j3d.GeometryArray
- */
-
-public class GeometryInfo {
-
- /**
- * Send to the constructor to inform that the data will be arranged so
- * that each set of three vertices form an independent triangle
- */
- public static final int TRIANGLE_ARRAY = 1;
-
- /**
- * Send to the constructor to inform that the data will be arranged so
- * that each set of four vertices form an independent quad
- */
- public static final int QUAD_ARRAY = 2;
-
- /**
- * Send to the constructor to inform that the data will be arranged so
- * that the stripCounts array indicates how many vertices to use
- * for each triangle fan.
- */
- public static final int TRIANGLE_FAN_ARRAY = 3;
-
- /**
- * Send to the constructor to inform that the data will be arranged so
- * that the stripCounts array indicates how many vertices to use
- * for each triangle strip.
- */
- public static final int TRIANGLE_STRIP_ARRAY = 4;
-
- /**
- * Send to the constructor to inform that the data is arranged as
- * possibly multi-contour, possible non-planar polygons.
- * The stripCounts array indicates how many vertices to use
- * for each contour, and the contourCounts array indicates how many
- * stripCounts entries to use for each polygon. The first
- * contour is the bounding polygon, and subsequent contours are
- * "holes." If contourCounts is left null, the default is
- * one contour per polygon.
- */
- public static final int POLYGON_ARRAY = 5;
-
- private int prim;
-
- // 1 Show indexification details
- private static final int DEBUG = 0;
-
- private Point3f coordinates[] = null;
- private Color3f colors3[] = null;
- private Color4f colors4[] = null;
- private Vector3f normals[] = null;
- private Object texCoordSets[][] = null;
-
- private int coordinateIndices[] = null;
- private int colorIndices[] = null;
- private int normalIndices[] = null;
- private int texCoordIndexSets[][] = null;
-
- private int[] texCoordSetMap = null;
- private int texCoordSetCount = 0;
- private int texCoordDim = 0;
-
- private int stripCounts[] = null;
- private int contourCounts[] = null;
-
- private Triangulator tr = null;
- private NormalGenerator ng = null;
-
- private int oldPrim = 0;
- private int oldStripCounts[] = null;
-
- private boolean coordOnly = false;
-
-
-
- /**
- * Constructor.
- * Creates an empty GeometryInfo object.
- * @param primitive Tells the GeometryInfo object the type of
- * primitive data to be stored
- * in it, so it will know the format of the data. It can be one of
- * TRIANGLE_ARRAY,
- * QUAD_ARRAY, TRIANGLE_FAN_ARRAY, TRIANGLE_STRIP_ARRAY, or POLYGON_ARRAY.
- */
- public GeometryInfo(int primitive)
- {
- if ((primitive >= TRIANGLE_ARRAY) && (primitive <= POLYGON_ARRAY)) {
- prim = primitive;
- } else {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo0"));
- }
- } // End of GeometryInfo(int)
-
-
-
- /**
- * Contructor. Populates the GeometryInfo with the geometry from
- * the GeometryArray.
- * GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
- * // initialize the geometry info here
- * // generate normals
- * NormalGenerator ng = new NormalGenerator();
- * ng.generateNormals(gi);
- * // stripify
- * Stripifier st = new Stripifier();
- * st.stripify(gi);
- * GeometryArray result = gi.getGeometryArray();
- *
Initial
and
- * Valid
GeometryArray methods (
- * setInitialVertexIndex()
and setValidVertexCount()
- *
and their cousins) then only the needed geometry
- * is copied into the GeometryInfo.
- */
- public GeometryInfo(GeometryArray ga)
- {
- GeometryInfoGenerator.create(this, ga);
- } // End of GeometryInfo(GeometryArray)
-
-
-
- /**
- * Removes all data from the GeometryInfo and resets the primitive.
- * After a call to reset(), the GeometryInfo object will be just like
- * it was when it was newly constructed.
- * @param primitive Either TRIANGLE_ARRAY, QUAD_ARRAY,
- * TRIANGLE_FAN_ARRAY, TRIANGLE_STRIP_ARRAY, or POLYGON_ARRAY.
- * Tells the GeometryInfo object the type of primitive data to be stored
- * in it, so it will know the format of the data.
- */
- public void reset(int primitive)
- {
- if ((primitive >= TRIANGLE_ARRAY) && (primitive <= POLYGON_ARRAY)) {
- prim = primitive;
- } else {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo0"));
- }
-
- coordinates = null;
- colors3 = null;
- colors4 = null;
- normals = null;
-
- coordinateIndices = null;
- colorIndices = null;
- normalIndices = null;
-
- stripCounts = null;
- contourCounts = null;
-
- oldPrim = 0;
- oldStripCounts = null;
-
- texCoordDim = 0;
- texCoordSetCount = 0;
- texCoordSets = null;
- texCoordIndexSets = null;
- texCoordSetMap = null;
-
- coordOnly = false;
-
- } // End of reset(int)
-
-
-
- /**
- * Removes all data from this GeometryInfo and populates it with
- * the geometry from the GeometryArray.
- */
- public void reset(GeometryArray ga)
- {
- GeometryInfoGenerator.create(this, ga);
- } // End of reset(GeometryArray)
-
-
-
- // This method takes an indexed quad array and expands it to
- // a list of indexed triangles. It is used for the Coordinate
- // indices as well as the color and texture indices.
- private int[] expandQuad(int indices[])
- {
- int triangles[] = new int[indices.length / 4 * 6];
-
- for (int i = 0 ; i < indices.length / 4 ; i++ ) {
- triangles[i * 6 + 0] = indices[i * 4];
- triangles[i * 6 + 1] = indices[i * 4 + 1];
- triangles[i * 6 + 2] = indices[i * 4 + 2];
- triangles[i * 6 + 3] = indices[i * 4];
- triangles[i * 6 + 4] = indices[i * 4 + 2];
- triangles[i * 6 + 5] = indices[i * 4 + 3];
- }
-
- return triangles;
- } // End of expandQuad
-
-
-
- // This method takes an indexed triangle fan and expands it to
- // a list of indexed triangles. It is used for the Coordinate
- // indices as well as the color and texture indices.
- private int[] expandTriFan(int numTris, int indices[])
- {
- int triangles[] = new int[numTris * 3];
- int p = 0;
- int base = 0;
- for (int f = 0 ; f < stripCounts.length ; f++) {
- for (int t = 0 ; t < stripCounts[f] - 2 ; t++) {
- triangles[p++] = indices[base];
- triangles[p++] = indices[base + t + 1];
- triangles[p++] = indices[base + t + 2];
- }
- base += stripCounts[f];
- }
- return triangles;
- } // End of expandTriFan
-
-
-
- // This method takes an indexed triangle strip and expands it to
- // a list of indexed triangles. It is used for the Coordinate
- // indices as well as the color and texture indices.
- private int[] expandTriStrip(int numTris, int indices[])
- {
- int triangles[] = new int[numTris * 3];
-
- int p = 0;
- int base = 0;
- for (int s = 0 ; s < stripCounts.length ; s++) {
- for (int t = 0 ; t < stripCounts[s] - 2 ; t++) {
-
- // Use a ping-ponging algorithm to reverse order on every other
- // triangle to preserve winding
- if (t % 2 == 0) {
- triangles[p++] = indices[base + t + 0];
- triangles[p++] = indices[base + t + 1];
- triangles[p++] = indices[base + t + 2];
- } else {
- triangles[p++] = indices[base + t + 0];
- triangles[p++] = indices[base + t + 2];
- triangles[p++] = indices[base + t + 1];
- }
- }
- base += stripCounts[s];
- }
-
- return triangles;
- } // End of expandTriStrip
-
-
-
- // Used by the NormalGenerator utility. Informs the GeometryInfo object
- // to remember its current primitive and stripCounts arrays so that
- // they can be used to convert the object back to its original
- // primitive
- void rememberOldPrim()
- {
- oldPrim = prim;
- oldStripCounts = stripCounts;
- } // End of rememberOldPrim
-
-
-
- // The NormalGenerator needs to know the original primitive for
- // facet normal generation for quads
- int getOldPrim()
- {
- return oldPrim;
- } // End of getOldPrim
-
-
-
- // Used by the Utility libraries other than the NormalGenerator.
- // Informs the GeometryInfo object that the geometry need not
- // be converted back to the original primitive before returning.
- // For example, if a list of Fans is sent, converted to Triangles
- // for normal generation, and then stripified by the Stripifyer,
- // we want to make sure that GeometryInfo doesn't convert the
- // geometry *back* to fans before creating the output GeometryArray.
- void forgetOldPrim()
- {
- oldPrim = 0;
- oldStripCounts = null;
- } // End of forgetOldPrim
-
-
-
- // We have changed the user's data from their original primitive
- // type to TRIANGLE_ARRAY. If this method is being called, it
- // means we need to change it back (to try and hide from the user
- // the fact that we've converted). This usually happens when
- // the user has used GeometryInfo for generating normals, but
- // they are not Stripifying or Triangulating. The function is
- // called from getGeometryArray before creating the output data.
- private void changeBackToOldPrim()
- {
- if (oldPrim != 0) {
- convertToIndexedTriangles();
- if (ng == null) ng = new NormalGenerator();
- ng.convertBackToOldPrim(this, oldPrim, oldStripCounts);
- oldPrim = 0;
- oldStripCounts = null;
- }
- } // End of changeBackToOldPrim
-
-
-
- /**
- * Convert the GeometryInfo object to have primitive type TRIANGLE_ARRAY
- * and be indexed.
- * @throws IllegalArgumentException if coordinate data is missing,
- * if the index lists aren't all the
- * same length, if an index list is set and the corresponding data
- * list isn't set, if a data list is set and the corresponding
- * index list is unset (unless all index lists are unset or in
- * USE_COORD_INDEX_ONLY format),
- * if StripCounts or ContourCounts is inconsistent with the current
- * primitive, if the sum of the contourCounts array doesn't equal
- * the length of the StripCounts array, or if the number of vertices
- * isn't a multiple of three (for triangles) or four (for quads).
- */
- public void convertToIndexedTriangles()
- {
- int triangles = 0;
-
- // This calls checkForBadData
- indexify();
-
- if (prim == TRIANGLE_ARRAY) return;
-
- switch(prim) {
-
- case QUAD_ARRAY:
-
- coordinateIndices = expandQuad(coordinateIndices);
- if (colorIndices != null) colorIndices = expandQuad(colorIndices);
- if (normalIndices != null)
- normalIndices = expandQuad(normalIndices);
- for (int i = 0 ; i < texCoordSetCount ; i++)
- texCoordIndexSets[i] = expandQuad(texCoordIndexSets[i]);
- break;
-
- case TRIANGLE_FAN_ARRAY:
- // Count how many triangles are in the object
- for (int i = 0 ; i < stripCounts.length ; i++) {
- triangles += stripCounts[i] - 2;
- }
-
- coordinateIndices = expandTriFan(triangles, coordinateIndices);
- if (colorIndices != null)
- colorIndices = expandTriFan(triangles, colorIndices);
- if (normalIndices != null)
- normalIndices = expandTriFan(triangles, normalIndices);
- for (int i = 0 ; i < texCoordSetCount ; i++)
- texCoordIndexSets[i] = expandTriFan(triangles,
- texCoordIndexSets[i]);
- break;
-
- case TRIANGLE_STRIP_ARRAY:
- // Count how many triangles are in the object
- for (int i = 0 ; i < stripCounts.length ; i++) {
- triangles += stripCounts[i] - 2;
- }
-
- coordinateIndices = expandTriStrip(triangles, coordinateIndices);
- if (colorIndices != null)
- colorIndices = expandTriStrip(triangles, colorIndices);
- if (normalIndices != null)
- normalIndices = expandTriStrip(triangles, normalIndices);
- for (int i = 0 ; i < texCoordSetCount ; i++)
- texCoordIndexSets[i] = expandTriStrip(triangles,
- texCoordIndexSets[i]);
- break;
-
- case POLYGON_ARRAY:
- if (tr == null) tr = new Triangulator();
- tr.triangulate(this);
- break;
- }
-
- prim = TRIANGLE_ARRAY;
- stripCounts = null;
- } // End of convertToIndexedTriangles
-
-
-
- /**
- * Get the current primitive. Some of the utilities may change the
- * primitive type of the data stored in the GeometryInfo object
- * (for example, the stripifyer will change it to TRIANGLE_STRIP_ARRAY).
- */
- public int getPrimitive()
- {
- return prim;
- } // End of getPrimitive()
-
-
-
- /**
- * Set the current primitive. Some of the utilities may change the
- * primitive type of the data stored in the GeometryInfo object
- * (for example, the stripifyer will change it to TRIANGLE_STRIP_ARRAY).
- * But the user can't change the primitive type - it is set in the
- * constructor. Therefore, this method has package scope.
- */
- void setPrimitive(int primitive)
- {
- if ((prim >= TRIANGLE_ARRAY) && (prim <= POLYGON_ARRAY)) {
- prim = primitive;
- } else {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo0"));
- }
- } // End of setPrimitive()
-
-
-
- /**
- * Sets the coordinates array.
- * No data copying is done because a reference to user data is used.
- */
- public void setCoordinates(Point3f coordinates[])
- {
- this.coordinates = coordinates;
- } // End of setCoordinates
-
-
-
- /**
- * Sets the coordinates array.
- * The points are copied into the GeometryInfo object.
- */
- public void setCoordinates(Point3d coordinates[])
- {
- if (coordinates == null) this.coordinates = null;
- else {
- this.coordinates = new Point3f[coordinates.length];
- for (int i = 0 ; i < coordinates.length ; i++) {
- this.coordinates[i] = new Point3f(
- (float)(coordinates[i].x),
- (float)(coordinates[i].y),
- (float)(coordinates[i].z));
- }
- }
- } // End of setCoordinates
-
-
-
- /**
- * Sets the coordinates array.
- * The points are copied into the GeometryInfo object.
- */
- public void setCoordinates(float coordinates[])
- {
- if (coordinates == null) this.coordinates = null;
- else {
- this.coordinates = new Point3f[coordinates.length / 3];
- for (int i = 0 ; i < this.coordinates.length ; i++) {
- this.coordinates[i] = new Point3f(coordinates[i * 3],
- coordinates[i * 3 + 1],
- coordinates[i * 3 + 2]);
- }
- }
- } // End of setCoordinates
-
-
-
- /**
- * Sets the coordinates array.
- * The points are copied into the GeometryInfo object.
- */
- public void setCoordinates(double coordinates[])
- {
- if (coordinates == null) this.coordinates = null;
- else {
- this.coordinates = new Point3f[coordinates.length / 3];
- for (int i = 0 ; i < coordinates.length / 3 ; i++) {
- this.coordinates[i] = new Point3f((float)coordinates[i * 3],
- (float)coordinates[i * 3 + 1],
- (float)coordinates[i * 3 + 2]);
- }
- }
- } // End of setCoordinates
-
-
-
- /**
- * Retrieves a reference to the coordinate array.
- */
- public Point3f[] getCoordinates()
- {
- return coordinates;
- } // End of getCoordinates
-
-
-
- /**
- * Sets the colors array.
- * No data copying is done because a reference to
- * user data is used.
- */
- public void setColors(Color3f colors[])
- {
- colors3 = colors;
- colors4 = null;
- } // End of setColors
-
-
-
- /**
- * Sets the colors array.
- * No data copying is done because a reference to
- * user data is used.
- */
- public void setColors(Color4f colors[])
- {
- colors3 = null;
- colors4 = colors;
- } // End of setColors
-
-
-
- /**
- * Sets the colors array.
- * The points are copied into the GeometryInfo object.
- */
- public void setColors(Color3b colors[])
- {
- if (colors == null) {
- colors3 = null;
- colors4 = null;
- } else {
- colors3 = new Color3f[colors.length];
- colors4 = null;
- for (int i = 0 ; i < colors.length ; i++) {
- colors3[i] = new Color3f((float) (colors[i].x & 0xff) / 255.0f,
- (float) (colors[i].y & 0xff) / 255.0f,
- (float) (colors[i].z & 0xff) / 255.0f);
- }
- }
- } // End of setColors
-
-
-
- /**
- * Sets the colors array.
- * The points are copied into the GeometryInfo object.
- */
- public void setColors(Color4b colors[])
- {
- if (colors == null) {
- colors3 = null;
- colors4 = null;
- } else {
- colors3 = null;
- colors4 = new Color4f[colors.length];
- for (int i = 0 ; i < colors.length ; i++) {
- colors4[i] = new Color4f((float) (colors[i].x & 0xff) / 255.0f,
- (float) (colors[i].y & 0xff) / 255.0f,
- (float) (colors[i].z & 0xff) / 255.0f,
- (float) (colors[i].w & 0xff) / 255.0f);
- }
- }
- } // End of setColors
-
-
-
- /**
- * Sets the colors array.
- * The points are copied into the GeometryInfo object, assuming
- * 3 components (R, G, and B) per vertex.
- */
- public void setColors3(float colors[])
- {
- if (colors == null) {
- colors3 = null;
- colors4 = null;
- } else {
- colors3 = new Color3f[colors.length / 3];
- colors4 = null;
- for (int i = 0 ; i < colors.length / 3 ; i++) {
- colors3[i] = new Color3f(colors[i * 3],
- colors[i * 3 + 1],
- colors[i * 3 + 2]);
- }
- }
- } // End of setColors3
-
-
-
- /**
- * Sets the colors array.
- * The points are copied into the GeometryInfo object, assuming
- * 4 components (R, G, B, and A) per vertex.
- */
- public void setColors4(float colors[])
- {
- if (colors == null) {
- colors3 = null;
- colors4 = null;
- } else {
- colors3 = null;
- colors4 = new Color4f[colors.length / 4];
- for (int i = 0 ; i < colors.length / 4 ; i++) {
- colors4[i] = new Color4f(colors[i * 4],
- colors[i * 4 + 1],
- colors[i * 4 + 2],
- colors[i * 4 + 3]);
- }
- }
- } // End of setColors4
-
-
-
- /**
- * Sets the colors array.
- * The points are copied into the GeometryInfo object, assuming
- * 3 components (R, G, and B) per vertex.
- */
- public void setColors3(byte colors[])
- {
- if (colors == null) {
- colors3 = null;
- colors4 = null;
- } else {
- colors3 = new Color3f[colors.length / 3];
- colors4 = null;
- for (int i = 0 ; i < colors.length / 3 ; i++) {
- colors3[i] =
- new Color3f((float)(colors[i * 3] & 0xff) / 255.0f,
- (float)(colors[i * 3 + 1] & 0xff) / 255.0f,
- (float)(colors[i * 3 + 2] & 0xff) / 255.0f);
- }
- }
- } // End of setColors3
-
-
-
- /**
- * Sets the colors array.
- * The points are copied into the GeometryInfo object, assuming
- * 4 components (R, G, B, and A) per vertex.
- */
- public void setColors4(byte colors[])
- {
- if (colors == null) {
- colors3 = null;
- colors4 = null;
- } else {
- colors3 = null;
- colors4 = new Color4f[colors.length / 4];
- for (int i = 0 ; i < colors.length / 4 ; i++) {
- colors4[i] =
- new Color4f((float)(colors[i * 4] & 0xff) / 255.0f,
- (float)(colors[i * 4 + 1] & 0xff) / 255.0f,
- (float)(colors[i * 4 + 2] & 0xff) / 255.0f,
- (float)(colors[i * 4 + 3] & 0xff) / 255.0f);
- }
- }
- } // End of setColors4
-
-
-
- /**
- * Retrieves a reference to the colors array. Will be either
- * Color3f[]
or Color4f[]
depending on
- * the type of the input data. Call
- * getNumColorComponents() to find out which version is returned.
- */
- public Object[] getColors()
- {
- if (colors3 != null) return colors3;
- else return colors4;
- } // End of getColors
-
-
-
- /**
- * Returns the number of color data components stored per vertex
- * in the current GeometryInfo object (3 for RGB or 4 for RGBA).
- * If no colors are currently defined, 0 is returned.
- */
- public int getNumColorComponents()
- {
- if (colors3 != null) return 3;
- else if (colors4 != null) return 4;
- else return 0;
- } // End of getNumColorComponents
-
-
-
- /**
- * Sets the normals array.
- * No data copying is done because a reference to
- * user data is used.
- */
- public void setNormals(Vector3f normals[])
- {
- this.normals = normals;
- } // End of setNormals
-
-
-
- /**
- * Sets the normals array.
- * The points are copied into the GeometryInfo object.
- */
- public void setNormals(float normals[])
- {
- if (normals == null) this.normals = null;
- else {
- this.normals = new Vector3f[normals.length / 3];
- for (int i = 0 ; i < this.normals.length ; i++) {
- this.normals[i] = new Vector3f(normals[i * 3],
- normals[i * 3 + 1],
- normals[i * 3 + 2]);
- }
- }
- } // End of setNormals(float[])
-
-
-
- /**
- * Retrieves a reference to the normal array.
- */
- public Vector3f[] getNormals()
- {
- return normals;
- } // End of getNormals
-
-
-
- /**
- * This method is used to specify the number of texture coordinate sets
- * and the dimensionality of the texture coordinates.
- * The number of texture coordinate sets must be specified to the GeometryInfo
- * class before any of the sets are specified. The dimensionality of the
- * texture coordinates may be 2, 3, or 4, corresponding to 2D, 3D, or 4D
- * texture coordinates respectively.(All sets must have the same
- * dimensionality.) The default is zero, 2D texture coordinate sets.
- * This method should be called before any texture coordinate sets are
- * specified because calling this method will delete all previously
- * specified texture coordinate and texture coordinate index arrays
- * associated with this GeometryInfo. For example:
- *
- * The second call to
- * geomInfo.setTextureCoordinateParams(2, 3);
- * geomInfo.setTextureCoordinates(0, tex0);
- * geomInfo.setTextureCoordinates(1, tex1);
- * geomInfo.setTextureCoordinateParams(1, 2);
- * geomInfo.getTexCoordSetCount();
- *
setTextureCoordinateParams
will erase all
- * the texture coordinate arrays, so the subsequent call to
- * getTexCoordSetCount
will return 1.
- * @param numSets The number of texture coordinate sets that will be
- * specified for this GeometryInfo object.
- * @param dim The dimensionality of the texture coordinates. Has to be 2, 3
- * or 4.
- * @throws IllegalArgumentException if the dimensionality of the texture
- * coordinates is not one of 2, 3 or 4.
- */
- public void setTextureCoordinateParams(int numSets, int dim)
- {
- if (dim == 2) {
- texCoordSets = new TexCoord2f[numSets][];
- } else if (dim == 3) {
- texCoordSets = new TexCoord3f[numSets][];
- } else if (dim == 4) {
- texCoordSets = new TexCoord4f[numSets][];
- } else {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo9"));
- }
- texCoordIndexSets = new int[numSets][];
- texCoordDim = dim;
- texCoordSetCount = numSets;
- } // End of setTextureCoordinateParams
-
-
-
- /**
- * Returns the number of texture coordinate sets in this GeometryInfo.
- * This value is set with setTextureCoordinateParams().
- * If setTextureCoordinateParams()
- * has not been called, 0 is returned unless one of the deprecated
- * texture coordinate methods has been called. Calling one of the
- * deprecated texture coordinate methods sets the count to 1.
- * The deprecated texture coordinate methods are those that don't
- * take texCoordSet as the first parameter.
- * @return the number of texture coordinate sets in this
- * GeometryInfo.
- */
- public int getTexCoordSetCount() {
- return texCoordSetCount;
- }
-
-
-
- /**
- * Returns the number of texture coordinate components that are stored
- * per vertex. Returns 2 for ST (2D), 3 for STR (3D),
- * or 4 for STRQ (4D), aslo known as the "dimensionality" of the
- * coordinates. This value is set with
- * setTextureCoordinateParams(). If setTextureCoordinateParams()
- * has not been called, 0 is returned unless one of the deprecated
- * texture coordinate methods has been called. Calling one of the
- * deprecated texture coordinate methods sets the dimensionality
- * explicitly (if you called setTextureCoordinates(Point2f[]) then
- * 2 is returned).
- * The deprecated texture coordinate methods are those that don't
- * take texCoordSet as the first parameter.
- */
- public int getNumTexCoordComponents()
- {
- return texCoordDim;
- } // End of getNumTexCoordComponents
-
-
-
- /**
- * Sets the mapping between texture coordinate sets and texture units.
- * See the
- *
- * GeometryArray constructor for further details.
- * texCoordSet
< 0 or
- * texCoordSet >= texCoordSetCount
,
- * or the texture coordinate parameters were not previously set by
- * calling setTextureCoordinateParams(texCoordSetCount, 2)
.
- */
- public void setTextureCoordinates(int texCoordSet, TexCoord2f texCoords[])
- {
- if (texCoordDim != 2)
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo15"));
- if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo18"));
-
- texCoordSets[texCoordSet] = texCoords;
- } // End of setTextureCoordinates(int, TexCoord3f[])
-
-
-
- /**
- * Sets the TextureCoordinates array by copying the data
- * into the GeometryInfo object.
- * This method sets the number of texture coordinate sets to 1,
- * sets the dimensionality of the texture coordinates to 2,
- * and sets the coordinates for texture coordinate set 0.
- * @deprecated As of Java 3D 1.3 replaced by
- * setTextureCoordinates(int texCoordSet, TexCoord2f coords[])
- */
- public void setTextureCoordinates(Point2f texCoords[])
- {
- texCoordSetCount = 1;
- texCoordDim = 2;
- texCoordSets = new TexCoord2f[1][];
- if (texCoords != null) {
- TexCoord2f[] tex = new TexCoord2f[texCoords.length];
- for (int i = 0 ; i < texCoords.length ; i++)
- tex[i] = new TexCoord2f(texCoords[i]);
- texCoordSets[0] = tex;
- }
- } // End of setTextureCoordinates(Point2f[])
-
-
-
- /**
- * Sets the texture coordinates array for the specified set.
- * No data copying is done - a reference to user data is used.
- * @param texCoordSet The texture coordinate set for which these coordinates
- * are being specified.
- * @param texCoords Array of 3D texture coordinates.
- * @throws IllegalArgumentException if texCoordSet
< 0 or
- * texCoordSet >= texCoordSetCount
,
- * or the texture coordinate parameters were not previously set by
- * calling setTextureCoordinateParams(texCoordSetCount, 3)
.
- */
- public void setTextureCoordinates(int texCoordSet, TexCoord3f texCoords[])
- {
- if (texCoordDim != 3)
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo16"));
- if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo18"));
-
- texCoordSets[texCoordSet] = texCoords;
- } // End of setTextureCoordinates(int, TexCoord3f[])
-
-
-
- /**
- * Sets the TextureCoordinates array by copying the data
- * into the GeometryInfo object.
- * This method sets the number of texture coordinate sets to 1,
- * sets the dimensionality of the texture coordinates to 3,
- * and sets the coordinates for texture coordinate set 0.
- * @deprecated As of Java 3D 1.3 replaced by
- * setTextureCoordinates(int texCoordSet, TexCoord3f coords[])
- */
- public void setTextureCoordinates(Point3f texCoords[])
- {
- texCoordSetCount = 1;
- texCoordDim = 3;
- texCoordSets = new TexCoord3f[1][];
- if (texCoords != null) {
- TexCoord3f[] tex = new TexCoord3f[texCoords.length];
- for (int i = 0 ; i < texCoords.length ; i++)
- tex[i] = new TexCoord3f(texCoords[i]);
- texCoordSets[0] = tex;
- }
- } // End of setTextureCoordinates(Point3f[])
-
-
-
- /**
- * Sets the texture coordinates array for the specified set.
- * No data copying is done - a reference to user data is used.
- * @param texCoordSet The texture coordinate set for which these coordinates
- * are being specified.
- * @param texCoords Array of 4D texture coordinates.
- * @throws IllegalArgumentException if texCoordSet
< 0 or
- * texCoordSet >= texCoordSetCount
,
- * or the texture coordinate parameters were not previously set by
- * calling setTextureCoordinateParams(texCoordSetCount, 4)
.
- */
- public void setTextureCoordinates(int texCoordSet, TexCoord4f texCoords[]) {
- if (texCoordDim != 4)
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo17"));
- if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo18"));
-
- texCoordSets[texCoordSet] = texCoords;
- } // End of setTextureCoordinates(int, TexCoord4f[])
-
-
-
- /**
- * Sets the texture coordinates array by copying the data into the
- * GeometryInfo object. The number of sets and dimensionality of
- * the sets must have been set previously with
- * setTextureCoordinateParams(texCoordSetCount, dim).
- * @param texCoordSet The texture coordinate set for which these coordinates
- * are being specified.
- * @param texCoords The float array of texture coordinates. For n texture
- * coordinates with dimensionality d, there must be d*n floats in the array.
- * @throws IllegalArgumentException if texCoordSet
< 0 or
- * texCoordSet >= texCoordSetCount
,
- * or the texture coordinate parameters were not previously set by
- * calling setTextureCoordinateParams
.
- */
- public void setTextureCoordinates(int texCoordSet, float texCoords[])
- {
- if ((texCoords.length % texCoordDim) != 0)
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo2"));
-
- // Copy the texCoords into this GeometryInfo object
- if (texCoordDim == 2) {
- TexCoord2f tcoords[] = new TexCoord2f[texCoords.length / 2];
- for (int i = 0 ; i < tcoords.length ; i++)
- tcoords[i] = new TexCoord2f(texCoords[i * 2],
- texCoords[i * 2 + 1]);
- setTextureCoordinates(texCoordSet, tcoords);
- } else if (texCoordDim == 3) {
- TexCoord3f tcoords[] = new TexCoord3f[texCoords.length / 3];
- for (int i = 0 ; i < tcoords.length ; i++)
- tcoords[i] = new TexCoord3f(texCoords[i * 3],
- texCoords[i * 3 + 1],
- texCoords[i * 3 + 2]);
- setTextureCoordinates(texCoordSet, tcoords);
- } else if (texCoordDim == 4) {
- TexCoord4f tcoords[] = new TexCoord4f[texCoords.length / 4];
- for (int i = 0 ; i < tcoords.length ; i++)
- tcoords[i] = new TexCoord4f(texCoords[i * 4],
- texCoords[i * 4 + 1],
- texCoords[i * 4 + 2],
- texCoords[i * 4 + 3]);
- setTextureCoordinates(texCoordSet, tcoords);
- } else {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo21"));
- }
- } // End of setTextureCoordinates(int, float[])
-
-
-
- /**
- * Sets the texture coordinates array by copying the data
- * into the GeometryInfo object, assuming two numbers
- * (S and T) per vertex.
- * This method sets the number of texture coordinate sets to 1,
- * sets the dimensionality of the texture coordinates to 2,
- * and sets the coordinates for texture coordinate set 0.
- * @deprecated As of Java 3D 1.3 replaced by
- * setTextureCoordinates(int texCoordSet, float texCoords[])
- */
- public void setTextureCoordinates2(float texCoords[])
- {
- texCoordSetCount = 1;
- texCoordDim = 2;
- texCoordSets = new TexCoord2f[1][];
- setTextureCoordinates(0, texCoords);
- } // End of setTextureCoordinates2(float[])
-
-
-
- /**
- * Sets the TextureCoordinates array by copying the data
- * into the GeometryInfo object, assuming three numbers
- * (S, T, & R) per vertex.
- * This method sets the number of texture coordinate sets to 1,
- * sets the dimensionality of the texture coordinates to 3,
- * and sets the coordinates for texture coordinate set 0.
- * @deprecated As of Java 3D 1.3 replaced by
- * setTextureCoordinates(int texCoordSet, float texCoords[])
- */
- public void setTextureCoordinates3(float texCoords[])
- {
- texCoordSetCount = 1;
- texCoordDim = 3;
- texCoordSets = new TexCoord3f[1][];
- setTextureCoordinates(0, texCoords);
- } // End of setTextureCoordinates3(float[])
-
-
-
- /**
- * Returns a reference to the indicated texture coordinate array.
- * The return type will be TexCoord2f[]
, TexCoord3f[]
- *
, or TexCoord4f[]
depending on the
- * current dimensionality of the texture coordinates in the GeometryInfo
- * object. Use getNumTexCoordComponents()
to find out which
- * version is returned.
- * @param texCoordSet The index of the texture coordinate set to
- * retrieve.
- * @return An array of texture coordinates at the specified index
- * @throws IllegalArgumentException If texCoordSet
< 0
- * or texCoordSet >= texCoordSetCount
- */
- public Object[] getTextureCoordinates(int texCoordSet)
- {
- if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo18"));
- return texCoordSets[texCoordSet];
- } // End of getTextureCoordinates(int)
-
-
-
- /**
- * Retrieves a reference to texture coordinate set 0.
- * The return type will be TexCoord2f[]
, TexCoord3f[]
- *
, or TexCoord4f[]
depending on the
- * current dimensionality of the texture coordinates in the GeometryInfo
- * object. Use getNumTexCoordComponents()
to find out which
- * version is returned. Equivalent to getTextureCoordinates(0)
.
- * @return An array of texture coordinates for set 0.
- * @deprecated As of Java 3D 1.3 replaced by
- * getTextureCoordinates(int texCoordSet)
- */
- public Object[] getTextureCoordinates()
- {
- return texCoordSets[0];
- } // End of getTextureCoordinates()
-
-
-
- /**
- * Sets the array of indices into the Coordinate array.
- * No data copying is done - a reference to user data is used.
- */
- public void setCoordinateIndices(int coordinateIndices[])
- {
- this.coordinateIndices = coordinateIndices;
- } // End of setCoordinateIndices
-
-
-
- /**
- * Retrieves a reference to the array of indices into the
- * coordinate array.
texCoordSet
< 0 or
- * texCoordSet >= texCoordSetCount
.
- */
- public void setTextureCoordinateIndices(int texCoordSet, int texIndices[])
- {
- if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo18"));
-
- // Texture coordinates are indexed
- texCoordIndexSets[texCoordSet] = texIndices;
- } // End of setTextureCoordinateIndices(int, int[])
-
-
-
- /**
- * Sets the array of indices into texture coordinate set 0. Do not
- * call this method if you are using more than one set of texture
- * coordinates.
- * No data is copied - a reference to the user data is used.
- * @deprecated As of Java 3D 1.3 replaced by
- * setTextureCoordinateIndices(int texCoordSet, int indices[])
- * @throws IllegalArgumentException If texCoordSetCount > 1
.
- */
- public void setTextureCoordinateIndices(int texIndices[])
- {
- if (texCoordSetCount > 1)
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo1"));
- texCoordIndexSets = new int[1][];
- texCoordIndexSets[0] = texIndices;
- } // End of setTextureCoordinateIndices(int[])
-
-
-
- /**
- * Retrieves a reference to the specified array of texture
- * coordinate indices.- * - * This method should be considered for advanced users only. - * Novice users should just use getGeometryArray() to retrieve - * their data so that the internal format of GeometryInfo is - * of no concern.
- * - * Depending on which of the utility routines you've called - * on your GeometryInfo object, the results may not be what you - * expect. If you've called the Stripifier, your GeometryInfo - * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY - * and your data will be formatted accordingly. Similarly, if - * you've called the Triangulator, your data is in indexed - * TRIANGLE_ARRAY format. Generating normals with the NormalGenerator - * utility will convert your data to indexed TRIANGLE_ARRAY also, - * but if you call getGeometryArray without calling the Stripifier or - * Triangulator, your data will be converted back to the original - * primitive type when creating the GeometryArray object to pass - * back. However, if your creaseAngle was not Math.PI (no creases - - * smooth shading), then the introduction of - * creases into your model may have split primitives, lengthening - * the StripCounts and index arrays from your original data. - * @param texCoordSet The texture coordinate index set to be - * retrieved. - * @return Integer array of the texture coordinate indices for the specified - * set. - */ - public int[] getTextureCoordinateIndices(int texCoordSet) { - return texCoordIndexSets[texCoordSet]; - } - - - /** - * Returns a reference to texture coordinate index set 0. - * Equivalent to - *getTextureCoordinateIndices(0)
.
- * @deprecated As of Java 3D 1.3 replaced by
- * int[] getTextureCoordinateIndices(int texCoordSet)
- * @return Integer array of the texture coordinate indices for set 0
- */
- public int[] getTextureCoordinateIndices()
- {
- if (texCoordIndexSets == null) return null;
- return texCoordIndexSets[0];
- } // End of getTextureCoordinateIndices()
-
-
-
- /**
- * Sets the array of strip counts. If index lists have been set for
- * this GeomteryInfo object then the data is indexed and the stripCounts
- * are like stripIndexCounts. If no index lists have been set then
- * the data is non-indexed and the stripCounts are like
- * stripVertexCounts.
- * @see GeometryStripArray#GeometryStripArray(int, int,
- * int[] stripVertexCounts)
- * @see IndexedGeometryStripArray#IndexedGeometryStripArray(int, int, int,
- * int[] stripIndexCounts)
- */
- public void setStripCounts(int stripCounts[])
- {
- this.stripCounts = stripCounts;
- } // End of setStripCounts
-
-
-
- /**
- * Retrieves a reference to the array of stripCounts.
- *
- * This method should be considered for advanced users only.
- * Novice users should just use getGeometryArray() to retrieve
- * their data so that the internal format of GeometryInfo is
- * of no concern.
- *
- * Depending on which of the utility routines you've called
- * on your GeometryInfo object, the results may not be what you
- * expect. If you've called the Stripifier, your GeometryInfo
- * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY
- * and your data will be formatted accordingly. Similarly, if
- * you've called the Triangulator, your data is in indexed
- * TRIANGLE_ARRAY format. Generating normals with the NormalGenerator
- * utility will convert your data to indexed TRIANGLE_ARRAY also,
- * but if you call getGeometryArray without calling the Stripifier or
- * Triangulator, your data will be converted back to the original
- * primitive type when creating the GeometryArray object to pass
- * back. However, if your creaseAngle was not Math.PI (no creases -
- * smooth shading), then the introduction of
- * creases into your model may have split primitives, lengthening
- * the StripCounts and index arrays from your original data.
- */
- public int[] getStripCounts()
- {
- return stripCounts;
- } // End of getStripCounts
-
-
-
- /**
- * Sets the list of contour counts. Only used with the POLYGON_ARRAY
- * primitive. Polygons can be made of several vertex lists
- * called contours. The first list is the polygon, and
- * subsequent lists are "holes" that are removed from the
- * polygon. All of the holes must be contained entirely
- * within the polygon.
- */
- public void setContourCounts(int contourCounts[])
- {
- this.contourCounts = contourCounts;
- } // End of setContourCounts
-
-
-
- /**
- * Retrieves a reference to the array of contourCounts.
- */
- public int[] getContourCounts()
- {
- return contourCounts;
- } // End of getContourCounts
-
-
-
- /*
- * This routine will return an index list for any array of objects.
- */
- int[] getListIndices(Object list[])
- {
- // Create list of indices to return
- int indices[] = new int[list.length];
-
- // Create hash table with initial capacity equal to the number
- // of components (assuming about half will be duplicates)
- HashMap table = new HashMap(list.length);
-
- Integer idx;
- for (int i = 0 ; i < list.length ; i++) {
-
- // Find index associated with this object
- idx = (Integer)table.get(list[i]);
-
- if (idx == null) {
- // We haven't seen this object before
- indices[i] = i;
-
- // Put into hash table and remember the index
- table.put(list[i], new Integer(i));
-
- } else {
- // We've seen this object
- indices[i] = idx.intValue();
- }
- }
-
- return indices;
- } // End of getListIndices
-
-
-
- // Class to hash 'size' integers
- private class IndexRow {
- int[] val;
- int size;
- private static final int HASHCONST = 0xBABEFACE;
-
- @Override
- public int hashCode()
- {
- int bits = 0;
- for (int i = 0 ; i < size ; i++) {
- bits ^= (bits * HASHCONST) << 2;
- }
- return bits;
- } // End of IndexRow.hashCode
-
- @Override
- public boolean equals(Object obj)
- {
- for (int i = 0 ; i < size ; i++) {
- if (((IndexRow)obj).get(i) != val[i]) return false;
- }
- return true;
- } // End of IndexRow.equals()
-
- public int get(int index)
- {
- return val[index];
- } // End of IndexRow.get
-
- public void set(int index, int value)
- {
- val[index] = value;
- } // End of IndexRow.set
-
- IndexRow(int numColumns)
- {
- size = numColumns;
- val = new int[size];
- } // End of IndexRow constructor
- } // End of class IndexRow
-
-
-
- /**
- * Create index lists for all data lists.
- * Identical data entries are guaranteed to
- * use the same index value. Does not remove unused data values
- * from the object - call compact() to do this.
- * @param useCoordIndexOnly Reformat the data into the
- * GeometryArray.USE_COORD_INDEX_ONLY format where there is only
- * one index list. If the data is already in the USE_COORD_INDEX_ONLY
- * format, sending false (or calling indexify()) will change
- * it to the normal indexed format.
- * @throws IllegalArgumentException if coordinate data is missing,
- * if the index lists aren't all the
- * same length, if an index list is set and the corresponding data
- * list isn't set, if a data list is set and the corresponding
- * index list is unset (unless all index lists are unset or in
- * USE_COORD_INDEX_ONLY format),
- * if StripCounts or ContourCounts is inconsistent with the current
- * primitive, if the sum of the contourCounts array doesn't equal
- * the length of the StripCounts array, or if the number of vertices
- * isn't a multiple of three (for triangles) or four (for quads).
- */
- public void indexify(boolean useCoordIndexOnly)
- {
- checkForBadData();
-
- if (useCoordIndexOnly) {
- // Return if already in this format
- if (coordOnly) return;
-
- // Start from normal indexed format
- indexify(false);
-
- // Reformat data to USE_COORD_INDEX_ONLY format
- // Need to make an index into the index lists using each
- // row of indexes as one value
-
- // First, find out how many index lists there are;
- int numLists = 1; // Always have coordinates
- if (colorIndices != null) numLists++;
- if (normalIndices != null) numLists++;
- numLists += texCoordSetCount;
-
- // Make single array containing all indices
- int n = coordinateIndices.length;
- IndexRow[] ir = new IndexRow[n];
- int j;
- for (int i = 0 ; i < n ; i++) {
- ir[i] = new IndexRow(numLists);
- j = 0;
- ir[i].set(j++, coordinateIndices[i]);
- if (colorIndices != null) ir[i].set(j++, colorIndices[i]);
- if (normalIndices != null) ir[i].set(j++, normalIndices[i]);
- for (int k = 0 ; k < texCoordSetCount ; k++) {
- ir[i].set(j++, texCoordIndexSets[k][i]);
- }
- }
-
- // Get index into that array
- int[] coordOnlyIndices = getListIndices(ir);
-
- // Get rid of duplicate rows
- int newInd[] = new int[coordOnlyIndices.length];
- ir = (IndexRow[])compactData(coordOnlyIndices, ir, newInd);
- coordOnlyIndices = newInd;
-
- // Reformat data lists to correspond to new index
-
- // Allocate arrays to hold reformatted data
- Point3f[] newCoords = new Point3f[ir.length];
- Color3f[] newColors3 = null;
- Color4f[] newColors4 = null;
- Vector3f[] newNormals = null;
- Object newTexCoordSets[][] = null;
- if (colors3 != null) newColors3 = new Color3f[ir.length];
- else if (colors4 != null) newColors4 = new Color4f[ir.length];
- if (normals != null) newNormals = new Vector3f[ir.length];
- for (int i = 0 ; i < texCoordSetCount ; i++) {
- if (texCoordDim == 2) {
- if (i == 0) newTexCoordSets = new TexCoord2f[texCoordSetCount][];
- newTexCoordSets[i] = new TexCoord2f[ir.length];
- } else if (texCoordDim == 3) {
- if (i == 0) newTexCoordSets = new TexCoord3f[texCoordSetCount][];
- newTexCoordSets[i] = new TexCoord3f[ir.length];
- } else if (texCoordDim == 4) {
- if (i == 0) newTexCoordSets = new TexCoord4f[texCoordSetCount][];
- newTexCoordSets[i] = new TexCoord4f[ir.length];
- }
- }
-
- // Copy data into new arrays
- n = ir.length;
- for (int i = 0 ; i < n ; i++) {
- j = 0;
- newCoords[i] = coordinates[(ir[i]).get(j++)];
- if (colors3 != null) {
- newColors3[i] = colors3[(ir[i]).get(j++)];
- } else if (colors4 != null) {
- newColors4[i] = colors4[(ir[i]).get(j++)];
- }
- if (normals != null) newNormals[i] = normals[(ir[i]).get(j++)];
- for (int k = 0 ; k < texCoordSetCount ; k++) {
- newTexCoordSets[k][i] = texCoordSets[k][(ir[i]).get(j++)];
- }
- }
-
- // Replace old arrays with new arrays
- coordinates = newCoords;
- colors3 = newColors3;
- colors4 = newColors4;
- normals = newNormals;
- texCoordSets = newTexCoordSets;
- coordinateIndices = coordOnlyIndices;
- colorIndices = null;
- normalIndices = null;
- texCoordIndexSets = new int[texCoordSetCount][];
-
- coordOnly = true;
- } else if (coordOnly) {
- // Need to change from useCoordIndexOnly format to normal
- // indexed format. Should make a more efficient implementation
- // later.
-
- int n = coordinateIndices.length;
- if ((colors3 != null) || (colors4 != null)) {
- colorIndices = new int[n];
- for (int i = 0 ; i < n ; i++) colorIndices[i] = coordinateIndices[i];
- }
- if (normals != null) {
- normalIndices = new int[n];
- for (int i = 0 ; i < n ; i++) normalIndices[i] = coordinateIndices[i];
- }
- texCoordIndexSets = new int[texCoordSetCount][];
- for (int i = 0 ; i < texCoordSetCount ; i++) {
- texCoordIndexSets[i] = new int[n];
- for (int j = 0 ; j < n ; j++) {
- texCoordIndexSets[i][j] = coordinateIndices[j];
- }
- }
- coordOnly = false;
- } else {
-
- // No need to indexify if already indexed
- if (coordinateIndices != null) return;
-
- coordinateIndices = getListIndices(coordinates);
-
- if (colors3 != null) colorIndices = getListIndices(colors3);
- else if (colors4 != null) colorIndices = getListIndices(colors4);
-
- if (normals != null) normalIndices = getListIndices(normals);
-
- texCoordIndexSets = new int[texCoordSetCount][];
- for(int i = 0 ; i < texCoordSetCount ; i++) {
- texCoordIndexSets[i] = getListIndices(texCoordSets[i]);
- }
-
- coordOnly = false;
- }
-
- if ((DEBUG & 1) == 1) {
- System.out.println("Coordinate Array:");
- for (int i = 0 ; i < coordinates.length ; i++) {
- System.out.println(" " + i + " " + coordinates[i] +
- " " + coordinates[i].hashCode());
- }
- System.out.println("Index array:");
- for (int i = 0 ; i < coordinateIndices.length ; i++) {
- System.out.println(" " + i + " " + coordinateIndices[i]);
- }
- }
-
- } // End of indexify
-
-
-
- public void indexify()
- {
- indexify(false);
- } // End of indexify()
-
-
-
- /**
- * Allocates an array of the same type as the input type. This allows us to
- * use a generic compactData method.
- *
- * @param data Array of coordinate, color, normal or texture coordinate data
- * The data can be in one of the following formats - Point3f, Color3f,
- * Color4f, TexCoord2f, TexCoord3f, TexCoord4f.
- *
- * @param num The size of the array to be allocated
- *
- * @return An array of size num of the same type as the input type
- *
- * @exception IllegalArgumentException if the input array is not one of the
- * types listed above.
- */
- Object[] allocateArray(Object data[], int num) {
- Object newData[] = null;
- if (data instanceof javax.vecmath.Point3f[]) {
- newData = new Point3f[num];
- } else if (data instanceof javax.vecmath.Vector3f[]) {
- newData = new Vector3f[num];
- } else if (data instanceof javax.vecmath.Color3f[]) {
- newData = new Color3f[num];
- } else if (data instanceof javax.vecmath.Color4f[]) {
- newData = new Color4f[num];
- } else if (data instanceof javax.vecmath.TexCoord2f[]) {
- newData = new TexCoord2f[num];
- } else if (data instanceof javax.vecmath.TexCoord3f[]) {
- newData = new TexCoord3f[num];
- } else if (data instanceof javax.vecmath.TexCoord4f[]) {
- newData = new TexCoord4f[num];
- } else if (data instanceof IndexRow[]) {
- // Hack so we can use compactData for coordIndexOnly
- newData = new IndexRow[num];
- } else throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo9"));
- return newData;
- } // End of allocateArray
-
-
-
- /**
- * Generic method that compacts (ie removes unreferenced/duplicate data)
- * any type of indexed data.
- * Used to compact coordinate, color, normal and texture coordinate data.
- * @param indices Array of indices
- * @param data Array of coordinate, color, normal or texture coordinate data
- * The data can be in one of the following formats - Point3f, Color3f,
- * Color4f, TexCoord2f, TexCoord3f, TexCoord4f.
- * @param newInd The new array of indexes after the data has been compacted.
- * This must be allocated by the calling method. On return, this array will
- * contain the new index data. The size of this array must be equal to
- * indices.length
- * @return Array of the data with unreferenced and duplicate entries removed.
- * The return type will be the same as the type that was passed in data.
- */
- // TODO: Remove duplicate entries in data lists.
- private Object[] compactData(int indices[], Object data[], int newInd[]) {
- Object newData[] = null;
- /*
- * This is a three step process.
- * First, find out how many unique indexes are used. This
- * will be the size of the new data array.
- */
- int numUnique = 0;
- int translationTable[] = new int[data.length];
- for (int i = 0 ; i < indices.length ; i++) {
- if (translationTable[indices[i]] == 0) {
-
- numUnique++;
- translationTable[indices[i]] = 1;
- }
- }
- /*
- * Second, build the new data list. Remember the new indexes so
- * we can use the table to translate the old indexes to the new
- */
- newData = allocateArray(data, numUnique);
- int newIdx = 0;
- for (int i = 0 ; i < translationTable.length ; i++) {
- if (translationTable[i] != 0) {
- newData[newIdx] = data[i];
- translationTable[i] = newIdx++;
- }
- }
- /*
- * Third, make the new index list
- */
- for (int i = 0 ; i < indices.length ; i++) {
- newInd[i] = translationTable[indices[i]];
- }
- return newData;
- } // End of compactData
-
-
-
- /**
- * Remove unused data from an indexed dataset.
- * Indexed data may contain data entries that are never referenced by
- * the dataset. This routine will remove those entries where
- * appropriate and renumber the indices to match the new values.
- * @throws IllegalArgumentException if coordinate data is missing,
- * if the index lists aren't all the
- * same length, if an index list is set and the corresponding data
- * list isn't set, if a data list is set and the corresponding
- * index list is unset (unless all index lists are unset or in
- * USE_COORD_INDEX_ONLY format),
- * if StripCounts or ContourCounts is inconsistent with the current
- * primitive, if the sum of the contourCounts array doesn't equal
- * the length of the StripCounts array, or if the number of vertices
- * isn't a multiple of three (for triangles) or four (for quads).
- */
- public void compact()
- {
- checkForBadData();
-
- // Only usable on indexed data
- if (coordinateIndices == null) return;
-
- // USE_COORD_INDEX_ONLY never has unused data
- if (coordOnly) return;
-
- int newInd[] = new int[coordinateIndices.length];
- coordinates =
- (Point3f[])compactData(coordinateIndices, coordinates, newInd);
- coordinateIndices = newInd;
-
- if (colorIndices != null) {
- newInd = new int[colorIndices.length];
- if (colors3 != null)
- colors3 = (Color3f[])compactData(colorIndices, colors3, newInd);
- else if (colors4 != null)
- colors4 = (Color4f[])compactData(colorIndices, colors4, newInd);
- colorIndices = newInd;
- }
-
- if (normalIndices != null) {
- newInd = new int[normalIndices.length];
- normals = (Vector3f[])compactData(normalIndices, normals, newInd);
- normalIndices = newInd;
- }
-
- for (int i = 0 ; i < texCoordSetCount ; i++) {
- newInd = new int[texCoordIndexSets[i].length];
- texCoordSets[i] = compactData(texCoordIndexSets[i],
- texCoordSets[i], newInd);
- texCoordIndexSets[i] = newInd;
- }
- } // End of compact
-
-
-
- /**
- * Check the data to make sure everything's consistent.
- */
- private void checkForBadData() {
- boolean badData = false;
-
- //
- // Coordinates are required
- //
- if (coordinates == null) {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo3"));
- }
-
- //
- // Check for indices with no data
- //
- if ((colors3 == null) && (colors4 == null) && (colorIndices != null))
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo4"));
- if ((normals == null) && (normalIndices != null))
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo11"));
-
- //
- // Make sure all TextureCoordinate data is set (indices or not)
- //
- for (int i = 0 ; i < texCoordSetCount ; i++) {
- if (texCoordSets[i] == null)
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo10"));
- }
-
- //
- // Check for Missing Index lists
- //
- boolean texInds = false; // Indicates whether we have texcoord indices
- if (texCoordIndexSets != null) {
- for (int i = 0 ; i < texCoordSetCount ; i++) {
- if (texCoordIndexSets[i] != null) texInds = true;
- }
- }
- if ((coordinateIndices != null) ||
- (colorIndices != null) ||
- (normalIndices != null) ||
- texInds) {
- // At least one index list is present, so they all must be
- // present (unless coordOnly)
- if (coordinateIndices == null) badData = true;
- else if (coordOnly) {
- if ((colorIndices != null) ||
- (normalIndices != null) ||
- (texInds == true)) {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo20"));
- }
- } else if (((colors3 != null) || (colors4 != null)) &&
- (colorIndices == null)) badData = true;
- else if ((normals != null) && (normalIndices == null)) badData = true;
- else if ((texCoordSetCount > 0) && !texInds) badData = true;
- if (badData) throw new
- IllegalArgumentException(J3dUtilsI18N.getString("GeometryInfo19"));
- }
-
- //
- // Make sure index lists are all the same length
- //
- if ((coordinateIndices != null) && (!coordOnly)) {
- if (((colors3 != null) || (colors4 != null)) &&
- (colorIndices.length != coordinateIndices.length))
- badData = true;
- else if ((normals != null) &&
- (normalIndices.length != coordinateIndices.length))
- badData = true;
- else {
- //Check all texCoord indices have the same length
- for (int i = 0 ; i < texCoordSetCount ; i++) {
- if (texCoordIndexSets[i].length != coordinateIndices.length) {
- badData = true;
- break;
- }
- }
- }
- if (badData) {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo5"));
- }
- }
-
- //
- // For stripped primitives, make sure we have strip counts
- //
- if ((prim == TRIANGLE_STRIP_ARRAY) ||
- (prim == TRIANGLE_FAN_ARRAY) ||
- (prim == POLYGON_ARRAY)) {
- if (stripCounts == null) badData = true;
- } else if (stripCounts != null) badData = true;
- if (badData) {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo6"));
- }
-
- // Find out how much data we have
- int count;
- if (coordinateIndices == null) count = coordinates.length;
- else count = coordinateIndices.length;
-
- //
- // Make sure sum of strip counts equals indexCount (or vertexCount)
- // and check to make sure triangles and quads have the right number
- // of vertices
- //
- if ((prim == TRIANGLE_STRIP_ARRAY) ||
- (prim == TRIANGLE_FAN_ARRAY) ||
- (prim == POLYGON_ARRAY)) {
- int sum = 0;
- for (int i = 0 ; i < stripCounts.length ; i++) {
- sum += stripCounts[i];
- }
- if (sum != count) {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo7"));
- }
- } else if (prim == TRIANGLE_ARRAY) {
- if (count % 3 != 0) {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo12"));
- }
- } else if (prim == QUAD_ARRAY) {
- if (count % 4 != 0) {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo13"));
- }
- }
-
- //
- // For polygons, make sure the contours add up.
- //
- if (prim == POLYGON_ARRAY) {
- if (contourCounts != null) {
- int c = 0;
- for (int i = 0 ; i < contourCounts.length ; i++)
- c += contourCounts[i];
- if (c != stripCounts.length) {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo8"));
- }
- }
- } else {
- if (contourCounts != null) {
- throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfo14"));
- }
- }
- } // End of checkForBadData
-
-
-
- /**
- * Get rid of index lists by reorganizing data into an un-indexed
- * format. Does nothing if no index lists are set.
- * @throws IllegalArgumentException if coordinate data is missing,
- * if the index lists aren't all the
- * same length, if an index list is set and the corresponding data
- * list isn't set, if a data list is set and the corresponding
- * index list is unset (unless all index lists are unset or in
- * USE_COORD_INDEX_ONLY format),
- * if StripCounts or ContourCounts is inconsistent with the current
- * primitive, if the sum of the contourCounts array doesn't equal
- * the length of the StripCounts array, or if the number of vertices
- * isn't a multiple of three (for triangles) or four (for quads).
- */
- public void unindexify() {
- checkForBadData();
- if (coordinateIndices != null) {
- // Switch from USE_COORD_INDEX_ONLY format
- if (coordOnly) indexify(false);
-
- coordinates =
- (Point3f[])unindexifyData(coordinates, coordinateIndices);
- coordinateIndices = null;
-
- if (colors3 != null) {
- colors3 = (Color3f[])unindexifyData(colors3, colorIndices);
- } else if (colors4 != null) {
- colors4 = (Color4f[])unindexifyData(colors4, colorIndices);
- }
- colorIndices = null;
-
- if (normals != null) {
- normals = (Vector3f[])unindexifyData(normals, normalIndices);
- normalIndices = null;
- }
-
- for (int i = 0 ; i < texCoordSetCount ; i++)
- texCoordSets[i] = unindexifyData(texCoordSets[i],
- texCoordIndexSets[i]);
- texCoordIndexSets = new int[texCoordSetCount][];
- }
- } // End of unindexify
-
-
-
- /**
- * Generic unindexify method. Can unindex data in any of the following
- * formats Point3f, Color3f, Color4f, Vector3f, TexCoord2f, TexCoord3f,
- * TexCoord4f.
- */
- private Object[] unindexifyData(Object data[], int index[])
- {
- Object newData[] = allocateArray(data, index.length);
- for (int i = 0 ; i < index.length ; i++) {
- newData[i] = data[index[i]];
- }
- return newData;
- } // End of unindexifyData
-
-
-
- /**
- * Calculate vertexFormat based on data.
- */
- private int getVertexFormat()
- {
- int vertexFormat = GeometryArray.COORDINATES;
-
- if (colors3 != null) vertexFormat |= GeometryArray.COLOR_3;
- else if (colors4 != null) vertexFormat |= GeometryArray.COLOR_4;
-
- if (normals != null) vertexFormat |= GeometryArray.NORMALS;
-
- if (texCoordDim == 2)
- vertexFormat |= GeometryArray.TEXTURE_COORDINATE_2;
- else if (texCoordDim == 3)
- vertexFormat |= GeometryArray.TEXTURE_COORDINATE_3;
- else if (texCoordDim == 4)
- vertexFormat |= GeometryArray.TEXTURE_COORDINATE_4;
-
- return vertexFormat;
- } // End of getVertexFormat
-
-
-
- /**
- * Calculate vertexCount based on data
- */
- private int getVertexCount()
- {
- int vertexCount = coordinates.length;
-
- if (colors3 != null) {
- if (colors3.length > vertexCount) vertexCount = colors3.length;
- } else if (colors4 != null) {
- if (colors4.length > vertexCount) vertexCount = colors4.length;
- }
-
- if (normals != null) {
- if (normals.length > vertexCount) vertexCount = normals.length;
- }
-
- // Find max length tex coord set
- for (int i = 0 ; i < texCoordSetCount ; i++) {
- if (texCoordSets[i].length > vertexCount)
- vertexCount = texCoordSets[i].length;
- }
-
- return vertexCount;
- } // End of getVertexCount
-
-
-
- /**
- * Converts an array of Tuple2f, Tuple3f, or Tuple4f values into
- * an array of floats. Assumes array is not null. Returns null
- * if array is not Tuple2f, Tuple3f, or Tuple4f. Used by fillIn()
- * for BY_REFERENCE not INTERLEAVED geometry.
- */
- private float[] vecmathToFloat(Object[] ar)
- {
- if (ar[0] instanceof Tuple2f) {
- float[] p = new float[ar.length * 2];
- Tuple2f[] a = (Tuple2f[])ar;
- for (int i = 0 ; i < ar.length ; i++) {
- p[i * 2] = a[i].x;
- p[i * 2 + 1] = a[i].y;
- }
- return p;
- } else if (ar[0] instanceof Tuple3f) {
- float[] p = new float[ar.length * 3];
- Tuple3f[] a = (Tuple3f[])ar;
- for (int i = 0 ; i < ar.length ; i++) {
- p[i * 3] = a[i].x;
- p[i * 3 + 1] = a[i].y;
- p[i * 3 + 2] = a[i].z;
- }
- return p;
- } else if (ar[0] instanceof Tuple4f) {
- float[] p = new float[ar.length * 4];
- Tuple4f[] a = (Tuple4f[])ar;
- for (int i = 0 ; i < ar.length ; i++) {
- p[i * 4] = a[i].x;
- p[i * 4 + 1] = a[i].y;
- p[i * 4 + 2] = a[i].z;
- p[i * 4 + 3] = a[i].w;
- }
- return p;
- }
- return null;
- } // End of vecmathToFloat
-
-
-
- /**
- * Fill in the GeometryArray object. Used by getGeometryArray and
- * getIndexedGeometryArray. checkForBadData has already been called.
- */
- private void fillIn(GeometryArray ga, boolean byRef, boolean interleaved,
- boolean nio)
- {
- if (interleaved) {
- // Calculate number of words per vertex
- int wpv = 3; // Always have coordinate data
- if (normals != null) wpv += 3;
- if (colors3 != null) wpv += 3;
- else if (colors4 != null) wpv += 4;
- wpv += (texCoordSetCount * texCoordDim);
-
- // Build array of interleaved data
- float[] d = new float[wpv * coordinates.length];
-
- // Fill in the array
- int offset = 0;
- for (int i = 0 ; i < coordinates.length ; i++) {
- if (texCoordDim == 2) {
- for (int j = 0 ; j < texCoordSetCount ; j++) {
- d[offset++] = ((TexCoord2f)texCoordSets[j][i]).x;
- d[offset++] = ((TexCoord2f)texCoordSets[j][i]).y;
- }
- } else if (texCoordDim == 3) {
- for (int j = 0 ; j < texCoordSetCount ; j++) {
- d[offset++] = ((TexCoord3f)texCoordSets[j][i]).x;
- d[offset++] = ((TexCoord3f)texCoordSets[j][i]).y;
- d[offset++] = ((TexCoord3f)texCoordSets[j][i]).z;
- }
- } else if (texCoordDim == 4) {
- for (int j = 0 ; j < texCoordSetCount ; j++) {
- d[offset++] = ((TexCoord4f)texCoordSets[j][i]).x;
- d[offset++] = ((TexCoord4f)texCoordSets[j][i]).y;
- d[offset++] = ((TexCoord4f)texCoordSets[j][i]).z;
- d[offset++] = ((TexCoord4f)texCoordSets[j][i]).w;
- }
- }
-
- if (colors3 != null) {
- d[offset++] = colors3[i].x;
- d[offset++] = colors3[i].y;
- d[offset++] = colors3[i].z;
- } else if (colors4 != null) {
- d[offset++] = colors4[i].x;
- d[offset++] = colors4[i].y;
- d[offset++] = colors4[i].z;
- d[offset++] = colors4[i].w;
- }
-
- if (normals != null) {
- d[offset++] = normals[i].x;
- d[offset++] = normals[i].y;
- d[offset++] = normals[i].z;
- }
-
- d[offset++] = coordinates[i].x;
- d[offset++] = coordinates[i].y;
- d[offset++] = coordinates[i].z;
- }
- // Register reference to array of interleaved data
- if (nio) {
- ByteBuffer b = ByteBuffer.allocateDirect(d.length * 4);
- FloatBuffer f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
- f.put(d);
- ga.setInterleavedVertexBuffer(new J3DBuffer(f));
- } else ga.setInterleavedVertices(d);
- } else if (nio) {
-
- ByteBuffer b = ByteBuffer.allocateDirect(coordinates.length * 4 * 3);
- FloatBuffer f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
- f.put(vecmathToFloat(coordinates));
- ga.setCoordRefBuffer(new J3DBuffer(f));
-
- if (colors3 != null) {
- b = ByteBuffer.allocateDirect(colors3.length * 4 * 3);
- f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
- f.put(vecmathToFloat(colors3));
- ga.setColorRefBuffer(new J3DBuffer(f));
- } else if (colors4 != null) {
- b = ByteBuffer.allocateDirect(colors4.length * 4 * 4);
- f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
- f.put(vecmathToFloat(colors4));
- ga.setColorRefBuffer(new J3DBuffer(f));
- }
-
- if (normals != null) {
- b = ByteBuffer.allocateDirect(normals.length * 4 * 3);
- f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
- f.put(vecmathToFloat(normals));
- ga.setNormalRefBuffer(new J3DBuffer(f));
- }
-
- for (int i = 0 ; i < texCoordSetCount ; i++) {
- b = ByteBuffer.allocateDirect(texCoordSets[i].length * 4 * texCoordDim);
- f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
- f.put(vecmathToFloat(texCoordSets[i]));
- ga.setTexCoordRefBuffer(i, new J3DBuffer(f));
- }
- } else if (byRef) {
- // Need to copy the data into float arrays - GeometryArray
- // prefers them over the vecmath types
- ga.setCoordRefFloat(vecmathToFloat(coordinates));
- if (colors3 != null) ga.setColorRefFloat(vecmathToFloat(colors3));
- else if (colors4 != null) ga.setColorRefFloat(vecmathToFloat(colors4));
- if (normals != null) ga.setNormalRefFloat(vecmathToFloat(normals));
- for (int i = 0 ; i < texCoordSetCount ; i++) {
- ga.setTexCoordRefFloat(i, vecmathToFloat(texCoordSets[i]));
- }
- } else {
- ga.setCoordinates(0, coordinates);
- if (colors3 != null) ga.setColors(0, colors3);
- else if (colors4 != null) ga.setColors(0, colors4);
- if (normals != null) ga.setNormals(0, normals);
- for (int i = 0 ; i < texCoordSetCount ; i++) {
- if (texCoordDim == 2) {
- ga.setTextureCoordinates(i, 0, (TexCoord2f[])texCoordSets[i]);
- } else if (texCoordDim == 3) {
- ga.setTextureCoordinates(i, 0, (TexCoord3f[])texCoordSets[i]);
- } else if (texCoordDim == 4) {
- ga.setTextureCoordinates(i, 0, (TexCoord4f[])texCoordSets[i]);
- }
- }
- }
-
- if (coordinateIndices != null) {
- IndexedGeometryArray iga = null;
- iga = (IndexedGeometryArray)ga;
- iga.setCoordinateIndices(0, coordinateIndices);
- if (!coordOnly) {
- if (colorIndices != null) iga.setColorIndices(0, colorIndices);
- if (normalIndices != null) iga.setNormalIndices(0, normalIndices);
- for (int i = 0 ; i < texCoordSetCount ; i++)
- iga.setTextureCoordinateIndices(i, 0, texCoordIndexSets[i]);
- }
- }
- } // End of fillIn
-
-
-
- /**
- * Redo indexes to guarantee connection information.
- * Use this routine if your original data is in indexed format, but
- * you don't trust that the indexing is correct. After this
- * routine it is guaranteed that two points with the same
- * position will have the same coordinate index (for example).
- * Try this if you see
- * glitches in your normals or stripification, to rule out
- * bad indexing as the source of the problem. Works with normal
- * indexed format or USE_COORD_INDEX_ONLY format.
- * @throws IllegalArgumentException if coordinate data is missing,
- * if the index lists aren't all the
- * same length, if an index list is set and the corresponding data
- * list isn't set, if a data list is set and the corresponding
- * index list is unset (unless all index lists are unset or in
- * USE_COORD_INDEX_ONLY format),
- * if StripCounts or ContourCounts is inconsistent with the current
- * primitive, if the sum of the contourCounts array doesn't equal
- * the length of the StripCounts array, or if the number of vertices
- * isn't a multiple of three (for triangles) or four (for quads).
- */
- public void recomputeIndices()
- {
- boolean remember = coordOnly;
-
- // Can make more efficient implementation later
- unindexify();
- indexify(remember);
- } // End of recomputeIndices
-
-
-
- /**
- * Reverse the order of an array of ints (computer class homework
- * problem).
- */
- private void reverseList(int list[])
- {
- int t;
-
- if (list == null) return;
-
- for (int i = 0 ; i < list.length / 2 ; i++) {
- t = list[i];
- list[i] = list[list.length - i - 1];
- list[list.length - i - 1] = t;
- }
- } // End of reverseList
-
-
-
- /**
- * Reverse the order of all lists. If your polygons are formatted with
- * clockwise winding, you will always see the back and never the front.
- * (Java 3D always wants vertices specified with a counter-clockwise
- * winding.)
- * This method will (in effect) reverse the winding of your data by
- * inverting all of the index lists and the stripCounts
- * and contourCounts lists.
- * @throws IllegalArgumentException if coordinate data is missing,
- * if the index lists aren't all the
- * same length, if an index list is set and the corresponding data
- * list isn't set, if a data list is set and the corresponding
- * index list is unset (unless all index lists are unset or in
- * USE_COORD_INDEX_ONLY format),
- * if StripCounts or ContourCounts is inconsistent with the current
- * primitive, if the sum of the contourCounts array doesn't equal
- * the length of the StripCounts array, or if the number of vertices
- * isn't a multiple of three (for triangles) or four (for quads).
- */
- public void reverse()
- {
- indexify();
- reverseList(stripCounts);
- reverseList(oldStripCounts);
- reverseList(contourCounts);
- reverseList(coordinateIndices);
- reverseList(colorIndices);
- reverseList(normalIndices);
- for (int i = 0 ; i < texCoordSetCount ; i++)
- reverseList(texCoordIndexSets[i]);
- } // End of reverse
-
-
-
- /**
- * Returns true if the data in this GeometryInfo is currently
- * formatted in the USE_COORD_INDEX_ONLY format where a single
- * index list is used to index into all data lists.
- * @see GeometryInfo#indexify(boolean)
- * @see GeometryInfo#getIndexedGeometryArray(boolean, boolean, boolean,
- * boolean, boolean)
- */
- public boolean getUseCoordIndexOnly()
- {
- return coordOnly;
- } // End of getUseCoordIndexOnly
-
-
-
- /**
- * Tells the GeometryInfo that its data is formatted in the
- * USE_COORD_INDEX_ONLY format with a single index list
- * (the coordinate index list) that indexes into all data
- * lists (coordinates, normals, colors, and texture
- * coordinates). NOTE: this will not convert the data
- * for you. This method is for when you are sending in
- * data useng the setCoordinates, setNormals, setColors,
- * and/or setTextureCoordinates methods, and you are only
- * setting one index using setCoordinateIndices(). If
- * you want GeometryInfo to convert your data to the
- * USE_COORD_INDEX_ONLY format, use indexify(true) or
- * getIndexedGeometryArray with the useCoordIndexOnly
- * parameter set to true.
- * @see GeometryInfo#indexify(boolean)
- * @see GeometryInfo#getIndexedGeometryArray(boolean, boolean, boolean,
- * boolean, boolean)
- */
- public void setUseCoordIndexOnly(boolean useCoordIndexOnly)
- {
- coordOnly = useCoordIndexOnly;
- } // End of setUseCoordIndexOnly
-
-
-
- /**
- * Creates and returns a non-indexed Java 3D GeometryArray object
- * based on the data in the GeometryInfo object. This object is
- * suitable to be attached to a Shape3D node for rendering.
- * @param byRef Use geometry BY_REFERENCE
- * @param interleaved Use INTERLEAVED geometry. Implies byRef is
- * true as well.
- * @param nio Create GeometryArray using java.nio.Buffer for
- * geometry arrays. Only usable on JDK 1.4 or higher. Implies
- * byRef is true as well.
- * @throws IllegalArgumentException if coordinate data is missing,
- * if the index lists aren't all the
- * same length, if an index list is set and the corresponding data
- * list isn't set, if a data list is set and the corresponding
- * index list is unset (unless all index lists are unset or in
- * USE_COORD_INDEX_ONLY format),
- * if StripCounts or ContourCounts is inconsistent with the current
- * primitive, if the sum of the contourCounts array doesn't equal
- * the length of the StripCounts array, or if the number of vertices
- * isn't a multiple of three (for triangles) or four (for quads).
- */
- public GeometryArray getGeometryArray(boolean byRef, boolean interleaved,
- boolean nio)
- {
- checkForBadData();
-
- if (prim == POLYGON_ARRAY) {
- if (tr == null) tr = new Triangulator();
- tr.triangulate(this);
- } else changeBackToOldPrim();
-
- unindexify();
-
- int vertexFormat = getVertexFormat();
- if (nio) vertexFormat |= (GeometryArray.BY_REFERENCE |
- GeometryArray.USE_NIO_BUFFER);
- if (interleaved) vertexFormat |= (GeometryArray.BY_REFERENCE |
- GeometryArray.INTERLEAVED);
- if (byRef) vertexFormat |= GeometryArray.BY_REFERENCE;
-
- int vertexCount = coordinates.length;
-
- // If the texCoordSetMap hasn't been set, assume one set of
- // texture coordinates only and one texture state unit
- if ((texCoordSetCount > 0) && (texCoordSetMap == null)) {
- texCoordSetCount = 1;
- texCoordSetMap = new int[1];
- texCoordSetMap[0] = 0;
- }
-
- // Create the GeometryArray object
- GeometryArray ga = null;
- switch (prim) {
- case TRIANGLE_ARRAY:
- TriangleArray ta = new TriangleArray(vertexCount, vertexFormat,
- texCoordSetCount, texCoordSetMap);
- ga = (GeometryArray)ta;
- break;
-
- case QUAD_ARRAY:
- QuadArray qa = new QuadArray(vertexCount, vertexFormat,
- texCoordSetCount, texCoordSetMap);
- ga = (GeometryArray)qa;
- break;
-
- case TRIANGLE_STRIP_ARRAY:
- TriangleStripArray tsa = new TriangleStripArray(vertexCount,
- vertexFormat, texCoordSetCount, texCoordSetMap,
- stripCounts);
- ga = (GeometryArray)tsa;
- break;
-
- case TRIANGLE_FAN_ARRAY:
- TriangleFanArray tfa = new TriangleFanArray(vertexCount,
- vertexFormat, texCoordSetCount, texCoordSetMap,
- stripCounts);
- ga = (GeometryArray)tfa;
- break;
- }
-
- fillIn(ga, byRef, interleaved, nio);
-
- return ga;
- } // End of getGeometryArray(int, int)
-
-
-
- /**
- * Creates and returns a non-indexed Java 3D GeometryArray object
- * based on the data in the GeometryInfo object. This object is
- * suitable to be attached to a Shape3D node for rendering.
- * The geometry is not created using data BY_REFERENCE,
- * INTERLEAVED, or USE_NIO_BUFFER.
- * @throws IllegalArgumentException if coordinate data is missing,
- * if the index lists aren't all the
- * same length, if an index list is set and the corresponding data
- * list isn't set, if a data list is set and the corresponding
- * index list is unset (unless all index lists are unset or in
- * USE_COORD_INDEX_ONLY format),
- * if StripCounts or ContourCounts is inconsistent with the current
- * primitive, if the sum of the contourCounts array doesn't equal
- * the length of the StripCounts array, or if the number of vertices
- * isn't a multiple of three (for triangles) or four (for quads).
- */
- public GeometryArray getGeometryArray()
- {
- return getGeometryArray(false, false, false);
- } // End of getGeometryArray()
-
-
-
- /**
- * Creates and returns a IndexedGeometryArray
- * based on the data in the GeometryInfo object. This object is
- * suitable to be attached to a Shape3D node for rendering.
- * @param compact Remove Coordinates, Colors, Normals, and
- * TextureCoordinates that aren't referenced by any indices.
- * @param byRef Create the IndexedGeometryArray using geometry
- * BY_REFERENCE.
- * @param interleaved Use INTERLEAVED geometry. Implies byRef is
- * true as well.
- * @param useCoordIndexOnly Create the IndexedGeometryArray using
- * USE_COORD_INDEX_ONLY. Values from the coordinate index array
- * are used as a single set of indices into all vertex
- * component arrays (coord, color, normal, and texCoord).
- * @param nio Create GeometryArray using java.nio.Buffer for
- * geometry arrays. Only usable on JDK 1.4 or higher. Implies
- * byRef is true as well.
- * @throws IllegalArgumentException if coordinate data is missing,
- * if the index lists aren't all the
- * same length, if an index list is set and the corresponding data
- * list isn't set, if a data list is set and the corresponding
- * index list is unset (unless all index lists are unset or in
- * USE_COORD_INDEX_ONLY format),
- * if StripCounts or ContourCounts is inconsistent with the current
- * primitive, if the sum of the contourCounts array doesn't equal
- * the length of the StripCounts array, or if the number of vertices
- * isn't a multiple of three (for triangles) or four (for quads).
- */
- public IndexedGeometryArray getIndexedGeometryArray(boolean compact,
- boolean byRef,
- boolean interleaved,
- boolean useCoordIndexOnly,
- boolean nio)
- {
- indexify(useCoordIndexOnly);
-
- if (compact) compact();
-
- if (prim == POLYGON_ARRAY) {
- if (tr == null) tr = new Triangulator();
- tr.triangulate(this);
- } else changeBackToOldPrim();
-
- if (useCoordIndexOnly && coordOnly == false) {
- // Check to see if we can optimize for USE_COORD_INDEX_ONLY
- int i, j;
- boolean canUseCoordIndexOnly = true;
-
- if (coordinateIndices != null) {
- // See if all the array lengths are the same
- if (colorIndices != null &&
- colorIndices.length != coordinateIndices.length) {
- canUseCoordIndexOnly = false;
- }
- if (normalIndices != null &&
- normalIndices.length != coordinateIndices.length) {
- canUseCoordIndexOnly = false;
- }
- for (i = 0 ; i < texCoordSetCount ; i++) {
- if (texCoordIndexSets[i] != null &&
- texCoordIndexSets[i].length != coordinateIndices.length) {
- canUseCoordIndexOnly = false;
- break;
- }
- }
- if (canUseCoordIndexOnly &&
- ((colorIndices != null) ||
- (normalIndices != null) ||
- (texCoordSetCount > 0))) {
- // All array lengths are the same. Check their contents
-
- for (i=0; igetIndexedGeometryArray(compact, false,
- * false, false, false)
.
- * @param compact Remove Coordinates, Colors, Normals, and
- * TextureCoordinates that aren't referenced by any indices.
- * @throws IllegalArgumentException if coordinate data is missing,
- * if the index lists aren't all the
- * same length, if an index list is set and the corresponding data
- * list isn't set, if a data list is set and the corresponding
- * index list is unset (unless all index lists are unset or in
- * USE_COORD_INDEX_ONLY format),
- * if StripCounts or ContourCounts is inconsistent with the current
- * primitive, if the sum of the contourCounts array doesn't equal
- * the length of the StripCounts array, or if the number of vertices
- * isn't a multiple of three (for triangles) or four (for quads).
- */
- public IndexedGeometryArray getIndexedGeometryArray(boolean compact)
- {
- return getIndexedGeometryArray(compact, false, false, false, false);
- } // End of getIndexedGeometryArray(boolean)
-
-
-
- /**
- * Creates and returns an IndexedGeometryArray
- * based on the data in the GeometryInfo object. This object is
- * suitable to be attached to a Shape3D node for rendering.
- * Equivalent to getIndexedGeometryArray(false, false,
- * false, false, false)
.
- * @throws IllegalArgumentException if coordinate data is missing,
- * if the index lists aren't all the
- * same length, if an index list is set and the corresponding data
- * list isn't set, if a data list is set and the corresponding
- * index list is unset (unless all index lists are unset or in
- * USE_COORD_INDEX_ONLY format),
- * if StripCounts or ContourCounts is inconsistent with the current
- * primitive, if the sum of the contourCounts array doesn't equal
- * the length of the StripCounts array, or if the number of vertices
- * isn't a multiple of three (for triangles) or four (for quads).
- */
- public IndexedGeometryArray getIndexedGeometryArray()
- {
- return getIndexedGeometryArray(false, false, false, false, false);
- } // End of getIndexedGeometryArray()
-
-} // End of class GeometryInfo
-
-// End of file GeometryInfo.java
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfoGenerator.java b/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfoGenerator.java
deleted file mode 100644
index e0178b7..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/GeometryInfoGenerator.java
+++ /dev/null
@@ -1,862 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry;
-
-import java.nio.ByteBuffer;
-import java.nio.DoubleBuffer;
-import java.nio.FloatBuffer;
-
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.GeometryStripArray;
-import javax.media.j3d.IndexedGeometryArray;
-import javax.media.j3d.IndexedGeometryStripArray;
-import javax.media.j3d.IndexedQuadArray;
-import javax.media.j3d.IndexedTriangleArray;
-import javax.media.j3d.IndexedTriangleFanArray;
-import javax.media.j3d.IndexedTriangleStripArray;
-import javax.media.j3d.J3DBuffer;
-import javax.media.j3d.QuadArray;
-import javax.media.j3d.TriangleArray;
-import javax.media.j3d.TriangleFanArray;
-import javax.media.j3d.TriangleStripArray;
-import javax.vecmath.Color3b;
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4b;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3d;
-import javax.vecmath.Point3f;
-import javax.vecmath.TexCoord2f;
-import javax.vecmath.TexCoord3f;
-import javax.vecmath.TexCoord4f;
-import javax.vecmath.Vector3f;
-
-import com.sun.j3d.internal.BufferWrapper;
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-
-
-/**
- * Populate a GeometryInfo object from the Geometry provided. Used
- * by GeometryInfo.
- */
-class GeometryInfoGenerator extends Object {
-
- public static void create(GeometryInfo geomInfo, GeometryArray geomArray)
- {
- if (geomArray instanceof GeometryStripArray)
- create(geomInfo, (GeometryStripArray)geomArray);
- else if (geomArray instanceof TriangleArray) {
- geomInfo.reset(GeometryInfo.TRIANGLE_ARRAY);
- processGeometryArray(geomInfo, geomArray);
- } else if (geomArray instanceof QuadArray) {
- geomInfo.reset(GeometryInfo.QUAD_ARRAY);
- processGeometryArray(geomInfo, geomArray);
- } else if (geomArray instanceof IndexedGeometryArray)
- create(geomInfo, (IndexedGeometryArray)geomArray);
- else throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfoGenerator0"));
- } // End of create(GeometryInfo, GeometryArray)
-
-
-
- private static void create(GeometryInfo geomInfo,
- GeometryStripArray geomArray)
- {
- if (geomArray instanceof TriangleFanArray) {
- geomInfo.reset(GeometryInfo.TRIANGLE_FAN_ARRAY);
- } else if (geomArray instanceof TriangleStripArray) {
- geomInfo.reset(GeometryInfo.TRIANGLE_STRIP_ARRAY);
- } else throw new IllegalArgumentException(
- J3dUtilsI18N.getString("GeometryInfoGenerator0"));
-
- processGeometryArray(geomInfo, geomArray);
- processStripArray(geomInfo, geomArray);
- } // End of create(GeometryInfo, GeometryStripArray)
-
-
-
- private static void create(GeometryInfo geomInfo,
- IndexedGeometryArray geomArray)
- {
- if (geomArray instanceof IndexedQuadArray) {
- geomInfo.reset(GeometryInfo.QUAD_ARRAY);
- } else if (geomArray instanceof IndexedTriangleArray) {
- geomInfo.reset(GeometryInfo.TRIANGLE_ARRAY);
- } else if (geomArray instanceof IndexedTriangleFanArray) {
- geomInfo.reset(GeometryInfo.TRIANGLE_FAN_ARRAY);
- processIndexStripArray(geomInfo, (IndexedGeometryStripArray)geomArray);
- } else if (geomArray instanceof IndexedTriangleStripArray) {
- geomInfo.reset(GeometryInfo.TRIANGLE_STRIP_ARRAY);
- processIndexStripArray(geomInfo, (IndexedGeometryStripArray)geomArray);
- }
-
- processGeometryArray(geomInfo, geomArray);
- processIndexedArray(geomInfo, geomArray);
- } // End of create(GeometryInfo, IndexedGeometryArray)
-
-
-
- private static void processGeometryArray(GeometryInfo geomInfo,
- GeometryArray geomArray)
- {
- int i, j;
- int vertexFormat = geomArray.getVertexFormat();
- int texSets = geomArray.getTexCoordSetCount();
- int valid;
-
- // Calculate validVertexCount
- if (geomArray instanceof GeometryStripArray) {
- // Does not include IndexedGeometryStripArray
- GeometryStripArray gsa = (GeometryStripArray)geomArray;
- int[] strips = new int[gsa.getNumStrips()];
- gsa.getStripVertexCounts(strips);
- valid = 0;
- for (i = 0 ; i < strips.length ; i++) {
- valid += strips[i];
- }
- } else if (geomArray instanceof IndexedGeometryArray) {
- valid = geomArray.getVertexCount();
- } else valid = geomArray.getValidVertexCount();
-
- if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) {
-
- // Calculate words_per_vertex (wpv)
- int wpv = 3; // Always have coordinate data
- if ((vertexFormat & GeometryArray.NORMALS) != 0) wpv += 3;
- if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4)
- wpv += 4;
- else if ((vertexFormat & GeometryArray.COLOR_3) != 0) wpv += 3;
- if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0)
- wpv += 2 * texSets;
- else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0)
- wpv += 3 * texSets;
- else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0)
- wpv += 4 * texSets;
-
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialVertexIndex();
- } else initial = 0;
-
- float[] d;
- if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) {
- J3DBuffer b = geomArray.getInterleavedVertexBuffer();
- FloatBuffer w = (FloatBuffer)b.getBuffer();
- d = new float[w.limit()];
- w.position( 0 );
- w.get(d);
- } else d = geomArray.getInterleavedVertices();
-
- int offset = 0;
- if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
- geomInfo.setTextureCoordinateParams(texSets, 2);
- int[] map = new int[geomArray.getTexCoordSetMapLength()];
- geomArray.getTexCoordSetMap(map);
- geomInfo.setTexCoordSetMap(map);
- for (i = 0 ; i < texSets ; i++) {
- TexCoord2f[] tex = new TexCoord2f[valid];
- for (j = 0 ; j < valid ; j++) {
- tex[j] = new TexCoord2f(d[wpv * (j + initial) + offset],
- d[wpv * (j + initial) + offset + 1]);
- }
- geomInfo.setTextureCoordinates(i, tex);
- offset += 2;
- }
- } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
- geomInfo.setTextureCoordinateParams(texSets, 3);
- int[] map = new int[geomArray.getTexCoordSetMapLength()];
- geomArray.getTexCoordSetMap(map);
- geomInfo.setTexCoordSetMap(map);
- for (i = 0 ; i < texSets ; i++) {
- TexCoord3f[] tex = new TexCoord3f[valid];
- for (j = 0 ; j < valid ; j++) {
- tex[j] = new TexCoord3f(d[wpv * (j + initial) + offset],
- d[wpv * (j + initial) + offset + 1],
- d[wpv * (j + initial) + offset + 2]);
- }
- geomInfo.setTextureCoordinates(i, tex);
- offset += 3;
- }
- } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
- geomInfo.setTextureCoordinateParams(texSets, 4);
- int[] map = new int[geomArray.getTexCoordSetMapLength()];
- geomArray.getTexCoordSetMap(map);
- geomInfo.setTexCoordSetMap(map);
- for (i = 0 ; i < texSets ; i++) {
- TexCoord4f[] tex = new TexCoord4f[valid];
- for (j = 0 ; j < valid ; j++) {
- tex[j] = new TexCoord4f(d[wpv * (j + initial) + offset],
- d[wpv * (j + initial) + offset + 1],
- d[wpv * (j + initial) + offset + 2],
- d[wpv * (j + initial) + offset + 3]);
- }
- geomInfo.setTextureCoordinates(i, tex);
- offset += 4;
- }
- }
-
- if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
- Color4f[] color = new Color4f[valid];
- for (i = 0 ; i < valid ; i++) {
- color[i] = new Color4f(d[wpv * (i + initial) + offset],
- d[wpv * (i + initial) + offset + 1],
- d[wpv * (i + initial) + offset + 2],
- d[wpv * (i + initial) + offset + 3]);
- }
- geomInfo.setColors(color);
- offset += 4;
- } else if ((vertexFormat & GeometryArray.COLOR_3) != 0) {
- Color3f[] color = new Color3f[valid];
- for (i = 0 ; i < valid ; i++) {
- color[i] = new Color3f(d[wpv * (i + initial) + offset],
- d[wpv * (i + initial) + offset + 1],
- d[wpv * (i + initial) + offset + 2]);
- }
- geomInfo.setColors(color);
- offset += 3;
- }
-
- if ((vertexFormat & GeometryArray.NORMALS) != 0) {
- Vector3f[] normals = new Vector3f[valid];
- for (i = 0 ; i < valid ; i++) {
- normals[i] = new Vector3f(d[wpv * (i + initial) + offset],
- d[wpv * (i + initial) + offset + 1],
- d[wpv * (i + initial) + offset + 2]);
- }
- geomInfo.setNormals(normals);
- offset += 3;
- }
-
- Point3f[] coords = new Point3f[valid];
- for (i = 0 ; i < valid ; i++) {
- coords[i] = new Point3f(d[wpv * (i + initial) + offset],
- d[wpv * (i + initial) + offset + 1],
- d[wpv * (i + initial) + offset + 2]);
- }
- geomInfo.setCoordinates(coords);
- } else {
- // Data is not INTERLEAVED
- boolean byRef = ((vertexFormat & GeometryArray.BY_REFERENCE) != 0 );
- boolean nio = ((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 );
-
- Point3f[] coords = null;
- if (byRef) {
-
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialCoordIndex();
- } else initial = 0;
-
- if ( nio ) {
- J3DBuffer buf = geomArray.getCoordRefBuffer();
-
- switch (BufferWrapper.getBufferType(buf)) {
-
- case BufferWrapper.TYPE_FLOAT: {
- FloatBuffer bb = (FloatBuffer)buf.getBuffer();
- float[] c = new float[valid * 3];
- bb.position(initial * 3);
- bb.get(c, 0, valid * 3);
- coords = new Point3f[valid];
- for (i = 0 ; i < valid ; i++) {
- coords[i] = new Point3f(c[i * 3 + 0],
- c[i * 3 + 1],
- c[i * 3 + 2]);
- }
- }
- break;
-
- case BufferWrapper.TYPE_DOUBLE: {
- DoubleBuffer bb = (DoubleBuffer)buf.getBuffer();
- double[] c = new double[valid * 3];
- bb.position(initial * 3);
- bb.get(c, 0, valid * 3);
- coords = new Point3f[valid];
- for (i = 0 ; i < valid ; i++) {
- coords[i] = new Point3f((float)(c[i * 3 + 0]),
- (float)(c[i * 3 + 1]),
- (float)(c[i * 3 + 2]));
- }
- }
- break;
- }
- } else if (geomArray.getCoordRef3f() != null) {
- if (initial != 0) {
- Point3f[] c = geomArray.getCoordRef3f();
- coords = new Point3f[valid];
- for (i = 0 ; i < valid ; i++) {
- coords[i] = new Point3f(c[i + initial]);
- }
- } else coords = geomArray.getCoordRef3f();
- } else if (geomArray.getCoordRef3d() != null) {
- Point3d[] c = geomArray.getCoordRef3d();
- coords = new Point3f[valid];
- for (i = 0 ; i < valid ; i++) {
- coords[i] = new Point3f(c[i + initial]);
- }
- } else if (geomArray.getCoordRefFloat() != null) {
- float[] c = geomArray.getCoordRefFloat();
- coords = new Point3f[valid];
- for (i = 0 ; i < valid ; i++) {
- coords[i] = new Point3f(c[(i + initial) * 3],
- c[(i + initial) * 3 + 1],
- c[(i + initial) * 3 + 2]);
- }
- } else if (geomArray.getCoordRefDouble() != null) {
- double[] c = geomArray.getCoordRefDouble();
- coords = new Point3f[valid];
- for (i = 0 ; i < valid ; i++) {
- coords[i] = new Point3f((float)(c[(i + initial) * 3]),
- (float)(c[(i + initial) * 3 + 1]),
- (float)(c[(i + initial) * 3 + 2]));
- }
- }
- // No coordinate data - let GeometryInfo handle this.
- } else {
- // Not BY_REFERENCE
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialVertexIndex();
- } else initial = 0;
- coords = new Point3f[valid];
- for (i = 0 ; i < valid ; i++) coords[i] = new Point3f();
- geomArray.getCoordinates(initial, coords);
- }
- geomInfo.setCoordinates(coords);
-
- if ((vertexFormat & GeometryArray.NORMALS) != 0) {
- Vector3f[] normals = null;
- if (byRef) {
-
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialNormalIndex();
- } else initial = 0;
-
- if ( nio ) {
- J3DBuffer buf = geomArray.getNormalRefBuffer();
-
- if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) {
- FloatBuffer bb = (FloatBuffer)buf.getBuffer();
- float[] c = new float[valid * 3];
- bb.position(initial * 3);
- bb.get(c, 0, valid * 3);
- normals = new Vector3f[valid];
- for (i = 0 ; i < valid ; i++) {
- normals[i] = new Vector3f(c[i * 3 + 0],
- c[i * 3 + 1],
- c[i * 3 + 2]);
- }
- }
- // Normals were set in vertexFormat but none were set - OK
- } else if (geomArray.getNormalRef3f() != null) {
- if (initial != 0) {
- Vector3f[] n = geomArray.getNormalRef3f();
- normals = new Vector3f[valid];
- for (i = 0 ; i < valid ; i++) {
- normals[i] = new Vector3f(n[i + initial]);
- }
- } else normals = geomArray.getNormalRef3f();
- } else if (geomArray.getNormalRefFloat() != null) {
- float[] n = geomArray.getNormalRefFloat();
- normals = new Vector3f[valid];
- for (i = 0 ; i < valid ; i++) {
- normals[i] = new Vector3f(n[(i + initial) * 3],
- n[(i + initial) * 3 + 1],
- n[(i + initial) * 3 + 2]);
- }
- }
- // Normals were set in vertexFormat but none were set - OK
- } else {
- // Not BY_REFERENCE
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialVertexIndex();
- } else initial = 0;
- normals = new Vector3f[valid];
- for (i = 0 ; i < valid ; i++) normals[i] = new Vector3f();
- geomArray.getNormals(initial, normals);
- }
- geomInfo.setNormals(normals);
- }
-
- if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
- Color4f[] colors = null;
- if (byRef) {
-
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialColorIndex();
- } else initial = 0;
-
- if ( nio ) {
- J3DBuffer buf = geomArray.getColorRefBuffer();
-
- switch (BufferWrapper.getBufferType(buf)) {
-
- case BufferWrapper.TYPE_FLOAT: {
- FloatBuffer bb = (FloatBuffer)buf.getBuffer();
- float[] c = new float[valid * 4];
- bb.position(initial * 4);
- bb.get(c, 0, valid * 4);
- colors = new Color4f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color4f(c[i * 4 + 0],
- c[i * 4 + 1],
- c[i * 4 + 2],
- c[i * 4 + 3]);
- }
- }
- break;
-
- case BufferWrapper.TYPE_BYTE: {
- ByteBuffer bb = (ByteBuffer)buf.getBuffer();
- byte[] c = new byte[valid * 4];
- bb.position(initial * 4);
- bb.get(c, 0, valid * 4);
- colors = new Color4f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color4f((float)(c[i * 4 + 0] & 0xff) / 255.0f,
- (float)(c[i * 4 + 1] & 0xff) / 255.0f,
- (float)(c[i * 4 + 2] & 0xff) / 255.0f,
- (float)(c[i * 4 + 3] & 0xff) / 255.0f);
- }
- }
- break;
- }
- } else if (geomArray.getColorRef4f() != null) {
- if (initial != 0) {
- Color4f[] c = geomArray.getColorRef4f();
- colors = new Color4f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color4f(c[i + initial]);
- }
- } else colors = geomArray.getColorRef4f();
- } else if (geomArray.getColorRefFloat() != null) {
- float[] c = geomArray.getColorRefFloat();
- colors = new Color4f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color4f(c[(i + initial) * 4 + 0],
- c[(i + initial) * 4 + 1],
- c[(i + initial) * 4 + 2],
- c[(i + initial) * 4 + 3]);
- }
- } else if (geomArray.getColorRefByte() != null) {
- byte[] c = geomArray.getColorRefByte();
- colors = new Color4f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color4f((float)(c[(i + initial) * 4 + 0] & 0xff) / 255.0f,
- (float)(c[(i + initial) * 4 + 1] & 0xff) / 255.0f,
- (float)(c[(i + initial) * 4 + 2] & 0xff) / 255.0f,
- (float)(c[(i + initial) * 4 + 3] & 0xff) / 255.0f);
- }
- } else if (geomArray.getColorRef4b() != null) {
- Color4b[] c = geomArray.getColorRef4b();
- colors = new Color4f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color4f((float)(c[i + initial].x & 0xff) / 255.0f,
- (float)(c[i + initial].y & 0xff) / 255.0f,
- (float)(c[i + initial].z & 0xff) / 255.0f,
- (float)(c[i + initial].w & 0xff) / 255.0f);
- }
- }
- // Colors4 were set in vertexFormat but none were set - OK
- } else {
- // Not BY_REFERENCE
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialVertexIndex();
- } else initial = 0;
- colors = new Color4f[valid];
- for (i = 0 ; i < valid ; i++) colors[i] = new Color4f();
- geomArray.getColors(initial, colors);
- }
- geomInfo.setColors(colors);
- } else if ((vertexFormat & GeometryArray.COLOR_3) != 0) {
- Color3f[] colors = null;
- if (byRef) {
-
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialColorIndex();
- } else initial = 0;
-
- if ( nio ) {
- J3DBuffer buf = geomArray.getColorRefBuffer();
-
- switch (BufferWrapper.getBufferType(buf)) {
-
- case BufferWrapper.TYPE_FLOAT: {
- FloatBuffer bb = (FloatBuffer)buf.getBuffer();
- float[] c = new float[valid * 3];
- bb.position(initial * 3);
- bb.get(c, 0, valid * 3);
- colors = new Color3f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color3f(c[i * 3 + 0],
- c[i * 3 + 1],
- c[i * 3 + 2]);
- }
- }
- break;
-
- case BufferWrapper.TYPE_BYTE: {
- ByteBuffer bb = (ByteBuffer)buf.getBuffer();
- byte[] c = new byte[valid * 3];
- bb.position(initial * 3);
- bb.get(c, 0, valid * 3);
- colors = new Color3f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color3f((float)(c[i * 3 + 0] & 0xff) / 255.0f,
- (float)(c[i * 3 + 1] & 0xff) / 255.0f,
- (float)(c[i * 3 + 2] & 0xff) / 255.0f);
- }
- }
- break;
- }
- } else if (geomArray.getColorRef3f() != null) {
- if (initial != 0) {
- Color3f[] c = geomArray.getColorRef3f();
- colors = new Color3f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color3f(c[i + initial]);
- }
- } else colors = geomArray.getColorRef3f();
- } else if (geomArray.getColorRefFloat() != null) {
- float[] c = geomArray.getColorRefFloat();
- colors = new Color3f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color3f(c[(i + initial) * 3 + 0],
- c[(i + initial) * 3 + 1],
- c[(i + initial) * 3 + 2]);
- }
- } else if (geomArray.getColorRefByte() != null) {
- byte[] c = geomArray.getColorRefByte();
- colors = new Color3f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color3f((float)(c[(i + initial) * 3 + 0] & 0xff) / 255.0f,
- (float)(c[(i + initial) * 3 + 1] & 0xff) / 255.0f,
- (float)(c[(i + initial) * 3 + 2] & 0xff) / 255.0f);
- }
- } else if (geomArray.getColorRef3b() != null) {
- Color3b[] c = geomArray.getColorRef3b();
- colors = new Color3f[valid];
- for (i = 0 ; i < valid ; i++) {
- colors[i] = new Color3f((float)(c[i + initial].x & 0xff) / 255.0f,
- (float)(c[i + initial].y & 0xff) / 255.0f,
- (float)(c[i + initial].z & 0xff) / 255.0f);
- }
- }
- // Colors3 were set in vertexFormat but none were set - OK
- } else {
- // Not BY_REFERENCE
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialVertexIndex();
- } else initial = 0;
- colors = new Color3f[valid];
- for (i = 0 ; i < valid ; i++) colors[i] = new Color3f();
- geomArray.getColors(initial, colors);
- }
- geomInfo.setColors(colors);
- }
-
- if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
- geomInfo.setTextureCoordinateParams(texSets, 4);
- for (i = 0 ; i < texSets ; i++) {
- TexCoord4f[] tex = null;
- if (byRef) {
-
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialTexCoordIndex(i);
- } else initial = 0;
-
- if (nio) {
- J3DBuffer buf = geomArray.getTexCoordRefBuffer(i);
-
- if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) {
- FloatBuffer bb = (FloatBuffer)buf.getBuffer();
- float[] c = new float[valid * 4];
- bb.position(initial * 4);
- bb.get(c, 0, valid * 4);
- tex = new TexCoord4f[valid];
- for (j = 0 ; j < valid ; j++) {
- tex[j] = new TexCoord4f(c[j * 4 + 0],
- c[j * 4 + 1],
- c[j * 4 + 2],
- c[j * 4 + 3]);
- }
- }
- // TexCoords4 were set in vertexFormat but none were set - OK
- } else {
- // There if no TexCoordRef4f, so we know it's float
- float[] t = geomArray.getTexCoordRefFloat(i);
- tex = new TexCoord4f[valid];
- for (j = 0 ; j < valid ; j++) {
- tex[j] = new TexCoord4f(t[(j + initial) * 4],
- t[(j + initial) * 4 + 1],
- t[(j + initial) * 4 + 2],
- t[(j + initial) * 4 + 3]);
- }
- }
- } else {
- // Not BY_REFERENCE
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialVertexIndex();
- } else initial = 0;
- tex = new TexCoord4f[valid];
- for (j = 0 ; j < valid ; j++) tex[j] = new TexCoord4f();
- geomArray.getTextureCoordinates(i, initial, tex);
- }
- geomInfo.setTextureCoordinates(i, tex);
- }
- int[] map = new int[geomArray.getTexCoordSetMapLength()];
- geomArray.getTexCoordSetMap(map);
- geomInfo.setTexCoordSetMap(map);
- } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
- geomInfo.setTextureCoordinateParams(texSets, 3);
- for (i = 0 ; i < texSets ; i++) {
- TexCoord3f[] tex = null;
- if (byRef) {
-
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialTexCoordIndex(i);
- } else initial = 0;
-
- if (nio) {
- J3DBuffer buf = geomArray.getTexCoordRefBuffer(i);
-
- if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) {
- FloatBuffer bb = (FloatBuffer)buf.getBuffer();
- float[] c = new float[valid * 3];
- bb.position(initial * 3);
- bb.get(c, 0, valid * 3);
- tex = new TexCoord3f[valid];
- for (j = 0 ; j < valid ; j++) {
- tex[j] = new TexCoord3f(c[j * 3 + 0],
- c[j * 3 + 1],
- c[j * 3 + 2]);
- }
- }
- // TexCoords3 were set in vertexFormat but none were set - OK
- } else if (geomArray.getTexCoordRef3f(i) != null) {
- if (initial != 0) {
- TexCoord3f[] t = geomArray.getTexCoordRef3f(i);
- tex = new TexCoord3f[valid];
- for (j = 0 ; j < valid ; j++) {
- tex[j] = new TexCoord3f(t[j + initial]);
- }
- } else tex = geomArray.getTexCoordRef3f(i);
- } else if (geomArray.getTexCoordRefFloat(i) != null) {
- float[] t = geomArray.getTexCoordRefFloat(i);
- tex = new TexCoord3f[valid];
- for (j = 0 ; j < valid ; j++) {
- tex[j] = new TexCoord3f(t[(j + initial) * 3],
- t[(j + initial) * 3 + 1],
- t[(j + initial) * 3 + 2]);
- }
- }
- // TexCoords3 were set in vertexFormat but none were set - OK
- } else {
- // Not BY_REFERENCE
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialVertexIndex();
- } else initial = 0;
- tex = new TexCoord3f[valid];
- for (j = 0 ; j < valid ; j++) tex[j] = new TexCoord3f();
- geomArray.getTextureCoordinates(i, initial, tex);
- }
- geomInfo.setTextureCoordinates(i, tex);
- }
- int[] map = new int[geomArray.getTexCoordSetMapLength()];
- geomArray.getTexCoordSetMap(map);
- geomInfo.setTexCoordSetMap(map);
- } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0 ) {
- geomInfo.setTextureCoordinateParams(texSets, 2);
- for (i = 0 ; i < texSets ; i++) {
- TexCoord2f[] tex = null;
- if (byRef) {
-
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialTexCoordIndex(i);
- } else initial = 0;
-
- if (nio) {
- J3DBuffer buf = geomArray.getTexCoordRefBuffer(i);
-
- if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) {
- FloatBuffer bb = (FloatBuffer)buf.getBuffer();
- float[] c = new float[valid * 2];
- bb.position(initial * 2);
- bb.get(c, 0, valid * 2);
- tex = new TexCoord2f[valid];
- for (j = 0 ; j < valid ; j++) {
- tex[j] = new TexCoord2f(c[j * 2 + 0],
- c[j * 2 + 1]);
- }
- }
- // TexCoords2 were set in vertexFormat but none were set - OK
- } else if (geomArray.getTexCoordRefFloat(i) != null) {
- float[] t = geomArray.getTexCoordRefFloat(i);
- tex = new TexCoord2f[valid];
- for (j = 0 ; j < valid ; j++) {
- tex[j] = new TexCoord2f(t[(j + initial) * 2 + 0],
- t[(j + initial) * 2 + 1]);
- }
- } else if (geomArray.getTexCoordRef2f(i) != null) {
- if (initial != 0) {
- TexCoord2f[] t = geomArray.getTexCoordRef2f(i);
- tex = new TexCoord2f[valid];
- for (j = 0 ; j < valid ; j++) {
- tex[j] = new TexCoord2f(t[j + initial]);
- }
- } else tex = geomArray.getTexCoordRef2f(i);
- }
- // TexCoords2 were set in vertexFormat but none were set - OK
- } else {
- // Not BY_REFERENCE
- int initial;
- if (!(geomArray instanceof IndexedGeometryArray)) {
- initial = geomArray.getInitialVertexIndex();
- } else initial = 0;
- tex = new TexCoord2f[valid];
- for (j = 0 ; j < valid ; j++) tex[j] = new TexCoord2f();
- geomArray.getTextureCoordinates(i, initial, tex);
- }
- geomInfo.setTextureCoordinates(i, tex);
- }
- int[] map = new int[geomArray.getTexCoordSetMapLength()];
- geomArray.getTexCoordSetMap(map);
- geomInfo.setTexCoordSetMap(map);
- }
- }
- } // End of processGeometryArray
-
-
-
- private static void processIndexedArray(GeometryInfo geomInfo,
- IndexedGeometryArray geomArray)
- {
- int initial = geomArray.getInitialIndexIndex();
- int vertexFormat = geomArray.getVertexFormat();
- int texSets = geomArray.getTexCoordSetCount();
-
- int valid;
- if (geomArray instanceof IndexedGeometryStripArray) {
- IndexedGeometryStripArray igsa = (IndexedGeometryStripArray)geomArray;
- int[] strips = new int[igsa.getNumStrips()];
- igsa.getStripIndexCounts(strips);
- valid = 0;
- for (int i = 0 ; i < strips.length ; i++) {
- valid += strips[i];
- }
- } else {
- valid = geomArray.getValidIndexCount();
- }
-
- int[] coordI = new int[valid];
- geomArray.getCoordinateIndices(initial, coordI);
- geomInfo.setCoordinateIndices(coordI);
-
- if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) {
- if ((vertexFormat & GeometryArray.NORMALS) != 0)
- geomInfo.setNormalIndices(coordI);
- if (((vertexFormat & GeometryArray.COLOR_3) != 0) ||
- ((vertexFormat & GeometryArray.COLOR_4) != 0))
- geomInfo.setColorIndices(coordI);
- if (((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) ||
- ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) ||
- ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0)) {
- for (int i = 0 ; i < texSets ; i++) {
- geomInfo.setTextureCoordinateIndices(i, coordI);
- }
- }
- } else {
- if ((vertexFormat & GeometryArray.NORMALS) != 0) {
- int[] normalI = new int[valid];
- geomArray.getNormalIndices(initial, normalI);
- geomInfo.setNormalIndices(normalI);
- }
-
- if (((vertexFormat & GeometryArray.COLOR_3) != 0) ||
- ((vertexFormat & GeometryArray.COLOR_4) != 0)) {
- int[] colorI = new int[valid];
- geomArray.getColorIndices(initial, colorI);
- geomInfo.setColorIndices(colorI);
- }
-
- if (((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) ||
- ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) ||
- ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0)) {
- for (int i = 0 ; i < texSets ; i++) {
- int[] texI = new int[valid];
- geomArray.getTextureCoordinateIndices(i, initial, texI);
- geomInfo.setTextureCoordinateIndices(i, texI);
- }
- }
- }
- } // End of processIndexedArray
-
-
-
- private static void processStripArray(GeometryInfo geomInfo,
- GeometryStripArray geomArray)
- {
- int[] strips = new int[geomArray.getNumStrips()];
- geomArray.getStripVertexCounts(strips);
- geomInfo.setStripCounts(strips);
- } // End of processStripArray
-
-
-
- private static void processIndexStripArray(
- GeometryInfo geomInfo, IndexedGeometryStripArray geomArray)
- {
- int[] strips = new int[geomArray.getNumStrips()];
- geomArray.getStripIndexCounts(strips);
- geomInfo.setStripCounts(strips);
- } // End of processIndexStripArray
-
-} // End of class GeometryInfoGenerator
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/GeometryServiceImpl.java b/src/classes/share/com/sun/j3d/utils/geometry/GeometryServiceImpl.java
deleted file mode 100644
index f3b0dff..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/GeometryServiceImpl.java
+++ /dev/null
@@ -1,38 +0,0 @@
-
-package com.sun.j3d.utils.geometry;
-
-import java.util.ArrayList;
-
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.GeometryService;
-import javax.vecmath.Point3f;
-
-/**
- * Default implementation of the {@link GeometryService} service interface.
- */
-public class GeometryServiceImpl implements GeometryService {
-
- @Override
- public int triangulateIslands(final int[][] islandCounts,
- final Point3f[][] outVerts, final int[] contourCounts,
- final ArrayList- *
- * If two (or more) triangles in the model share the same coordinate - * index then the normal generator will attempt to generate one normal - * for the vertex, resulting in a "smooth" looking surface. If two - * coordinates don't have the same index then they will have two - * separate normals, even if they have the same position. This will - * result in a "crease" in your object. If you suspect that your - * data isn't properly indexed, call GeometryInfo.recomputeIndexes().
- *
- * Of course, sometimes your model *has* a crease in it. That's what
- * creaseAngle is. If two triangles' normals differ by more than
- * creaseAngle, then the vertex will get two separate normals, creating a
- * discontinuous crease in the model. This is perfect for the edge
- * of a table or the corner of a cube, for instance.
- */
-
-public class NormalGenerator {
-
- private double creaseAngle;
- private ArrayList
- * When a texture is applied to a Sphere, it is mapped CCW from the back
- * of the sphere.
- *
- * By default all primitives with the same parameters share their
- * geometry (e.g., you can have 50 shperes in your scene, but the
- * geometry is stored only once). A change to one primitive will
- * effect all shared nodes. Another implication of this
- * implementation is that the capabilities of the geometry are shared,
- * and once one of the shared nodes is live, the capabilities cannot
- * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to
- * share geometry among primitives with the same parameters.
- */
-
-public class Sphere extends Primitive {
-
- /**
- * Sphere shape identifier, used by
- * If the appearance is null, the sphere defaults to a white appearance.
- */
- public Sphere(float radius, int primflags, int divisions, Appearance ap) {
- super();
-
- int sign;
- int n, nstep;
-
- this.radius = radius;
- this.divisions = divisions;
-
- /*
- * The sphere algorithm evaluates spherical angles along regular
- * units. For each spherical coordinate, (theta, rho), a (x,y,z) is
- * evaluated (along with the normals and texture coordinates).
- *
- * The spherical angles theta varies from 0 to 2pi and rho from 0
- * to pi. Sample points depends on the number of divisions.
- */
-
- flags = primflags;
- boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0;
-
- //Depending on whether normal inward bit is set.
- if ((flags & GENERATE_NORMALS_INWARD) != 0) {
- sign = -1;
- } else {
- sign = 1;
- }
-
- if (divisions < 4) {
- nstep = 1;
- n = 4;
- } else {
- int mod = divisions % 4;
- if (mod == 0) {
- n = divisions;
- } else {
- n = divisions + (4 - mod);
- }
- nstep = n/4;
- }
-
-
- GeomBuffer cache = getCachedGeometry(Primitive.SPHERE,
- radius, 0.0f, 0.0f,
- divisions, 0, primflags);
-
- Shape3D shape;
-
- if (cache != null) {
- shape = new Shape3D(cache.getComputedGeometry());
- numVerts += cache.getNumVerts();
- numTris += cache.getNumTris();
- } else {
- // buffer size = 8*(1 + 2E{i} + (nstep+1))
- // where E{i} = sum of i = 2 ... nstep
- GeomBuffer gbuf = new GeomBuffer(8*nstep*(nstep+2));
-
- for (int i=0; i < 4; i++) {
- buildQuadrant(gbuf, i*Math.PI/2, (i+1)*Math.PI/2, sign, nstep, n, true);
- buildQuadrant(gbuf, i*Math.PI/2, (i+1)*Math.PI/2, sign, nstep, n, false);
- }
-
- // Fix to Issue 411. Java 3D prefers images used for texture mapping to be Y-up
- if (texCoordYUp) {
- TexCoord2f[] texCoords = gbuf.getTexCoords();
- if (texCoords != null) {
- for (int ii=0; ii
- * For any NodeComponent objects
- * contained by the object being duplicated, each NodeComponent
- * object's
- *
- * Normal Generation should be performed on the GeometryInfo object
- * before Stripification, for best results. Example:
- *
- *
- *
- *
- * A compression command includes an 8-bit header and can range up to 72
- * bits in length. The command with the maximum length is a 2-bit color
- * command with a 6-bit tag in the header, followed by four 16-bit color
- * components of data.
- *
- * A subcommand is either a position, normal, or color, though in practice
- * a position subcommand can only be part of a vertex command. Normal and
- * color subcommands can be parts of separate global normal and color
- * commands as well as parts of a vertex command.
- *
- * A subcommand includes a 6-bit header. Its length is 2 bits less than
- * the length of the corresponding command.
- *
- * @param header contains compression command header bits, right-justified
- * within the bits of the int
- * @param headerLength number of bits in header, either 8 for commands or
- * 6 for subcommands
- * @param body contains the body of the compression command,
- * right-justified within the bits of the long
- * @param bodyLength number of bits in the body
- */
- void addCommand(int header, int headerLength, long body, int bodyLength) {
- addByte(header, headerLength) ;
- addLong(lastBody, lastBodyLength) ;
-
- lastBody = body ;
- lastBodyLength = bodyLength ;
- }
-
- //
- // Add the rightmost bitCount bits of b to the end of the command stream.
- //
- private void addByte(int b, int bitCount) {
- int bitsEmpty = 8 - bitOffset ;
- b &= (int)CompressionStreamElement.lengthMask[bitCount] ;
-
- if (bitCount <= bitsEmpty) {
- bytes[byteOffset] |= (b << (bitsEmpty - bitCount)) ;
- bitOffset += bitCount ;
- return ;
- }
-
- if (bytes.length == byteOffset + 1) {
- byte newBytes[] = new byte[bytes.length * 2] ;
- System.arraycopy(bytes, 0, newBytes, 0, bytes.length) ;
- bytes = newBytes ;
- }
-
- bitOffset = bitCount - bitsEmpty ;
- bytes[byteOffset] |= (b >>> bitOffset) ;
-
- byteOffset++ ;
- bytes[byteOffset] = (byte)(b << (8 - bitOffset)) ;
- }
-
- //
- // Add the rightmost bitCount bits of l to the end of the command stream.
- //
- private void addLong(long l, int bitCount) {
- int byteCount = bitCount / 8 ;
- int excessBits = bitCount - byteCount * 8 ;
-
- if (excessBits > 0)
- addByte((int)(l >>> (byteCount * 8)), excessBits) ;
-
- while (byteCount > 0) {
- addByte((int)((l >>> ((byteCount - 1) * 8)) & 0xff), 8) ;
- byteCount-- ;
- }
- }
-
- /**
- * Add a no-op and the last command body. Pad out with additional no-ops
- * to a 64-bit boundary if necessary. A call to this method is required
- * in order to create a valid compression command stream.
- */
- void end() {
- int excessBytes, padBits ;
-
- // Add the 1st no-op and the last body.
- addByte(V_NO_OP, 8) ;
- addLong(lastBody, lastBodyLength) ;
-
- excessBytes = (byteOffset + 1) % 8 ;
- if (excessBytes == 0 && bitOffset == 8)
- // No padding necessary.
- return ;
-
- // Need to add padding with a 2nd no-op.
- addByte(V_NO_OP, 8) ;
- excessBytes = (byteOffset + 1) % 8 ;
-
- if (excessBytes == 0)
- padBits = 8 - bitOffset ;
- else {
- int fillBytes = 8 - excessBytes ;
- padBits = (8 * fillBytes) + (8 - bitOffset) ;
- }
-
- // The minimum length for a no-op command body is 5 bits.
- if (padBits < 5)
- // Have to cross the next 64-bit boundary.
- padBits += 64 ;
-
- // The maximum length of a no-op body is a 5-bit length + 31 bits of
- // fill for a total of 36.
- if (padBits < 37) {
- // Pad with the body of the 1st no-op.
- addLong((padBits - 5) << (padBits - 5), padBits) ;
- return ;
- }
-
- // The number of bits to pad at this point is [37..68]. Knock off 24
- // bits with the body of the 1st no-op to reduce the number of pad
- // bits to [13..44], which can be filled with 1 more no-op.
- addLong(19 << 19, 24) ;
- padBits -= 24 ;
-
- // Add a 3rd no-op.
- addByte(V_NO_OP, 8) ;
- padBits -= 8 ;
-
- // Complete padding with the body of the 2nd no-op.
- addLong((padBits - 5) << (padBits - 5), padBits) ;
- }
-
- /**
- * Get the number of bytes in the compression command stream.
- *
- * @return size of compressed data in bytes
- */
- int getByteCount() {
- if (byteOffset + bitOffset == 0)
- return 0 ;
- else
- return byteOffset + 1 ;
- }
-
- /**
- * Get the bytes composing the compression command stream.
- *
- * @return reference to array of bytes containing the compressed data
- */
- byte[] getBytes() {
- return bytes ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryData.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryData.java
deleted file mode 100644
index 4c18434..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryData.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.J3DBuffer;
-import javax.media.j3d.Shape3D;
-import javax.vecmath.Point3d;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-/**
- * The compressed geometry object is used to store geometry in a
- * compressed format. Using compressed geometry may increase the speed
- * objects can be sent over the network. Note that the geometry will
- * be decompressed in memory, so the application will not see any
- * memory savings.
- *
- * Compressed geometry may be passed to this CompressedGeometryData object
- * in one of two ways: by copying the data into this object using the
- * existing constructor, or by passing a reference to the data.
- *
- *
- * All instance data is declared public and no get or set methods are
- * provided.
- *
- * @since Java 3D 1.5
- */
- public static class Header extends Object {
-
- /**
- * bufferType: compressed geometry is made up of individual points.
- */
- public static final int POINT_BUFFER = 0;
-
- /**
- * bufferType: compressed geometry is made up of line segments.
- */
- public static final int LINE_BUFFER = 1;
-
- /**
- * bufferType: compressed geometry is made up of triangles.
- */
- public static final int TRIANGLE_BUFFER = 2;
-
- // Valid values for the bufferDataPresent field.
-
- /**
- * bufferDataPresent: bit indicating that normal information is
- * bundled with the vertices in the compressed geometry buffer.
- */
- public static final int NORMAL_IN_BUFFER = 1;
-
- /**
- * bufferDataPresent: bit indicating that RGB color information is
- * bundled with the vertices in the compressed geometry buffer.
- */
- public static final int COLOR_IN_BUFFER = 2;
-
- /**
- * bufferDataPresent: bit indicating that alpha information is
- * bundled with the vertices in the compressed geometry buffer.
- */
- public static final int ALPHA_IN_BUFFER = 4;
-
- /**
- * The major version number for the compressed geometry format that
- * was used to compress the geometry.
- * If the version number of compressed geometry is incompatible
- * with the supported version of compressed geometry in the
- * current version of Java 3D, the compressed geometry obejct will
- * not be rendered.
- *
- * @see Canvas3D#queryProperties
- */
- public int majorVersionNumber;
-
- /**
- * The minor version number for the compressed geometry format that
- * was used to compress the geometry.
- * If the version number of compressed geometry is incompatible
- * with the supported version of compressed geometry in the
- * current version of Java 3D, the compressed geometry obejct will
- * not be rendered.
- *
- * @see Canvas3D#queryProperties
- */
- public int minorVersionNumber;
-
- /**
- * The minor-minor version number for the compressed geometry format
- * that was used to compress the geometry.
- * If the version number of compressed geometry is incompatible
- * with the supported version of compressed geometry in the
- * current version of Java 3D, the compressed geometry obejct will
- * not be rendered.
- *
- * @see Canvas3D#queryProperties
- */
- public int minorMinorVersionNumber;
-
- /**
- * Describes the type of data in the compressed geometry buffer.
- * Only one type may be present in any given compressed geometry
- * buffer.
- */
- public int bufferType;
-
- /**
- * Contains bits indicating what data is bundled with the vertices in the
- * compressed geometry buffer. If this data is not present (e.g. color)
- * then this info will be inherited from the Appearance node.
- */
- public int bufferDataPresent;
-
- /**
- * Size of the compressed geometry in bytes.
- */
- public int size;
-
- /**
- * Offset in bytes of the start of the compressed geometry from the
- * beginning of the compressed geometry byte array passed to the
- * CompressedGeometryData constructor.
- *
- * If the CompressedGeometryData is created with reference access semantics,
- * then this allow external compressors or file readers to embed several
- * blocks of compressed geometry in a single large byte array, possibly
- * interspersed with metadata that is not specific to Java 3D, without
- * having to copy each block to a separate byte array.
- *
- * If the CompressedGeometryData is created with copy access semantics, then
- *
- *
- * At 1 bit of quantization it is not possible to express positive
- * absolute or delta positions.
- */
- int positionQuant ;
-
- /**
- * Current color component (R, G, B, A) quantization value. This can
- * range from 2 to 16 bits and has a default of 9.
- *
- * A color component is represented with a signed fixed-point value in
- * order to be able express negative deltas; the default of 9 bits
- * corresponds to the 8-bit color component range of the graphics hardware
- * commonly available. Colors must be non-negative, so the lower limit of
- * quantization is 2 bits.
- */
- int colorQuant ;
-
- /**
- * Current normal component (U and V) quantization value. This can range
- * from 0 to 6 bits and has a default of 6.
- *
- * At 0 bits of quantization normals are represented only as 6 bit
- * sextant/octant pairs and 14 specially encoded normals (the 6 axis
- * normals and the 8 octant midpoint normals); since U and V can only be 0
- * at the minimum quantization, the totally number of unique normals is
- * 12 + 14 = 26.
- */
- int normalQuant ;
-
- /**
- * Flag indicating position quantization change.
- */
- boolean positionQuantChanged ;
-
- /**
- * Flag indicating color quantization change.
- */
- boolean colorQuantChanged ;
-
- /**
- * Flag indicating normal quantization change.
- */
- boolean normalQuantChanged ;
-
- /**
- * Last quantized position.
- */
- int lastPosition[] = new int[3] ;
-
- /**
- * Last quantized color.
- */
- int lastColor[] = new int[4] ;
-
- /**
- * Last quantized normal's sextant.
- */
- int lastSextant ;
-
- /**
- * Last quantized normal's octant.
- */
- int lastOctant ;
-
- /**
- * Last quantized normal's U encoding parameter.
- */
- int lastU ;
-
- /**
- * Last quantized normal's V encoding parameter.
- */
- int lastV ;
-
- /**
- * Flag indicating last normal used a special encoding.
- */
- boolean lastSpecialNormal ;
-
- /**
- * Flag indicating the first position in this stream.
- */
- boolean firstPosition ;
-
- /**
- * Flag indicating the first color in this stream.
- */
- boolean firstColor ;
-
- /**
- * Flag indicating the first normal in this stream.
- */
- boolean firstNormal ;
-
- /**
- * The total number of bytes used to create the uncompressed geometric
- * elements in this stream, useful for performance analysis. This
- * excludes mesh buffer references.
- */
- int byteCount ;
-
- /**
- * The number of vertices created for this stream, excluding mesh buffer
- * references.
- */
- int vertexCount ;
-
- /**
- * The number of mesh buffer references created for this stream.
- */
- int meshReferenceCount ;
-
- /**
- * Mesh buffer mirror used for computing deltas during quantization pass
- * and a limited meshing algorithm for unstripped data.
- */
- MeshBuffer meshBuffer = new MeshBuffer() ;
-
-
- // Collection which holds the elements of this stream.
- private Collection stream ;
-
- // True if preceding stream elements were colors or normals. Used to flag
- // color and normal mesh buffer substitution when computing deltas during
- // quantization pass.
- private boolean lastElementColor = false ;
- private boolean lastLastElementColor = false ;
- private boolean lastElementNormal = false ;
- private boolean lastLastElementNormal = false ;
-
- // Some convenient temporary holding variables.
- private Point3f p3f = new Point3f() ;
- private Color3f c3f = new Color3f() ;
- private Color4f c4f = new Color4f() ;
- private Vector3f n3f = new Vector3f() ;
-
-
- // Private constructor for common initializations.
- private CompressionStream() {
- this.stream = new LinkedList() ;
-
- byteCount = 0 ;
- vertexCount = 0 ;
- meshReferenceCount = 0 ;
-
- mcBounds[0] = new Point3d(Double.POSITIVE_INFINITY,
- Double.POSITIVE_INFINITY,
- Double.POSITIVE_INFINITY) ;
- mcBounds[1] = new Point3d(Double.NEGATIVE_INFINITY,
- Double.NEGATIVE_INFINITY,
- Double.NEGATIVE_INFINITY) ;
-
- qcBounds[0] = new Point3i(Integer.MAX_VALUE,
- Integer.MAX_VALUE,
- Integer.MAX_VALUE) ;
- qcBounds[1] = new Point3i(Integer.MIN_VALUE,
- Integer.MIN_VALUE,
- Integer.MIN_VALUE) ;
-
- /* normalized bounds computed from quantized bounds */
- ncBounds[0] = new Point3d() ;
- ncBounds[1] = new Point3d() ;
- }
-
- /**
- * Creates a new CompressionStream for the specified geometry type and
- * vertex format.
- *
- * @param streamType type of data in this stream, either
- * CompressedGeometryData.Header.POINT_BUFFER,
- * CompressedGeometryData.Header.LINE_BUFFER, or
- * CompressedGeometryData.Header.TRIANGLE_BUFFER
- * @param vertexComponents a mask indicating which components are present
- * in each vertex, as defined by GeometryArray: COORDINATES, NORMALS, and
- * COLOR_3 or COLOR_4.
- * @see GeometryCompressor
- * @see GeometryArray
- */
- CompressionStream(int streamType, int vertexComponents) {
- this() ;
- this.streamType = streamType ;
- this.vertexComponents = getVertexComponents(vertexComponents) ;
- }
-
- // See what vertex geometry components are present. The byReference,
- // interleaved, useNIOBuffer, and useCoordIndexOnly flags are not
- // examined.
- private int getVertexComponents(int vertexFormat) {
- int components = 0 ;
-
- vertexColors = vertexColor3 = vertexColor4 = vertexNormals =
- vertexTextures = vertexTexture2 = vertexTexture3 = vertexTexture4 =
- false ;
-
- if ((vertexFormat & GeometryArray.NORMALS) != 0) {
- vertexNormals = true ;
- components &= GeometryArray.NORMALS ;
- if (debug) System.out.println("vertexNormals") ;
- }
-
- if ((vertexFormat & GeometryArray.COLOR_3) != 0) {
- vertexColors = true ;
-
- if ((vertexFormat & GeometryArray.COLOR_4) != 0) {
- vertexColor4 = true ;
- components &= GeometryArray.COLOR_4 ;
- if (debug) System.out.println("vertexColor4") ;
- }
- else {
- vertexColor3 = true ;
- components &= GeometryArray.COLOR_3 ;
- if (debug) System.out.println("vertexColor3") ;
- }
- }
-
- if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
- vertexTextures = true ;
- vertexTexture2 = true ;
- components &= GeometryArray.TEXTURE_COORDINATE_2 ;
- if (debug) System.out.println("vertexTexture2") ;
- }
- else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
- vertexTextures = true ;
- vertexTexture3 = true ;
- components &= GeometryArray.TEXTURE_COORDINATE_3 ;
- if (debug) System.out.println("vertexTexture3") ;
- }
- else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
- vertexTextures = true ;
- vertexTexture4 = true ;
- components &= GeometryArray.TEXTURE_COORDINATE_4 ;
- if (debug) System.out.println("vertexTexture4") ;
- }
-
- if (vertexTextures)
- // Throw exception for now until texture is supported.
- throw new UnsupportedOperationException
- ("\ncompression of texture coordinates is not supported") ;
-
- return components ;
- }
-
- // Get the streamType associated with a GeometryArray instance.
- private int getStreamType(GeometryArray ga) {
- if (ga instanceof TriangleStripArray ||
- ga instanceof IndexedTriangleStripArray ||
- ga instanceof TriangleFanArray ||
- ga instanceof IndexedTriangleFanArray ||
- ga instanceof TriangleArray ||
- ga instanceof IndexedTriangleArray ||
- ga instanceof QuadArray ||
- ga instanceof IndexedQuadArray)
-
- return CompressedGeometryData.Header.TRIANGLE_BUFFER ;
-
- else if (ga instanceof LineArray ||
- ga instanceof IndexedLineArray ||
- ga instanceof LineStripArray ||
- ga instanceof IndexedLineStripArray)
-
- return CompressedGeometryData.Header.LINE_BUFFER ;
-
- else
- return CompressedGeometryData.Header.POINT_BUFFER ;
- }
-
- /**
- * Iterates across all compression stream elements and applies
- * quantization parameters, encoding consecutive vertices as delta values
- * whenever possible. Each geometric element is mapped to a HuffmanNode
- * object containing its resulting bit length, right shift (trailing 0
- * count), and absolute or relative status.
- *
- * Positions are normalized to span a unit cube via an offset and a
- * uniform scale factor that maps the midpoint of the object extents along
- * each dimension to the origin, and the longest dimension of the object to
- * the open interval (-1.0 .. +1.0). The geometric endpoints along that
- * dimension are both one quantum away from unity; for example, at a
- * position quantization of 6 bits, an object would be normalized so that
- * its most negative dimension is at (-1 + 1/64) and the most positive is
- * at (1 - 1/64).
- *
- * Normals are assumed to be of unit length. Color components are clamped
- * to the [0..1) range, where the right endpoint is one quantum less
- * than 1.0.
- *
- * @param huffmanTable Table which will map geometric compression stream
- * elements to HuffmanNode objects describing each element's data
- * representation. This table can then be processed with Huffman's
- * algorithm to optimize the bit length of descriptor tags according to
- * the number of geometric elements mapped to each tag.
- */
- void quantize(HuffmanTable huffmanTable) {
- // Set up default initial quantization parameters. The position and
- // color parameters specify the number of bits for each X, Y, Z, R, G,
- // B, or A component. The normal quantization parameter specifies the
- // number of bits for each U and V component.
- positionQuant = 16 ;
- colorQuant = 9 ;
- normalQuant = 6 ;
-
- // Compute position center and scaling for normalization to the unit
- // cube. This is a volume bounded by the open intervals (-1..1) on
- // each axis.
- center[0] = (mcBounds[1].x + mcBounds[0].x) / 2.0 ;
- center[1] = (mcBounds[1].y + mcBounds[0].y) / 2.0 ;
- center[2] = (mcBounds[1].z + mcBounds[0].z) / 2.0 ;
-
- double xRange = mcBounds[1].x - mcBounds[0].x ;
- double yRange = mcBounds[1].y - mcBounds[0].y ;
- double zRange = mcBounds[1].z - mcBounds[0].z ;
-
- if (xRange > yRange)
- positionRangeMaximum = xRange ;
- else
- positionRangeMaximum = yRange ;
-
- if (zRange > positionRangeMaximum)
- positionRangeMaximum = zRange ;
-
- // Adjust the range of the unit cube to match the default
- // quantization.
- //
- // This scale factor along with the center values computed above will
- // produce 16-bit integer representations of the floating point
- // position coordinates ranging symmetrically about 0 from -32767 to
- // +32767. -32768 is not used and the normalized floating point
- // position coordinates of -1.0 as well as +1.0 will not be
- // represented.
- //
- // Applications which wish to seamlessly stitch together compressed
- // objects will need to be aware that the range of normalized
- // positions will be one quantum away from the [-1..1] endpoints of
- // the unit cube and should adjust scale factors accordingly.
- scale = (2.0 / positionRangeMaximum) * (32767.0 / 32768.0) ;
-
- // Flag quantization change.
- positionQuantChanged = colorQuantChanged = normalQuantChanged = true ;
-
- // Flag first position, color, and normal.
- firstPosition = firstColor = firstNormal = true ;
-
- // Apply quantization.
- Iterator i = stream.iterator() ;
- while (i.hasNext()) {
- Object o = i.next() ;
-
- if (o instanceof CompressionStreamElement) {
- ((CompressionStreamElement)o).quantize(this, huffmanTable) ;
-
- // Keep track of whether last two elements were colors or
- // normals for mesh buffer component substitution semantics.
- lastLastElementColor = lastElementColor ;
- lastLastElementNormal = lastElementNormal ;
- lastElementColor = lastElementNormal = false ;
-
- if (o instanceof CompressionStreamColor)
- lastElementColor = true ;
- else if (o instanceof CompressionStreamNormal)
- lastElementNormal = true ;
- }
- }
-
- // Compute the bounds in normalized coordinates.
- ncBounds[0].x = (double)qcBounds[0].x / 32768.0 ;
- ncBounds[0].y = (double)qcBounds[0].y / 32768.0 ;
- ncBounds[0].z = (double)qcBounds[0].z / 32768.0 ;
-
- ncBounds[1].x = (double)qcBounds[1].x / 32768.0 ;
- ncBounds[1].y = (double)qcBounds[1].y / 32768.0 ;
- ncBounds[1].z = (double)qcBounds[1].z / 32768.0 ;
- }
-
- /**
- * Iterates across all compression stream elements and builds the
- * compressed geometry command stream output.
- *
- * @param huffmanTable Table which maps geometric elements in this stream
- * to tags describing the encoding parameters (length, shift, and
- * absolute/relative status) to be used for their representations in the
- * compressed output. All tags must be 6 bits or less in length, and the
- * sum of the number of bits in the tag plus the number of bits in the
- * data it describes must be at least 6 bits in length.
- *
- * @param outputBuffer CommandStream to use for collecting the compressed
- * bits.
- */
- void outputCommands(HuffmanTable huffmanTable, CommandStream outputBuffer) {
- //
- // The first command output is setState to indicate what data is
- // bundled with each vertex. Although the semantics of geometry
- // decompression allow setState to appear anywhere in the stream, this
- // cannot be handled by the current Java 3D software decompressor,
- // which internally decompresses an entire compressed buffer into a
- // single retained object sharing a single consistent vertex format.
- // This limitation may be removed in subsequent releases of Java 3D.
- //
- int bnv = (vertexNormals? 1 : 0) ;
- int bcv = ((vertexColor3 || vertexColor4)? 1 : 0) ;
- int cap = (vertexColor4? 1 : 0) ;
-
- int command = CommandStream.SET_STATE | bnv ;
- long data = (bcv << 2) | (cap << 1) ;
-
- // Output the setState command.
- outputBuffer.addCommand(command, 8, data, 3) ;
-
- // Output the Huffman table commands.
- huffmanTable.outputCommands(outputBuffer) ;
-
- // Output each compression stream element's data.
- Iterator i = stream.iterator() ;
- while (i.hasNext()) {
- Object o = i.next() ;
- if (o instanceof CompressionStreamElement)
- ((CompressionStreamElement)o).outputCommand(huffmanTable,
- outputBuffer) ;
- }
-
- // Finish the header-forwarding interleave and long-word align.
- outputBuffer.end() ;
- }
-
- /**
- * Retrieve the total size of the uncompressed geometric data in bytes,
- * excluding mesh buffer references.
- * @return uncompressed byte count
- */
- int getByteCount() {
- return byteCount ;
- }
-
- /**
- * Retrieve the the number of vertices created for this stream, excluding
- * mesh buffer references.
- * @return vertex count
- */
- int getVertexCount() {
- return vertexCount ;
- }
-
- /**
- * Retrieve the number of mesh buffer references created for this stream.
- * @return mesh buffer reference count
- */
- int getMeshReferenceCount() {
- return meshReferenceCount ;
- }
-
- /**
- * Stream element that sets position quantization during quantize pass.
- */
- private class PositionQuant extends CompressionStreamElement {
- int value ;
-
- PositionQuant(int value) {
- this.value = value ;
- }
-
- @Override
- void quantize(CompressionStream s, HuffmanTable t) {
- positionQuant = value ;
- positionQuantChanged = true ;
-
- // Adjust range of unit cube scaling to match quantization.
- scale = (2.0 / positionRangeMaximum) *
- (((double)((1 << (value-1)) - 1))/((double)(1 << (value-1)))) ;
- }
-
- @Override
- public String toString() {
- return "positionQuant: " + value ;
- }
- }
-
- /**
- * Stream element that sets normal quantization during quantize pass.
- */
- private class NormalQuant extends CompressionStreamElement {
- int value ;
-
- NormalQuant(int value) {
- this.value = value ;
- }
-
- @Override
- void quantize(CompressionStream s, HuffmanTable t) {
- normalQuant = value ;
- normalQuantChanged = true ;
- }
-
- @Override
- public String toString() {
- return "normalQuant: " + value ;
- }
- }
-
- /**
- * Stream element that sets color quantization during quantize pass.
- */
- private class ColorQuant extends CompressionStreamElement {
- int value ;
-
- ColorQuant(int value) {
- this.value = value ;
- }
-
- @Override
- void quantize(CompressionStream s, HuffmanTable t) {
- colorQuant = value ;
- colorQuantChanged = true ;
- }
-
- @Override
- public String toString() {
- return "colorQuant: " + value ;
- }
- }
-
- /**
- * Stream element that references the mesh buffer.
- */
- private class MeshReference extends CompressionStreamElement {
- int stripFlag, meshIndex ;
-
- MeshReference(int stripFlag, int meshIndex) {
- this.stripFlag = stripFlag ;
- this.meshIndex = meshIndex ;
- meshReferenceCount++ ;
- }
-
- @Override
- void quantize(CompressionStream s, HuffmanTable t) {
- // Retrieve the vertex from the mesh buffer mirror and set up the
- // data needed for the next stream element to compute its deltas.
- CompressionStreamVertex v = meshBuffer.getVertex(meshIndex) ;
- lastPosition[0] = v.xAbsolute ;
- lastPosition[1] = v.yAbsolute ;
- lastPosition[2] = v.zAbsolute ;
-
- // Set up last color data if it exists and previous elements
- // don't override it.
- if (v.color != null && !lastElementColor &&
- !(lastElementNormal && lastLastElementColor)) {
- lastColor[0] = v.color.rAbsolute ;
- lastColor[1] = v.color.gAbsolute ;
- lastColor[2] = v.color.bAbsolute ;
- lastColor[3] = v.color.aAbsolute ;
- }
-
- // Set up last normal data if it exists and previous element
- // doesn't override it.
- if (v.normal != null && !lastElementNormal &&
- !(lastElementColor && lastLastElementNormal)) {
- lastSextant = v.normal.sextant ;
- lastOctant = v.normal.octant ;
- lastU = v.normal.uAbsolute ;
- lastV = v.normal.vAbsolute ;
- lastSpecialNormal = v.normal.specialNormal ;
- }
- }
-
- @Override
- void outputCommand(HuffmanTable t, CommandStream outputBuffer) {
- int command = CommandStream.MESH_B_R ;
- long data = stripFlag & 0x1 ;
-
- command |= (((meshIndex & 0xf) << 1) | (stripFlag >> 1)) ;
- outputBuffer.addCommand(command, 8, data, 1) ;
- }
-
- @Override
- public String toString() {
- return
- "meshReference: stripFlag " + stripFlag +
- " meshIndex " + meshIndex ;
- }
- }
-
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, int stripFlag) {
- stream.add(new CompressionStreamVertex(this, pos,
- (Vector3f)null, (Color3f)null,
- stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, Vector3f norm, int stripFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, (Color3f)null, stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, Color3f color, int stripFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, Color4f color, int stripFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, Vector3f norm, Color3f color,
- int stripFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART,
- * REPLACE_OLDEST, or REPLACE_MIDDLE
- */
- void addVertex(Point3f pos, Vector3f norm, Color4f color,
- int stripFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, (Vector3f)null, (Color3f)null, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Vector3f norm,
- int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, (Color3f)null, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Color3f color,
- int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Color4f color,
- int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Vector3f norm, Color3f color,
- int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, color, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param color color data
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Vector3f norm, Color4f color,
- int stripFlag, int meshFlag) {
- stream.add(new CompressionStreamVertex
- (this, pos, norm, color, stripFlag, meshFlag)) ;
- }
-
- /**
- * Copy vertex data and add it to the end of this stream.
- * @param pos position data
- * @param norm normal data
- * @param color color data, either Color3f or Color4f, determined by
- * current vertex format
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
- */
- void addVertex(Point3f pos, Vector3f norm,
- Object color, int stripFlag, int meshFlag) {
-
- if (vertexColor3)
- stream.add(new CompressionStreamVertex
- (this, pos, norm, (Color3f)color, stripFlag, meshFlag)) ;
- else
- stream.add(new CompressionStreamVertex
- (this, pos, norm, (Color4f)color, stripFlag, meshFlag)) ;
- }
-
- /**
- * Add a mesh buffer reference to this stream.
- * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
- * or REPLACE_MIDDLE
- * @param meshIndex index of vertex to retrieve from the mesh buffer
- */
- void addMeshReference(int stripFlag, int meshIndex) {
- stream.add(new MeshReference(stripFlag, meshIndex)) ;
- }
-
- /**
- * Copy the given color to the end of this stream and use it as a global
- * state change that applies to all subsequent vertices.
- */
- void addColor(Color3f c3f) {
- stream.add(new CompressionStreamColor(this, c3f)) ;
- }
-
- /**
- * Copy the given color to the end of this stream and use it as a global
- * state change that applies to all subsequent vertices.
- */
- void addColor(Color4f c4f) {
- stream.add(new CompressionStreamColor(this, c4f)) ;
- }
-
- /**
- * Copy the given normal to the end of this stream and use it as a global
- * state change that applies to all subsequent vertices.
- */
- void addNormal(Vector3f n) {
- stream.add(new CompressionStreamNormal(this, n)) ;
- }
-
- /**
- * Add a new position quantization value to the end of this stream that
- * will apply to all subsequent vertex positions.
- *
- * @param value number of bits to quantize each position's X, Y,
- * and Z components, ranging from 1 to 16 with a default of 16
- */
- void addPositionQuantization(int value) {
- stream.add(new PositionQuant(value)) ;
- }
-
- /**
- * Add a new color quantization value to the end of this stream that will
- * apply to all subsequent colors.
- *
- * @param value number of bits to quantize each color's R, G, B, and
- * alpha components, ranging from 2 to 16 with a default of 9
- */
- void addColorQuantization(int value) {
- stream.add(new ColorQuant(value)) ;
- }
-
- /**
- * Add a new normal quantization value to the end of this stream that will
- * apply to all subsequent normals. This value specifies the number of
- * bits for each normal's U and V components.
- *
- * @param value number of bits for quantizing U and V, ranging from 0 to
- * 6 with a default of 6
- */
- void addNormalQuantization(int value) {
- stream.add(new NormalQuant(value)) ;
- }
-
- /**
- * Interface to access GeometryArray vertex components and add them to the
- * compression stream.
- *
- * A processVertex() implementation retrieves vertex components using the
- * appropriate access semantics of a particular GeometryArray, and adds
- * them to the compression stream.
- *
- * The implementation always pushes vertices into the mesh buffer unless
- * they match ones already there; if they do, it generates mesh buffer
- * references instead. This reduces the number of vertices when
- * non-stripped abutting facets are added to the stream.
- *
- * Note: Level II geometry compression semantics allow the mesh buffer
- * normals to be substituted with the value of an immediately
- * preceding SetNormal command, but this is unavailable in Level I.
- *
- * @param index vertex offset from the beginning of its data array
- * @param stripFlag RESTART, REPLACE_MIDDLE, or REPLACE_OLDEST
- */
- private interface GeometryAccessor {
- void processVertex(int index, int stripFlag) ;
- }
-
- /**
- * This class implements the GeometryAccessor interface for geometry
- * arrays accessed with by-copy semantics.
- */
- private class ByCopyGeometry implements GeometryAccessor {
- Point3f[] positions = null ;
- Vector3f[] normals = null ;
- Color3f[] colors3 = null ;
- Color4f[] colors4 = null ;
-
- ByCopyGeometry(GeometryArray ga) {
- this(ga, ga.getInitialVertexIndex(), ga.getValidVertexCount()) ;
- }
-
- ByCopyGeometry(GeometryArray ga,
- int firstVertex, int validVertexCount) {
- int i ;
- positions = new Point3f[validVertexCount] ;
- for (i = 0 ; i < validVertexCount ; i++)
- positions[i] = new Point3f() ;
-
- ga.getCoordinates(firstVertex, positions) ;
-
- if (vertexNormals) {
- normals = new Vector3f[validVertexCount] ;
- for (i = 0 ; i < validVertexCount ; i++)
- normals[i] = new Vector3f() ;
-
- ga.getNormals(firstVertex, normals) ;
- }
-
- if (vertexColor3) {
- colors3 = new Color3f[validVertexCount] ;
- for (i = 0 ; i < validVertexCount ; i++)
- colors3[i] = new Color3f() ;
-
- ga.getColors(firstVertex, colors3) ;
- }
- else if (vertexColor4) {
- colors4 = new Color4f[validVertexCount] ;
- for (i = 0 ; i < validVertexCount ; i++)
- colors4[i] = new Color4f() ;
-
- ga.getColors(firstVertex, colors4) ;
- }
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- Point3f p = positions[v] ;
- int r = meshBuffer.getMeshReference(p) ;
-
- if ((r == meshBuffer.NOT_FOUND) ||
- (vertexNormals && noMeshNormalSubstitution &&
- (! normals[v].equals(meshBuffer.getNormal(r))))) {
-
- Vector3f n = vertexNormals? normals[v] : null ;
- Object c = vertexColor3? (Object)colors3[v] :
- vertexColor4? (Object)colors4[v] : null ;
-
- addVertex(p, n, c, stripFlag, MESH_PUSH) ;
- meshBuffer.push(p, c, n) ;
- }
- else {
- if (vertexNormals && !noMeshNormalSubstitution &&
- (! normals[v].equals(meshBuffer.getNormal(r))))
- addNormal(normals[v]) ;
-
- if (vertexColor3 &&
- (! colors3[v].equals(meshBuffer.getColor3(r))))
- addColor(colors3[v]) ;
-
- else if (vertexColor4 &&
- (! colors4[v].equals(meshBuffer.getColor4(r))))
- addColor(colors4[v]) ;
-
- addMeshReference(stripFlag, r) ;
- }
- }
- }
-
- /**
- * Class which holds index array references for a geometry array.
- */
- private static class IndexArrays {
- int colorIndices[] = null ;
- int normalIndices[] = null ;
- int positionIndices[] = null ;
- }
-
- /**
- * Retrieves index array references for the specified IndexedGeometryArray.
- * Index arrays are copied starting from initialIndexIndex.
- */
- private void getIndexArrays(GeometryArray ga, IndexArrays ia) {
- IndexedGeometryArray iga = (IndexedGeometryArray)ga ;
-
- int initialIndexIndex = iga.getInitialIndexIndex() ;
- int indexCount = iga.getValidIndexCount() ;
- int vertexFormat = iga.getVertexFormat() ;
-
- boolean useCoordIndexOnly = false ;
- if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) {
- if (debug) System.out.println("useCoordIndexOnly") ;
- useCoordIndexOnly = true ;
- }
-
- ia.positionIndices = new int[indexCount] ;
- iga.getCoordinateIndices(initialIndexIndex, ia.positionIndices) ;
-
- if (vertexNormals) {
- if (useCoordIndexOnly) {
- ia.normalIndices = ia.positionIndices ;
- }
- else {
- ia.normalIndices = new int[indexCount] ;
- iga.getNormalIndices(initialIndexIndex, ia.normalIndices) ;
- }
- }
- if (vertexColor3 || vertexColor4) {
- if (useCoordIndexOnly) {
- ia.colorIndices = ia.positionIndices ;
- }
- else {
- ia.colorIndices = new int[indexCount] ;
- iga.getColorIndices(initialIndexIndex, ia.colorIndices) ;
- }
- }
- }
-
- /**
- * Class which holds indices for a specific vertex of an
- * IndexedGeometryArray.
- */
- private static class VertexIndices {
- int pi, ni, ci ;
- }
-
- /**
- * Retrieves vertex indices for a specific vertex in an
- * IndexedGeometryArray.
- */
- private void getVertexIndices(int v, IndexArrays ia, VertexIndices vi) {
- vi.pi = ia.positionIndices[v] ;
- if (vertexNormals)
- vi.ni = ia.normalIndices[v] ;
- if (vertexColors)
- vi.ci = ia.colorIndices[v] ;
- }
-
- /**
- * This class implements the GeometryAccessor interface for indexed
- * geometry arrays accessed with by-copy semantics.
- */
- private class IndexedByCopyGeometry extends ByCopyGeometry {
- IndexArrays ia = new IndexArrays() ;
- VertexIndices vi = new VertexIndices() ;
-
- IndexedByCopyGeometry(GeometryArray ga) {
- super(ga, 0, ga.getVertexCount()) ;
- getIndexArrays(ga, ia) ;
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- getVertexIndices(v, ia, vi) ;
- int r = meshBuffer.getMeshReference(vi.pi) ;
-
- if ((r == meshBuffer.NOT_FOUND) ||
- (vertexNormals && noMeshNormalSubstitution &&
- (vi.ni != meshBuffer.getNormalIndex(r)))) {
-
- Point3f p = positions[vi.pi] ;
- Vector3f n = vertexNormals? normals[vi.ni] : null ;
- Object c = vertexColor3? (Object)colors3[vi.ci] :
- vertexColor4? (Object)colors4[vi.ci] : null ;
-
- addVertex(p, n, c, stripFlag, MESH_PUSH) ;
- meshBuffer.push(vi.pi, vi.ci, vi.ni) ;
- }
- else {
- if (vertexNormals && !noMeshNormalSubstitution &&
- vi.ni != meshBuffer.getNormalIndex(r))
- addNormal(normals[vi.ni]) ;
-
- if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r))
- addColor(colors3[vi.ci]) ;
-
- else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r))
- addColor(colors4[vi.ci]) ;
-
- addMeshReference(stripFlag, r) ;
- }
- }
- }
-
- //
- // NOTE: For now, copies are made of all GeometryArray vertex components
- // even when by-reference access is available.
- //
- private static class VertexCopy {
- Object c = null ;
- Point3f p = null ;
- Vector3f n = null ;
- Color3f c3 = null ;
- Color4f c4 = null ;
- }
-
- private void processVertexCopy(VertexCopy vc, int stripFlag) {
- int r = meshBuffer.getMeshReference(vc.p) ;
-
- if ((r == meshBuffer.NOT_FOUND) ||
- (vertexNormals && noMeshNormalSubstitution &&
- (! vc.n.equals(meshBuffer.getNormal(r))))) {
-
- addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ;
- meshBuffer.push(vc.p, vc.c, vc.n) ;
- }
- else {
- if (vertexNormals && !noMeshNormalSubstitution &&
- (! vc.n.equals(meshBuffer.getNormal(r))))
- addNormal(vc.n) ;
-
- if (vertexColor3 && (! vc.c3.equals(meshBuffer.getColor3(r))))
- addColor(vc.c3) ;
-
- else if (vertexColor4 && (! vc.c4.equals(meshBuffer.getColor4(r))))
- addColor(vc.c4) ;
-
- addMeshReference(stripFlag, r) ;
- }
- }
-
- private void processIndexedVertexCopy(VertexCopy vc,
- VertexIndices vi,
- int stripFlag) {
-
- int r = meshBuffer.getMeshReference(vi.pi) ;
-
- if ((r == meshBuffer.NOT_FOUND) ||
- (vertexNormals && noMeshNormalSubstitution &&
- (vi.ni != meshBuffer.getNormalIndex(r)))) {
-
- addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ;
- meshBuffer.push(vi.pi, vi.ci, vi.ni) ;
- }
- else {
- if (vertexNormals && !noMeshNormalSubstitution &&
- vi.ni != meshBuffer.getNormalIndex(r))
- addNormal(vc.n) ;
-
- if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r))
- addColor(vc.c3) ;
-
- else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r))
- addColor(vc.c4) ;
-
- addMeshReference(stripFlag, r) ;
- }
- }
-
- /**
- * This abstract class implements the GeometryAccessor interface for
- * concrete subclasses which handle float and NIO interleaved geometry
- * arrays.
- */
- private abstract class InterleavedGeometry implements GeometryAccessor {
- VertexCopy vc = new VertexCopy() ;
-
- int vstride = 0 ;
- int coffset = 0 ;
- int noffset = 0 ;
- int poffset = 0 ;
- int tstride = 0 ;
- int tcount = 0 ;
-
- InterleavedGeometry(GeometryArray ga) {
- if (vertexTextures) {
- if (vertexTexture2) tstride = 2 ;
- else if (vertexTexture3) tstride = 3 ;
- else if (vertexTexture4) tstride = 4 ;
-
- tcount = ga.getTexCoordSetCount() ;
- vstride += tcount * tstride ;
- }
-
- if (vertexColors) {
- coffset = vstride ;
- if (vertexColor3) vstride += 3 ;
- else vstride += 4 ;
- }
-
- if (vertexNormals) {
- noffset = vstride ;
- vstride += 3 ;
- }
-
- poffset = vstride ;
- vstride += 3 ;
- }
-
- abstract void copyVertex(int pi, int ni, int ci, VertexCopy vc) ;
-
- @Override
- public void processVertex(int v, int stripFlag) {
- copyVertex(v, v, v, vc) ;
- processVertexCopy(vc, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for float
- * interleaved geometry arrays.
- */
- private class InterleavedGeometryFloat extends InterleavedGeometry {
- float[] vdata = null ;
-
- InterleavedGeometryFloat(GeometryArray ga) {
- super(ga) ;
- vdata = ga.getInterleavedVertices() ;
- }
-
- @Override
- void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
- int voffset ;
- voffset = pi * vstride ;
- vc.p = new Point3f(vdata[voffset + poffset + 0],
- vdata[voffset + poffset + 1],
- vdata[voffset + poffset + 2]) ;
-
- if (vertexNormals) {
- voffset = ni * vstride ;
- vc.n = new Vector3f(vdata[voffset + noffset + 0],
- vdata[voffset + noffset + 1],
- vdata[voffset + noffset + 2]) ;
- }
- if (vertexColor3) {
- voffset = ci * vstride ;
- vc.c3 = new Color3f(vdata[voffset + coffset + 0],
- vdata[voffset + coffset + 1],
- vdata[voffset + coffset + 2]) ;
- vc.c = vc.c3 ;
- }
- else if (vertexColor4) {
- voffset = ci * vstride ;
- vc.c4 = new Color4f(vdata[voffset + coffset + 0],
- vdata[voffset + coffset + 1],
- vdata[voffset + coffset + 2],
- vdata[voffset + coffset + 3]) ;
- vc.c = vc.c4 ;
- }
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for indexed
- * interleaved geometry arrays.
- */
- private class IndexedInterleavedGeometryFloat
- extends InterleavedGeometryFloat {
-
- IndexArrays ia = new IndexArrays() ;
- VertexIndices vi = new VertexIndices() ;
-
- IndexedInterleavedGeometryFloat(GeometryArray ga) {
- super(ga) ;
- getIndexArrays(ga, ia) ;
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- getVertexIndices(v, ia, vi) ;
- copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
- processIndexedVertexCopy(vc, vi, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for
- * interleaved NIO geometry arrays.
- */
- private class InterleavedGeometryNIO extends InterleavedGeometry {
- FloatBuffer fbw = null ;
-
- InterleavedGeometryNIO(GeometryArray ga) {
- super(ga) ;
- J3DBuffer buffer = ga.getInterleavedVertexBuffer() ;
- if (BufferWrapper.getBufferType(buffer) ==
- BufferWrapper.TYPE_FLOAT) {
- fbw = (FloatBuffer)buffer.getBuffer();
- }
- else {
- throw new IllegalArgumentException
- ("\ninterleaved vertex buffer must be FloatBuffer") ;
- }
- }
-
- @Override
- void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
- int voffset ;
- voffset = pi * vstride ;
- vc.p = new Point3f(fbw.get(voffset + poffset + 0),
- fbw.get(voffset + poffset + 1),
- fbw.get(voffset + poffset + 2)) ;
-
- if (vertexNormals) {
- voffset = ni * vstride ;
- vc.n = new Vector3f(fbw.get(voffset + noffset + 0),
- fbw.get(voffset + noffset + 1),
- fbw.get(voffset + noffset + 2)) ;
- }
- if (vertexColor3) {
- voffset = ci * vstride ;
- vc.c3 = new Color3f(fbw.get(voffset + coffset + 0),
- fbw.get(voffset + coffset + 1),
- fbw.get(voffset + coffset + 2)) ;
- vc.c = vc.c3 ;
- }
- else if (vertexColor4) {
- voffset = ci * vstride ;
- vc.c4 = new Color4f(fbw.get(voffset + coffset + 0),
- fbw.get(voffset + coffset + 1),
- fbw.get(voffset + coffset + 2),
- fbw.get(voffset + coffset + 3)) ;
- vc.c = vc.c4 ;
- }
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for indexed
- * interleaved NIO geometry arrays.
- */
- private class IndexedInterleavedGeometryNIO extends InterleavedGeometryNIO {
- IndexArrays ia = new IndexArrays() ;
- VertexIndices vi = new VertexIndices() ;
-
- IndexedInterleavedGeometryNIO(GeometryArray ga) {
- super(ga) ;
- getIndexArrays(ga, ia) ;
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- getVertexIndices(v, ia, vi) ;
- copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
- processIndexedVertexCopy(vc, vi, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for
- * non-interleaved geometry arrays accessed with by-reference semantics.
- */
- private class ByRefGeometry implements GeometryAccessor {
- VertexCopy vc = new VertexCopy() ;
-
- byte[] colorsB = null ;
- float[] colorsF = null ;
- float[] normals = null ;
- float[] positionsF = null ;
- double[] positionsD = null ;
-
- int initialPositionIndex = 0 ;
- int initialNormalIndex = 0 ;
- int initialColorIndex = 0 ;
-
- ByRefGeometry(GeometryArray ga) {
- positionsF = ga.getCoordRefFloat() ;
- if (debug && positionsF != null)
- System.out.println("float positions") ;
-
- positionsD = ga.getCoordRefDouble() ;
- if (debug && positionsD != null)
- System.out.println("double positions") ;
-
- if (positionsF == null && positionsD == null)
- throw new UnsupportedOperationException
- ("\nby-reference access to Point3{d,f} arrays") ;
-
- initialPositionIndex = ga.getInitialCoordIndex() ;
-
- if (vertexColors) {
- colorsB = ga.getColorRefByte() ;
- if (debug && colorsB != null)
- System.out.println("byte colors") ;
-
- colorsF = ga.getColorRefFloat() ;
- if (debug && colorsF != null)
- System.out.println("float colors") ;
-
- if (colorsB == null && colorsF == null)
- throw new UnsupportedOperationException
- ("\nby-reference access to Color{3b,3f,4b,4f} arrays") ;
-
- initialColorIndex = ga.getInitialColorIndex() ;
- }
-
- if (vertexNormals) {
- normals = ga.getNormalRefFloat() ;
- if (debug && normals != null)
- System.out.println("float normals") ;
-
- if (normals == null)
- throw new UnsupportedOperationException
- ("\nby-reference access to Normal3f array") ;
-
- initialNormalIndex = ga.getInitialNormalIndex() ;
- }
- }
-
- void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
- pi *= 3 ;
- if (positionsF != null) {
- vc.p = new Point3f(positionsF[pi + 0],
- positionsF[pi + 1],
- positionsF[pi + 2]) ;
- }
- else {
- vc.p = new Point3f((float)positionsD[pi + 0],
- (float)positionsD[pi + 1],
- (float)positionsD[pi + 2]) ;
- }
-
- ni *= 3 ;
- if (vertexNormals) {
- vc.n = new Vector3f(normals[ni + 0],
- normals[ni + 1],
- normals[ni + 2]) ;
- }
-
- if (vertexColor3) {
- ci *= 3 ;
- if (colorsB != null) {
- vc.c3 = new Color3f
- ((colorsB[ci + 0] & 0xff) * ByteToFloatScale,
- (colorsB[ci + 1] & 0xff) * ByteToFloatScale,
- (colorsB[ci + 2] & 0xff) * ByteToFloatScale) ;
- }
- else {
- vc.c3 = new Color3f(colorsF[ci + 0],
- colorsF[ci + 1],
- colorsF[ci + 2]) ;
- }
- vc.c = vc.c3 ;
- }
- else if (vertexColor4) {
- ci *= 4 ;
- if (colorsB != null) {
- vc.c4 = new Color4f
- ((colorsB[ci + 0] & 0xff) * ByteToFloatScale,
- (colorsB[ci + 1] & 0xff) * ByteToFloatScale,
- (colorsB[ci + 2] & 0xff) * ByteToFloatScale,
- (colorsB[ci + 3] & 0xff) * ByteToFloatScale) ;
- }
- else {
- vc.c4 = new Color4f(colorsF[ci + 0],
- colorsF[ci + 1],
- colorsF[ci + 2],
- colorsF[ci + 3]) ;
- }
- vc.c = vc.c4 ;
- }
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- copyVertex(v + initialPositionIndex,
- v + initialNormalIndex,
- v + initialColorIndex, vc) ;
-
- processVertexCopy(vc, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for indexed
- * non-interleaved geometry arrays accessed with by-reference semantics.
- */
- private class IndexedByRefGeometry extends ByRefGeometry {
- IndexArrays ia = new IndexArrays() ;
- VertexIndices vi = new VertexIndices() ;
-
- IndexedByRefGeometry(GeometryArray ga) {
- super(ga) ;
- getIndexArrays(ga, ia) ;
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- getVertexIndices(v, ia, vi) ;
- copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
- processIndexedVertexCopy(vc, vi, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for
- * non-interleaved geometry arrays accessed with NIO.
- */
- private class ByRefGeometryNIO implements GeometryAccessor {
- VertexCopy vc = new VertexCopy() ;
-
- ByteBuffer colorsB = null ;
- FloatBuffer colorsF = null ;
- FloatBuffer normals = null ;
- FloatBuffer positionsF = null ;
- DoubleBuffer positionsD = null ;
-
- int initialPositionIndex = 0 ;
- int initialNormalIndex = 0 ;
- int initialColorIndex = 0 ;
-
- ByRefGeometryNIO(GeometryArray ga) {
- J3DBuffer buffer ;
- buffer = ga.getCoordRefBuffer() ;
- initialPositionIndex = ga.getInitialCoordIndex() ;
-
- switch (BufferWrapper.getBufferType(buffer)) {
- case BufferWrapper.TYPE_FLOAT:
- positionsF = (FloatBuffer)buffer.getBuffer();
- if (debug) System.out.println("float positions buffer") ;
- break ;
- case BufferWrapper.TYPE_DOUBLE:
- positionsD = (DoubleBuffer)buffer.getBuffer();
- if (debug) System.out.println("double positions buffer") ;
- break ;
- default:
- throw new IllegalArgumentException
- ("\nposition buffer must be FloatBuffer or DoubleBuffer") ;
- }
-
- if (vertexColors) {
- buffer = ga.getColorRefBuffer() ;
- initialColorIndex = ga.getInitialColorIndex() ;
-
- switch (BufferWrapper.getBufferType(buffer)) {
- case BufferWrapper.TYPE_BYTE:
- colorsB = (ByteBuffer)buffer.getBuffer();
- if (debug) System.out.println("byte colors buffer") ;
- break ;
- case BufferWrapper.TYPE_FLOAT:
- colorsF = (FloatBuffer)buffer.getBuffer();
- if (debug) System.out.println("float colors buffer") ;
- break ;
- default:
- throw new IllegalArgumentException
- ("\ncolor buffer must be ByteBuffer or FloatBuffer") ;
- }
- }
-
- if (vertexNormals) {
- buffer = ga.getNormalRefBuffer() ;
- initialNormalIndex = ga.getInitialNormalIndex() ;
-
- switch (BufferWrapper.getBufferType(buffer)) {
- case BufferWrapper.TYPE_FLOAT:
- normals = (FloatBuffer)buffer.getBuffer();
- if (debug) System.out.println("float normals buffer") ;
- break ;
- default:
- throw new IllegalArgumentException
- ("\nnormal buffer must be FloatBuffer") ;
- }
- }
- }
-
- void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
- pi *= 3 ;
- if (positionsF != null) {
- vc.p = new Point3f(positionsF.get(pi + 0),
- positionsF.get(pi + 1),
- positionsF.get(pi + 2)) ;
- }
- else {
- vc.p = new Point3f((float)positionsD.get(pi + 0),
- (float)positionsD.get(pi + 1),
- (float)positionsD.get(pi + 2)) ;
- }
-
- ni *= 3 ;
- if (vertexNormals) {
- vc.n = new Vector3f(normals.get(ni + 0),
- normals.get(ni + 1),
- normals.get(ni + 2)) ;
- }
-
- if (vertexColor3) {
- ci *= 3 ;
- if (colorsB != null) {
- vc.c3 = new Color3f
- ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale,
- (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale,
- (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale) ;
- }
- else {
- vc.c3 = new Color3f(colorsF.get(ci + 0),
- colorsF.get(ci + 1),
- colorsF.get(ci + 2)) ;
- }
- vc.c = vc.c3 ;
- }
- else if (vertexColor4) {
- ci *= 4 ;
- if (colorsB != null) {
- vc.c4 = new Color4f
- ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale,
- (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale,
- (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale,
- (colorsB.get(ci + 3) & 0xff) * ByteToFloatScale) ;
- }
- else {
- vc.c4 = new Color4f(colorsF.get(ci + 0),
- colorsF.get(ci + 1),
- colorsF.get(ci + 2),
- colorsF.get(ci + 3)) ;
- }
- vc.c = vc.c4 ;
- }
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- copyVertex(v + initialPositionIndex,
- v + initialNormalIndex,
- v + initialColorIndex, vc) ;
-
- processVertexCopy(vc, stripFlag) ;
- }
- }
-
- /**
- * This class implements the GeometryAccessor interface for
- * non-interleaved indexed geometry arrays accessed with NIO.
- */
- private class IndexedByRefGeometryNIO extends ByRefGeometryNIO {
- IndexArrays ia = new IndexArrays() ;
- VertexIndices vi = new VertexIndices() ;
-
- IndexedByRefGeometryNIO(GeometryArray ga) {
- super(ga) ;
- getIndexArrays(ga, ia) ;
- }
-
- @Override
- public void processVertex(int v, int stripFlag) {
- getVertexIndices(v, ia, vi) ;
- copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
- processIndexedVertexCopy(vc, vi, stripFlag) ;
- }
- }
-
- /**
- * Convert a GeometryArray to compression stream elements and add them to
- * this stream.
- *
- * @param ga GeometryArray to convert
- * @exception IllegalArgumentException if GeometryArray has a
- * dimensionality or vertex format inconsistent with the CompressionStream
- */
- void addGeometryArray(GeometryArray ga) {
- int firstVertex = 0 ;
- int validVertexCount = 0 ;
- int vertexFormat = ga.getVertexFormat() ;
- GeometryAccessor geometryAccessor = null ;
-
- if (streamType != getStreamType(ga))
- throw new IllegalArgumentException
- ("GeometryArray has inconsistent dimensionality") ;
-
- if (vertexComponents != getVertexComponents(vertexFormat))
- throw new IllegalArgumentException
- ("GeometryArray has inconsistent vertex components") ;
-
- // Set up for vertex data access semantics.
- boolean NIO = (vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 ;
- boolean byRef = (vertexFormat & GeometryArray.BY_REFERENCE) != 0 ;
- boolean interleaved = (vertexFormat & GeometryArray.INTERLEAVED) != 0 ;
- boolean indexedGeometry = ga instanceof IndexedGeometryArray ;
-
- if (indexedGeometry) {
- if (debug) System.out.println("indexed") ;
- // Index arrays will be copied such that valid indices start at
- // offset 0 in the copied arrays.
- firstVertex = 0 ;
- validVertexCount = ((IndexedGeometryArray)ga).getValidIndexCount() ;
- }
-
- if (!byRef) {
- if (debug) System.out.println("by-copy") ;
- if (indexedGeometry) {
- geometryAccessor = new IndexedByCopyGeometry(ga) ;
- }
- else {
- firstVertex = 0 ;
- validVertexCount = ga.getValidVertexCount() ;
- geometryAccessor = new ByCopyGeometry(ga) ;
- }
- }
- else if (interleaved && NIO) {
- if (debug) System.out.println("interleaved NIO") ;
- if (indexedGeometry) {
- geometryAccessor = new IndexedInterleavedGeometryNIO(ga) ;
- }
- else {
- firstVertex = ga.getInitialVertexIndex() ;
- validVertexCount = ga.getValidVertexCount() ;
- geometryAccessor = new InterleavedGeometryNIO(ga) ;
- }
- }
- else if (interleaved && !NIO) {
- if (debug) System.out.println("interleaved") ;
- if (indexedGeometry) {
- geometryAccessor = new IndexedInterleavedGeometryFloat(ga) ;
- }
- else {
- firstVertex = ga.getInitialVertexIndex() ;
- validVertexCount = ga.getValidVertexCount() ;
- geometryAccessor = new InterleavedGeometryFloat(ga) ;
- }
- }
- else if (!interleaved && NIO) {
- if (debug) System.out.println("non-interleaved NIO") ;
- if (indexedGeometry) {
- geometryAccessor = new IndexedByRefGeometryNIO(ga) ;
- }
- else {
- firstVertex = 0 ;
- validVertexCount = ga.getValidVertexCount() ;
- geometryAccessor = new ByRefGeometryNIO(ga) ;
- }
- }
- else if (!interleaved && !NIO) {
- if (debug) System.out.println("non-interleaved by-ref") ;
- if (indexedGeometry) {
- geometryAccessor = new IndexedByRefGeometry(ga) ;
- }
- else {
- firstVertex = 0 ;
- validVertexCount = ga.getValidVertexCount() ;
- geometryAccessor = new ByRefGeometry(ga) ;
- }
- }
-
- // Set up for topology.
- int stripCount = 0 ;
- int stripCounts[] = null ;
- int constantStripLength = 0 ;
- int replaceCode = RESTART ;
- boolean strips = false ;
- boolean implicitStrips = false ;
-
- if (ga instanceof TriangleStripArray ||
- ga instanceof IndexedTriangleStripArray ||
- ga instanceof LineStripArray ||
- ga instanceof IndexedLineStripArray) {
-
- strips = true ;
- replaceCode = REPLACE_OLDEST ;
- if (debug) System.out.println("strips") ;
- }
- else if (ga instanceof TriangleFanArray ||
- ga instanceof IndexedTriangleFanArray) {
-
- strips = true ;
- replaceCode = REPLACE_MIDDLE ;
- if (debug) System.out.println("fans") ;
- }
- else if (ga instanceof QuadArray ||
- ga instanceof IndexedQuadArray) {
-
- // Handled as fan arrays with 4 vertices per fan.
- implicitStrips = true ;
- constantStripLength = 4 ;
- replaceCode = REPLACE_MIDDLE ;
- if (debug) System.out.println("quads") ;
- }
-
- // Get strip counts.
- if (strips) {
- if (indexedGeometry) {
- IndexedGeometryStripArray igsa ;
- igsa = (IndexedGeometryStripArray)ga ;
-
- stripCount = igsa.getNumStrips() ;
- stripCounts = new int[stripCount] ;
- igsa.getStripIndexCounts(stripCounts) ;
-
- } else {
- GeometryStripArray gsa ;
- gsa = (GeometryStripArray)ga ;
-
- stripCount = gsa.getNumStrips() ;
- stripCounts = new int[stripCount] ;
- gsa.getStripVertexCounts(stripCounts) ;
- }
- }
-
- // Build the compression stream for this shape's geometry.
- int v = firstVertex ;
- if (strips) {
- for (int i = 0 ; i < stripCount ; i++) {
- geometryAccessor.processVertex(v++, RESTART) ;
- for (int j = 1 ; j < stripCounts[i] ; j++) {
- geometryAccessor.processVertex(v++, replaceCode) ;
- }
- }
- }
- else if (implicitStrips) {
- while (v < firstVertex + validVertexCount) {
- geometryAccessor.processVertex(v++, RESTART) ;
- for (int j = 1 ; j < constantStripLength ; j++) {
- geometryAccessor.processVertex(v++, replaceCode) ;
- }
- }
- }
- else {
- while (v < firstVertex + validVertexCount) {
- geometryAccessor.processVertex(v++, RESTART) ;
- }
- }
- }
-
- /**
- * Print the stream to standard output.
- */
- void print() {
- System.out.println("\nstream has " + stream.size() + " entries") ;
- System.out.println("uncompressed size " + byteCount + " bytes") ;
- System.out.println("upper position bound: " + mcBounds[1].toString()) ;
- System.out.println("lower position bound: " + mcBounds[0].toString()) ;
- System.out.println("X, Y, Z centers (" +
- ((float)center[0]) + " " +
- ((float)center[1]) + " " +
- ((float)center[2]) + ")\n" +
- "scale " + ((float)scale) + "\n") ;
-
- Iterator i = stream.iterator() ;
- while (i.hasNext()) {
- System.out.println(i.next().toString() + "\n") ;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////
- // //
- // The following constructors and methods are currently the only public //
- // members of this class. All other members are subject to revision. //
- // //
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Creates a CompressionStream from an array of Shape3D scene graph
- * objects. These Shape3D objects may only consist of a GeometryArray
- * component and an optional Appearance component. The resulting stream
- * may be used as input to the GeometryCompressor methods.
- *
- * Each Shape3D in the array must be of the same dimensionality (point,
- * line, or surface) and have the same vertex format as the others.
- * Texture coordinates are ignored.
- *
- * If a color is specified in the material attributes for a Shape3D then
- * that color is added to the CompressionStream as the current global
- * color. Subsequent colors as well as any colors bundled with vertices
- * will override it. Only the material diffuse colors are used; all other
- * appearance attributes are ignored.
- *
- * @param positionQuant
- * number of bits to quantize each position's X, Y,
- * and Z components, ranging from 1 to 16
- *
- * @param colorQuant
- * number of bits to quantize each color's R, G, B, and
- * alpha components, ranging from 2 to 16
- *
- * @param normalQuant
- * number of bits for quantizing each normal's U and V components, ranging
- * from 0 to 6
- *
- * @param shapes
- * an array of Shape3D scene graph objects containing
- * GeometryArray objects, all with the same vertex format and
- * dimensionality
- *
- * @exception IllegalArgumentException if any Shape3D has an inconsistent
- * dimensionality or vertex format, or if any Shape3D contains a geometry
- * component that is not a GeometryArray
- *
- * @see Shape3D
- * @see GeometryArray
- * @see GeometryCompressor
- */
- public CompressionStream(int positionQuant, int colorQuant,
- int normalQuant, Shape3D shapes[]) {
- this() ;
- if (debug) System.out.println("CompressionStream(Shape3D[]):") ;
-
- if (shapes == null)
- throw new IllegalArgumentException("null Shape3D array") ;
-
- if (shapes.length == 0)
- throw new IllegalArgumentException("zero-length Shape3D array") ;
-
- if (shapes[0] == null)
- throw new IllegalArgumentException("Shape3D at index 0 is null") ;
-
- long startTime = 0 ;
- if (benchmark) startTime = System.currentTimeMillis() ;
-
- Geometry g = shapes[0].getGeometry() ;
- if (! (g instanceof GeometryArray))
- throw new IllegalArgumentException
- ("Shape3D at index 0 is not a GeometryArray") ;
-
- GeometryArray ga = (GeometryArray)g ;
- this.streamType = getStreamType(ga) ;
- this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ;
-
- // Add global quantization parameters to the start of the stream.
- addPositionQuantization(positionQuant) ;
- addColorQuantization(colorQuant) ;
- addNormalQuantization(normalQuant) ;
-
- // Loop through all shapes.
- for (int s = 0 ; s < shapes.length ; s++) {
- if (debug) System.out.println("\nShape3D " + s + ":") ;
-
- g = shapes[s].getGeometry() ;
- if (! (g instanceof GeometryArray))
- throw new IllegalArgumentException
- ("Shape3D at index " + s + " is not a GeometryArray") ;
-
- // Check for material color and add it to the stream if it exists.
- Appearance a = shapes[s].getAppearance() ;
- if (a != null) {
- Material m = a.getMaterial() ;
- if (m != null) {
- m.getDiffuseColor(c3f) ;
- if (vertexColor4) {
- c4f.set(c3f.x, c3f.y, c3f.z, 1.0f) ;
- addColor(c4f) ;
- } else
- addColor(c3f) ;
- }
- }
-
- // Add the geometry array to the stream.
- addGeometryArray((GeometryArray)g) ;
- }
-
- if (benchmark) {
- long t = System.currentTimeMillis() - startTime ;
- System.out.println
- ("\nCompressionStream:\n" + shapes.length + " shapes in " +
- (t / 1000f) + " sec") ;
- }
- }
-
- /**
- * Creates a CompressionStream from an array of Shape3D scene graph
- * objects. These Shape3D objects may only consist of a GeometryArray
- * component and an optional Appearance component. The resulting stream
- * may be used as input to the GeometryCompressor methods.
- *
- * Each Shape3D in the array must be of the same dimensionality (point,
- * line, or surface) and have the same vertex format as the others.
- * Texture coordinates are ignored.
- *
- * If a color is specified in the material attributes for a Shape3D then
- * that color is added to the CompressionStream as the current global
- * color. Subsequent colors as well as any colors bundled with vertices
- * will override it. Only the material diffuse colors are used; all other
- * appearance attributes are ignored.
- *
- * Defaults of 16, 9, and 6 bits are used as the quantization values for
- * positions, colors, and normals respectively. These are the maximum
- * resolution values defined for positions and normals; the default of 9
- * for color is the equivalent of the 8 bits of RGBA component resolution
- * commonly available in graphics frame buffers.
- *
- * @param shapes
- * an array of Shape3D scene graph objects containing
- * GeometryArray objects, all with the same vertex format and
- * dimensionality.
- *
- * @exception IllegalArgumentException if any Shape3D has an inconsistent
- * dimensionality or vertex format, or if any Shape3D contains a geometry
- * component that is not a GeometryArray
- *
- * @see Shape3D
- * @see GeometryArray
- * @see GeometryCompressor
- */
- public CompressionStream(Shape3D shapes[]) {
- this(16, 9, 6, shapes) ;
- }
-
- /**
- * Creates a CompressionStream from an array of GeometryInfo objects. The
- * resulting stream may be used as input to the GeometryCompressor
- * methods.
- *
- * Each GeometryInfo in the array must be of the same dimensionality
- * (point, line, or surface) and have the same vertex format as the
- * others. Texture coordinates are ignored.
- *
- * @param positionQuant
- * number of bits to quantize each position's X, Y,
- * and Z components, ranging from 1 to 16
- *
- * @param colorQuant
- * number of bits to quantize each color's R, G, B, and
- * alpha components, ranging from 2 to 16
- *
- * @param normalQuant
- * number of bits for quantizing each normal's U and V components, ranging
- * from 0 to 6
- *
- * @param geometry
- * an array of GeometryInfo objects, all with the same
- * vertex format and dimensionality
- *
- * @exception IllegalArgumentException if any GeometryInfo object has an
- * inconsistent dimensionality or vertex format
- *
- * @see GeometryInfo
- * @see GeometryCompressor
- */
- public CompressionStream(int positionQuant, int colorQuant,
- int normalQuant, GeometryInfo geometry[]) {
- this() ;
- if (debug) System.out.println("CompressionStream(GeometryInfo[])") ;
-
- if (geometry == null)
- throw new IllegalArgumentException("null GeometryInfo array") ;
-
- if (geometry.length == 0)
- throw new IllegalArgumentException
- ("zero-length GeometryInfo array") ;
-
- if (geometry[0] == null)
- throw new IllegalArgumentException
- ("GeometryInfo at index 0 is null") ;
-
- long startTime = 0 ;
- if (benchmark) startTime = System.currentTimeMillis() ;
-
- GeometryArray ga = geometry[0].getGeometryArray() ;
- this.streamType = getStreamType(ga) ;
- this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ;
-
- // Add global quantization parameters to the start of the stream.
- addPositionQuantization(positionQuant) ;
- addColorQuantization(colorQuant) ;
- addNormalQuantization(normalQuant) ;
-
- // Loop through all GeometryInfo objects and add them to the stream.
- for (int i = 0 ; i < geometry.length ; i++) {
- if (debug) System.out.println("\nGeometryInfo " + i + ":") ;
- addGeometryArray(geometry[i].getGeometryArray()) ;
- }
-
- if (benchmark) {
- long t = System.currentTimeMillis() - startTime ;
- System.out.println
- ("\nCompressionStream:\n" + geometry.length +
- " GeometryInfo objects in " + (t / 1000f) + " sec") ;
- }
- }
-
- /**
- * Creates a CompressionStream from an array of GeometryInfo objects. The
- * resulting stream may be used as input to the GeometryCompressor
- * methods.
- *
- * Each GeometryInfo in the array must be of the same dimensionality
- * (point, line, or surface) and have the same vertex format as the
- * others. Texture coordinates are ignored.
- *
- * Defaults of 16, 9, and 6 bits are used as the quantization values for
- * positions, colors, and normals respectively. These are the maximum
- * resolution values defined for positions and normals; the default of 9
- * for color is the equivalent of the 8 bits of RGBA component resolution
- * commonly available in graphics frame buffers.
- *
- * @param geometry
- * an array of GeometryInfo objects, all with the same
- * vertex format and dimensionality
- *
- * @exception IllegalArgumentException if any GeometryInfo object has an
- * inconsistent dimensionality or vertex format
- *
- * @see GeometryInfo
- * @see GeometryCompressor
- */
- public CompressionStream(GeometryInfo geometry[]) {
- this(16, 9, 6, geometry) ;
- }
-
- /**
- * Get the original bounds of the coordinate data, in modeling coordinates.
- * Coordinate data is positioned and scaled to a normalized cube after
- * compression.
- *
- * @return Point3d array of length 2, where the 1st Point3d is the lower
- * bounds and the 2nd Point3d is the upper bounds.
- * @since Java 3D 1.3
- */
- public Point3d[] getModelBounds() {
- Point3d[] bounds = new Point3d[2] ;
- bounds[0] = new Point3d(mcBounds[0]) ;
- bounds[1] = new Point3d(mcBounds[1]) ;
- return bounds ;
- }
-
- /**
- * Get the bounds of the compressed object in normalized coordinates.
- * These have an maximum bounds by [-1.0 .. +1.0] across each axis.
- *
- * @return Point3d array of length 2, where the 1st Point3d is the lower
- * bounds and the 2nd Point3d is the upper bounds.
- * @since Java 3D 1.3
- */
- public Point3d[] getNormalizedBounds() {
- Point3d[] bounds = new Point3d[2] ;
- bounds[0] = new Point3d(ncBounds[0]) ;
- bounds[1] = new Point3d(ncBounds[1]) ;
- return bounds ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamColor.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamColor.java
deleted file mode 100644
index ad9263b..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamColor.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4f;
-
-/**
- * This class represents a color in a compression stream. It maintains both
- * floating-point and quantized representations. This color may be bundled
- * with a vertex or exist separately as a global color.
- */
-class CompressionStreamColor extends CompressionStreamElement {
- private int R, G, B, A ;
- private boolean color3 ;
- private boolean color4 ;
- private float colorR, colorG, colorB, colorA ;
-
- int rAbsolute, gAbsolute, bAbsolute, aAbsolute ;
-
- /**
- * Create a CompressionStreamColor.
- *
- * @param stream CompressionStream associated with this element
- * @param color3 floating-point representation to be encoded
- */
- CompressionStreamColor(CompressionStream stream, Color3f c3) {
- this.color4 = false ;
- this.color3 = true ;
- colorR = c3.x ;
- colorG = c3.y ;
- colorB = c3.z ;
- colorA = 0.0f ;
- stream.byteCount += 12 ;
- }
-
- /**
- * Create a CompressionStreamColor.
- *
- * @param stream CompressionStream associated with this element
- * @param color4 floating-point representation to be encoded
- */
- CompressionStreamColor(CompressionStream stream, Color4f c4) {
- this.color3 = false ;
- this.color4 = true ;
- colorR = c4.x ;
- colorG = c4.y ;
- colorB = c4.z ;
- colorA = c4.w ;
- stream.byteCount += 16 ;
- }
-
- /**
- * Quantize a floating point color to fixed point integer components of
- * the specified number of bits. The bit length can range from a maximum
- * of 16 to a minimum of 2 bits since negative colors are not defined.
- *
- * The bit length is the total number of bits in the signed version of the
- * fixed point representation of the input color, which is assumed to
- * be normalized into the [0..1) range. With the maximum bit length of
- * 16, 15 bits of positive colors can be represented; a bit length of 9 is
- * needed to get the 8 bit positive color size in common use.
- *
- * @param stream CompressionStream associated with this element
- * @param table HuffmanTable for collecting data about the quantized
- * representation of this element
- */
- @Override
- void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
- // Clamp quantization.
- int quant =
- (stream.colorQuant < 2? 2 :
- (stream.colorQuant > 16? 16 : stream.colorQuant)) ;
-
- absolute = false ;
- if (stream.firstColor || stream.colorQuantChanged) {
- absolute = true ;
- stream.lastColor[0] = 0 ;
- stream.lastColor[1] = 0 ;
- stream.lastColor[2] = 0 ;
- stream.lastColor[3] = 0 ;
- stream.firstColor = false ;
- stream.colorQuantChanged = false ;
- }
-
- // Convert the floating point position to s.15 2's complement.
- if (color3) {
- R = (int)(colorR * 32768.0) ;
- G = (int)(colorG * 32768.0) ;
- B = (int)(colorB * 32768.0) ;
- A = 0 ;
- } else if (color4) {
- R = (int)(colorR * 32768.0) ;
- G = (int)(colorG * 32768.0) ;
- B = (int)(colorB * 32768.0) ;
- A = (int)(colorA * 32768.0) ;
- }
-
- // Clamp color components.
- R = (R > 32767? 32767: (R < 0? 0: R)) ;
- G = (G > 32767? 32767: (G < 0? 0: G)) ;
- B = (B > 32767? 32767: (B < 0? 0: B)) ;
- A = (A > 32767? 32767: (A < 0? 0: A)) ;
-
- // Compute quantized values.
- R &= quantizationMask[quant] ;
- G &= quantizationMask[quant] ;
- B &= quantizationMask[quant] ;
- A &= quantizationMask[quant] ;
-
- // Copy and retain absolute color for mesh buffer lookup.
- rAbsolute = R ;
- gAbsolute = G ;
- bAbsolute = B ;
- aAbsolute = A ;
-
- // Compute deltas.
- R -= stream.lastColor[0] ;
- G -= stream.lastColor[1] ;
- B -= stream.lastColor[2] ;
- A -= stream.lastColor[3] ;
-
- // Update last values.
- stream.lastColor[0] += R ;
- stream.lastColor[1] += G ;
- stream.lastColor[2] += B ;
- stream.lastColor[3] += A ;
-
- // Compute length and shift common to all components.
- if (color3)
- computeLengthShift(R, G, B) ;
-
- else if (color4)
- computeLengthShift(R, G, B, A) ;
-
- // 0-length components are allowed only for normals.
- if (length == 0)
- length = 1 ;
-
- // Add this element to the Huffman table associated with this stream.
- huffmanTable.addColorEntry(length, shift, absolute) ;
- }
-
- /**
- * Output a setColor command.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- @Override
- void outputCommand(HuffmanTable table, CommandStream output) {
- outputColor(table, output, CommandStream.SET_COLOR, 8) ;
- }
-
- /**
- * Output a color subcommand.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- void outputSubcommand(HuffmanTable table, CommandStream output) {
-
- outputColor(table, output, 0, 6) ;
- }
-
- //
- // Output the final compressed bits to the output command stream.
- //
- private void outputColor(HuffmanTable table, CommandStream output,
- int header, int headerLength) {
- HuffmanNode t ;
-
- // Look up the Huffman token for this compression stream element.
- t = table.getColorEntry(length, shift, absolute) ;
-
- // Construct the color subcommand components. The maximum length of a
- // color subcommand is 70 bits (a tag with a length of 6 followed by 4
- // components of 16 bits each). The subcommand is therefore
- // constructed initially using just the first 3 components, with the
- // 4th component added later after the tag has been shifted into the
- // subcommand header.
- int componentLength = t.dataLength - t.shift ;
- int subcommandLength = t.tagLength + (3 * componentLength) ;
-
- R = (R >> t.shift) & (int)lengthMask[componentLength] ;
- G = (G >> t.shift) & (int)lengthMask[componentLength] ;
- B = (B >> t.shift) & (int)lengthMask[componentLength] ;
-
- long colorSubcommand =
- (((long)t.tag) << (3 * componentLength)) |
- (((long)R) << (2 * componentLength)) |
- (((long)G) << (1 * componentLength)) |
- (((long)B) << (0 * componentLength)) ;
-
- if (subcommandLength < 6) {
- // The header will have some empty bits. The Huffman tag
- // computation will prevent this if necessary.
- header |= (int)(colorSubcommand << (6 - subcommandLength)) ;
- subcommandLength = 0 ;
- }
- else {
- // Move the 1st 6 bits of the subcommand into the header.
- header |= (int)(colorSubcommand >>> (subcommandLength - 6)) ;
- subcommandLength -= 6 ;
- }
-
- // Add alpha if present.
- if (color4) {
- A = (A >> t.shift) & (int)lengthMask[componentLength] ;
- colorSubcommand = (colorSubcommand << componentLength) | A ;
- subcommandLength += componentLength ;
- }
-
- // Add the header and body to the output buffer.
- output.addCommand(header, headerLength,
- colorSubcommand, subcommandLength) ;
- }
-
- @Override
- public String toString() {
- String d = absolute? "" : "delta " ;
- String c = (colorR + " " + colorG + " " + colorB +
- (color4? (" " + colorA): "")) ;
-
- return
- "color: " + c + "\n" +
- " fixed point " + d + + R + " " + G + " " + B + "\n" +
- " length " + length + " shift " + shift +
- (absolute? " absolute" : " relative") ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamElement.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamElement.java
deleted file mode 100644
index 2e8fe98..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamElement.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-/**
- * Instances of this class are used as elements in a CompressionStream.
- * @see CompressionStream
- */
-abstract class CompressionStreamElement {
- /**
- * Bit length of quantized geometric components.
- */
- int length ;
-
- /**
- * Number of trailing zeros in quantized geometric components.
- */
- int shift ;
-
- /**
- * If false, geometric component values are represented as differences
- * from those of the preceding element in the stream.
- */
- boolean absolute ;
-
- /**
- * Array with elements that can be used as masks to apply a quantization
- * to the number of bits indicated by the referencing index [0..16].
- */
- static final int quantizationMask[] = {
- 0xFFFF0000, 0xFFFF8000, 0xFFFFC000, 0xFFFFE000,
- 0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00,
- 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0,
- 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE,
- 0xFFFFFFFF
- } ;
-
- /**
- * Array with elements that can be used as masks to retain the number of
- * trailing bits of data indicated by the referencing index [0..64]. Used
- * to clear the leading sign bits of fixed-point 2's complement numbers
- * and in building the compressed output stream.
- */
- static final long lengthMask[] = {
- 0x0000000000000000L, 0x0000000000000001L,
- 0x0000000000000003L, 0x0000000000000007L,
- 0x000000000000000FL, 0x000000000000001FL,
- 0x000000000000003FL, 0x000000000000007FL,
- 0x00000000000000FFL, 0x00000000000001FFL,
- 0x00000000000003FFL, 0x00000000000007FFL,
- 0x0000000000000FFFL, 0x0000000000001FFFL,
- 0x0000000000003FFFL, 0x0000000000007FFFL,
- 0x000000000000FFFFL, 0x000000000001FFFFL,
- 0x000000000003FFFFL, 0x000000000007FFFFL,
- 0x00000000000FFFFFL, 0x00000000001FFFFFL,
- 0x00000000003FFFFFL, 0x00000000007FFFFFL,
- 0x0000000000FFFFFFL, 0x0000000001FFFFFFL,
- 0x0000000003FFFFFFL, 0x0000000007FFFFFFL,
- 0x000000000FFFFFFFL, 0x000000001FFFFFFFL,
- 0x000000003FFFFFFFL, 0x000000007FFFFFFFL,
- 0x00000000FFFFFFFFL, 0x00000001FFFFFFFFL,
- 0x00000003FFFFFFFFL, 0x00000007FFFFFFFFL,
- 0x0000000FFFFFFFFFL, 0x0000001FFFFFFFFFL,
- 0x0000003FFFFFFFFFL, 0x0000007FFFFFFFFFL,
- 0x000000FFFFFFFFFFL, 0x000001FFFFFFFFFFL,
- 0x000003FFFFFFFFFFL, 0x000007FFFFFFFFFFL,
- 0x00000FFFFFFFFFFFL, 0x00001FFFFFFFFFFFL,
- 0x00003FFFFFFFFFFFL, 0x00007FFFFFFFFFFFL,
- 0x0000FFFFFFFFFFFFL, 0x0001FFFFFFFFFFFFL,
- 0x0003FFFFFFFFFFFFL, 0x0007FFFFFFFFFFFFL,
- 0x000FFFFFFFFFFFFFL, 0x001FFFFFFFFFFFFFL,
- 0x003FFFFFFFFFFFFFL, 0x007FFFFFFFFFFFFFL,
- 0x00FFFFFFFFFFFFFFL, 0x01FFFFFFFFFFFFFFL,
- 0x03FFFFFFFFFFFFFFL, 0x07FFFFFFFFFFFFFFL,
- 0x0FFFFFFFFFFFFFFFL, 0x1FFFFFFFFFFFFFFFL,
- 0x3FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL,
- 0xFFFFFFFFFFFFFFFFL
- } ;
-
-
- /**
- * Computes the quantized representation of this stream element.
- *
- * @param stream CompressionStream associated with this element
- * @param table HuffmanTable for collecting data about the quantized
- * representation of this element
- */
- abstract void quantize(CompressionStream stream, HuffmanTable table) ;
-
- /**
- * Outputs the compressed bits representing this stream element.
- * Some instances of CompressionStreamElement don't require an
- * implementation and will inherit the stub provided here.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- void outputCommand(HuffmanTable table, CommandStream output) {
- }
-
- /**
- * Finds the minimum bits needed to represent the given 16-bit signed 2's
- * complement integer. For positive integers, this include the first
- * 1 starting from the left, plus a 0 sign bit; for negative integers,
- * this includes the first 0 starting from the left, plus a 1 sign bit.
- * 0 is a special case returning 0; however, 0-length components are valid
- * ONLY for normals.
- *
- * The decompressor uses the data length to determine how many bits of
- * sign extension to add to the data coming in from the compressed stream
- * in order to create a 16-bit signed 2's complement integer. E.g., a data
- * length of 12 indicates that 16-12=4 bits of sign are to be extended.
- *
- * @param number a signed 2's complement integer representable in 16 bits
- * or less
- * @return minimum number of bits to represent the number
- */
- private static final int getLength(int number) {
- if (number == 0)
- return 0 ;
-
- else if ((number & 0x8000) > 0) {
- // negative numbers
- if ((number & 0x4000) == 0) return 16 ;
- if ((number & 0x2000) == 0) return 15 ;
- if ((number & 0x1000) == 0) return 14 ;
- if ((number & 0x0800) == 0) return 13 ;
- if ((number & 0x0400) == 0) return 12 ;
- if ((number & 0x0200) == 0) return 11 ;
- if ((number & 0x0100) == 0) return 10 ;
- if ((number & 0x0080) == 0) return 9 ;
- if ((number & 0x0040) == 0) return 8 ;
- if ((number & 0x0020) == 0) return 7 ;
- if ((number & 0x0010) == 0) return 6 ;
- if ((number & 0x0008) == 0) return 5 ;
- if ((number & 0x0004) == 0) return 4 ;
- if ((number & 0x0002) == 0) return 3 ;
- if ((number & 0x0001) == 0) return 2 ;
-
- return 1 ;
-
- } else {
- // positive numbers
- if ((number & 0x4000) > 0) return 16 ;
- if ((number & 0x2000) > 0) return 15 ;
- if ((number & 0x1000) > 0) return 14 ;
- if ((number & 0x0800) > 0) return 13 ;
- if ((number & 0x0400) > 0) return 12 ;
- if ((number & 0x0200) > 0) return 11 ;
- if ((number & 0x0100) > 0) return 10 ;
- if ((number & 0x0080) > 0) return 9 ;
- if ((number & 0x0040) > 0) return 8 ;
- if ((number & 0x0020) > 0) return 7 ;
- if ((number & 0x0010) > 0) return 6 ;
- if ((number & 0x0008) > 0) return 5 ;
- if ((number & 0x0004) > 0) return 4 ;
- if ((number & 0x0002) > 0) return 3 ;
-
- return 2 ;
- }
- }
-
- /**
- * Finds the rightmost 1 bit in the given 16-bit integer. This value is
- * used by the decompressor to indicate the number of trailing zeros to be
- * added to the end of the data coming in from the compressed stream,
- * accomplished by left shifting the data by the indicated amount.
- * 0 is a special case returning 0.
- *
- * @param number an integer representable in 16 bits or less
- * @return number of trailing zeros
- */
- private static final int getShift(int number) {
- if (number == 0) return 0 ;
-
- if ((number & 0x0001) > 0) return 0 ;
- if ((number & 0x0002) > 0) return 1 ;
- if ((number & 0x0004) > 0) return 2 ;
- if ((number & 0x0008) > 0) return 3 ;
- if ((number & 0x0010) > 0) return 4 ;
- if ((number & 0x0020) > 0) return 5 ;
- if ((number & 0x0040) > 0) return 6 ;
- if ((number & 0x0080) > 0) return 7 ;
- if ((number & 0x0100) > 0) return 8 ;
- if ((number & 0x0200) > 0) return 9 ;
- if ((number & 0x0400) > 0) return 10 ;
- if ((number & 0x0800) > 0) return 11 ;
- if ((number & 0x1000) > 0) return 12 ;
- if ((number & 0x2000) > 0) return 13 ;
- if ((number & 0x4000) > 0) return 14 ;
-
- return 15 ;
- }
-
- /**
- * Computes common length and shift of 2 numbers.
- */
- final void computeLengthShift(int n0, int n1) {
- int s0 = n0 & 0x8000 ;
- int s1 = n1 & 0x8000 ;
-
- // equal sign optimization
- if (s0 == s1)
- if (s0 == 0)
- this.length = getLength(n0 | n1) ;
- else
- this.length = getLength(n0 & n1) ;
- else
- this.length = getMaximum(getLength(n0), getLength(n1)) ;
-
- this.shift = getShift(n0 | n1) ;
- }
-
-
- /**
- * Computes common length and shift of 3 numbers.
- */
- final void computeLengthShift(int n0, int n1, int n2) {
- int s0 = n0 & 0x8000 ;
- int s1 = n1 & 0x8000 ;
- int s2 = n2 & 0x8000 ;
-
- // equal sign optimization
- if (s0 == s1)
- if (s1 == s2)
- if (s2 == 0)
- this.length = getLength(n0 | n1 | n2) ;
- else
- this.length = getLength(n0 & n1 & n2) ;
- else
- if (s1 == 0)
- this.length = getMaximum(getLength(n0 | n1),
- getLength(n2)) ;
- else
- this.length = getMaximum(getLength(n0 & n1),
- getLength(n2)) ;
- else
- if (s1 == s2)
- if (s2 == 0)
- this.length = getMaximum(getLength(n1 | n2),
- getLength(n0)) ;
- else
- this.length = getMaximum(getLength(n1 & n2),
- getLength(n0)) ;
- else
- if (s0 == 0)
- this.length = getMaximum(getLength(n0 | n2),
- getLength(n1)) ;
- else
- this.length = getMaximum(getLength(n0 & n2),
- getLength(n1)) ;
-
- this.shift = getShift(n0 | n1 | n2) ;
- }
-
-
- /**
- * Computes common length and shift of 4 numbers.
- */
- final void computeLengthShift(int n0, int n1, int n2, int n3) {
- this.length = getMaximum(getLength(n0), getLength(n1),
- getLength(n2), getLength(n3)) ;
-
- this.shift = getShift(n0 | n1 | n2 | n3) ;
- }
-
-
- /**
- * Finds the maximum of two integers.
- */
- private static final int getMaximum(int x, int y) {
- if (x > y)
- return x ;
- else
- return y ;
- }
-
- /**
- * Finds the maximum of three integers.
- */
- private static final int getMaximum(int x, int y, int z) {
- if (x > y)
- if (x > z)
- return x ;
- else
- return z ;
- else
- if (y > z)
- return y ;
- else
- return z ;
- }
-
- /**
- * Finds the maximum of four integers.
- */
- private static final int getMaximum(int x, int y, int z, int w) {
- int n0, n1 ;
-
- if (x > y)
- n0 = x ;
- else
- n0 = y ;
-
- if (z > w)
- n1 = z ;
- else
- n1 = w ;
-
- if (n0 > n1)
- return n0 ;
- else
- return n1 ;
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamNormal.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamNormal.java
deleted file mode 100644
index 10b8704..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamNormal.java
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import javax.vecmath.Vector3f;
-
-/**
- * This class represents a normal in a compression stream. It maintains both
- * floating-point and quantized representations. This normal may be bundled
- * with a vertex or exist separately as a global normal.
- */
-class CompressionStreamNormal extends CompressionStreamElement {
- private int u, v ;
- private int specialOctant, specialSextant ;
- private float normalX, normalY, normalZ ;
-
- int octant, sextant ;
- boolean specialNormal ;
- int uAbsolute, vAbsolute ;
-
- /**
- * Create a CompressionStreamNormal.
- *
- * @param stream CompressionStream associated with this element
- * @param normal floating-point representation to be encoded
- */
- CompressionStreamNormal(CompressionStream stream, Vector3f normal) {
- this.normalX = normal.x ;
- this.normalY = normal.y ;
- this.normalZ = normal.z ;
- stream.byteCount += 12 ;
- }
-
- //
- // Normal Encoding Parameterization
- //
- // A floating point normal is quantized to a desired number of bits by
- // comparing it to candidate entries in a table of every possible normal
- // at that quantization and finding the closest match. This table of
- // normals is indexed by the following encoding:
- //
- // First, points on a unit radius sphere are parameterized by two angles,
- // th and psi, using usual spherical coordinates. th is the angle about
- // the y axis, psi is the inclination to the plane containing the point.
- // The mapping between rectangular and spherical coordinates is:
- //
- // x = cos(th)*cos(psi)
- // y = sin(psi)
- // z = sin(th)*cos(psi)
- //
- // Points on sphere are folded first by octant, and then by sort order
- // of xyz into one of six sextants. All the table encoding takes place in
- // the positive octant, in the region bounded by the half spaces:
- //
- // x >= z
- // z >= y
- // y >= 0
- //
- // This triangular shaped patch runs from 0 to 45 degrees in th, and
- // from 0 to as much as 0.615479709 (MAX_Y_ANG) in psi. The xyz bounds
- // of the patch is:
- //
- // (1, 0, 0) (1/sqrt(2), 0, 1/sqrt(2)) (1/sqrt(3), 1/sqrt(3), 1/sqrt(3))
- //
- // When dicing this space up into discrete points, the choice for y is
- // linear quantization in psi. This means that if the y range is to be
- // divided up into n segments, the angle of segment j is:
- //
- // psi(j) = MAX_Y_ANG*(j/n)
- //
- // The y height of the patch (in arc length) is *not* the same as the xz
- // dimension. However, the subdivision quantization needs to treat xz and
- // y equally. To achieve this, the th angles are re-parameterized as
- // reflected psi angles. That is, the i-th point's th is:
- //
- // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*(i/n)))
- //
- // To go the other direction, the angle th corresponds to the real index r
- // (in the same 0-n range as i):
- //
- // r(th) = n*atan(sin(th))/MAX_Y_ANG
- //
- // Rounded to the nearest integer, this gives the closest integer index i
- // to the xz angle th. Because the triangle has a straight edge on the
- // line x=z, it is more intuitive to index the xz angles in reverse
- // order. Thus the two equations above are replaced by:
- //
- // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*((n-i)/n)))
- //
- // r(th) = n*(1 - atan(sin(th))/MAX_Y_ANG)
- //
- // Each level of quantization subdivides the triangular patch twice as
- // densely. The case in which only the three vertices of the triangle are
- // present is the first logical stage of representation, but because of
- // how the table is encoded the first usable case starts one level of
- // sub-division later. This three point level has an n of 2 by the above
- // conventions.
- //
- private static final int MAX_UV_BITS = 6 ;
- private static final int MAX_UV_ENTRIES = 64 ;
-
- private static final double cgNormals[][][][] =
- new double[MAX_UV_BITS+1][MAX_UV_ENTRIES+1][MAX_UV_ENTRIES+1][3] ;
-
- private static final double MAX_Y_ANG = 0.615479709 ;
- private static final double UNITY_14 = 16384.0 ;
-
- private static void computeNormals() {
- int inx, iny, inz, n ;
- double th, psi, qnx, qny, qnz ;
-
- for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) {
- n = 1 << quant ;
-
- for (int j = 0 ; j <= n ; j++) {
- for (int i = 0 ; i <= n ; i++) {
- if (i+j > n) continue ;
-
- psi = MAX_Y_ANG*(j/((double) n)) ;
- th = Math.asin(Math.tan(MAX_Y_ANG*((n-i)/((double) n)))) ;
-
- qnx = Math.cos(th)*Math.cos(psi) ;
- qny = Math.sin(psi) ;
- qnz = Math.sin(th)*Math.cos(psi) ;
-
- // The normal table uses 16-bit components and must be
- // able to represent both +1.0 and -1.0, so convert the
- // floating point normal components to fixed point with 14
- // fractional bits, a unity bit, and a sign bit (s1.14).
- // Set them back to get the float equivalent.
- qnx = qnx*UNITY_14 ; inx = (int)qnx ;
- qnx = inx ; qnx = qnx/UNITY_14 ;
-
- qny = qny*UNITY_14 ; iny = (int)qny ;
- qny = iny ; qny = qny/UNITY_14 ;
-
- qnz = qnz*UNITY_14 ; inz = (int)qnz ;
- qnz = inz ; qnz = qnz/UNITY_14 ;
-
- cgNormals[quant][j][i][0] = qnx ;
- cgNormals[quant][j][i][1] = qny ;
- cgNormals[quant][j][i][2] = qnz ;
- }
- }
- }
- }
-
- //
- // An inverse sine table is used for each quantization level to take the Y
- // component of a normal (which is the sine of the inclination angle) and
- // obtain the closest quantized Y angle.
- //
- // At any level of compression, there are a fixed number of different Y
- // angles (between 0 and MAX_Y_ANG). The inverse table is built to have
- // slightly more than twice as many entries as y angles at any particular
- // level; this ensures that the inverse look-up will get within one angle
- // of the right one. The size of the table should be as small as
- // possible, but with its delta sine still smaller than the delta sine
- // between the last two angles to be encoded.
- //
- // Example: the inverse sine table has a maximum angle of 0.615479709. At
- // the maximum resolution of 6 bits there are 65 discrete angles used,
- // but twice as many are needed for thresholding between angles, so the
- // delta angle is 0.615479709/128. The difference then between the last
- // two angles to be encoded is:
- // sin(0.615479709*128.0/128.0) - sin(0.615479709*127.0/128.0) = 0.003932730
- //
- // Using 8 significent bits below the binary point, fixed point can
- // represent sines in increments of 0.003906250, just slightly smaller.
- // However, because the maximum Y angle sine is 0.577350269, only 148
- // instead of 256 table entries are needed.
- //
- private static final short inverseSine[][] = new short[MAX_UV_BITS+1][] ;
-
- // UNITY_14 * sin(MAX_Y_ANGLE)
- private static final short MAX_SIN_14BIT = 9459 ;
-
- private static void computeInverseSineTables() {
- int intSin, deltaSin, intAngle ;
- double floatSin, floatAngle ;
- short sin14[] = new short[MAX_UV_ENTRIES+1] ;
-
- // Build table of sines in s1.14 fixed point for each of the
- // discrete angles used at maximum resolution.
- for (int i = 0 ; i <= MAX_UV_ENTRIES ; i++) {
- sin14[i] = (short)(UNITY_14*Math.sin(i*MAX_Y_ANG/MAX_UV_ENTRIES)) ;
- }
-
- for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) {
- switch (quant) {
- default:
- case 6:
- // Delta angle: MAX_Y_ANGLE/128.0
- // Bits below binary point for fixed point delta sine: 8
- // Integer delta sine: 64
- // Inverse sine table size: 148 entries
- deltaSin = 1 << (14 - 8) ;
- break ;
- case 5:
- // Delta angle: MAX_Y_ANGLE/64.0
- // Bits below binary point for fixed point delta sine: 7
- // Integer delta sine: 128
- // Inverse sine table size: 74 entries
- deltaSin = 1 << (14 - 7) ;
- break ;
- case 4:
- // Delta angle: MAX_Y_ANGLE/32.0
- // Bits below binary point for fixed point delta sine: 6
- // Integer delta sine: 256
- // Inverse sine table size: 37 entries
- deltaSin = 1 << (14 - 6) ;
- break ;
- case 3:
- // Delta angle: MAX_Y_ANGLE/16.0
- // Bits below binary point for fixed point delta sine: 5
- // Integer delta sine: 512
- // Inverse sine table size: 19 entries
- deltaSin = 1 << (14 - 5) ;
- break ;
- case 2:
- // Delta angle: MAX_Y_ANGLE/8.0
- // Bits below binary point for fixed point delta sine: 4
- // Integer delta sine: 1024
- // Inverse sine table size: 10 entries
- deltaSin = 1 << (14 - 4) ;
- break ;
- case 1:
- // Delta angle: MAX_Y_ANGLE/4.0
- // Bits below binary point for fixed point delta sine: 3
- // Integer delta sine: 2048
- // Inverse sine table size: 5 entries
- deltaSin = 1 << (14 - 3) ;
- break ;
- case 0:
- // Delta angle: MAX_Y_ANGLE/2.0
- // Bits below binary point for fixed point delta sine: 2
- // Integer delta sine: 4096
- // Inverse sine table size: 3 entries
- deltaSin = 1 << (14 - 2) ;
- break ;
- }
-
- inverseSine[quant] = new short[(MAX_SIN_14BIT/deltaSin) + 1] ;
-
- intSin = 0 ;
- for (int i = 0 ; i < inverseSine[quant].length ; i++) {
- // Compute float representation of integer sine with desired
- // number of fractional bits by effectively right shifting 14.
- floatSin = intSin/UNITY_14 ;
-
- // Compute the angle with this sine value and quantize it.
- floatAngle = Math.asin(floatSin) ;
- intAngle = (int)((floatAngle/MAX_Y_ANG) * (1 << quant)) ;
-
- // Choose the closest of the three nearest quantized values
- // intAngle-1, intAngle, and intAngle+1.
- if (intAngle > 0) {
- if (Math.abs(sin14[intAngle << (6-quant)] - intSin) >
- Math.abs(sin14[(intAngle-1) << (6-quant)] - intSin))
- intAngle = intAngle-1 ;
- }
-
- if (intAngle < (1 << quant)) {
- if (Math.abs(sin14[intAngle << (6-quant)] - intSin) >
- Math.abs(sin14[(intAngle+1) << (6-quant)] - intSin))
- intAngle = intAngle+1 ;
- }
-
- inverseSine[quant][i] = (short)intAngle ;
- intSin += deltaSin ;
- }
- }
- }
-
- /**
- * Compute static tables needed for normal quantization.
- */
- static {
- computeNormals() ;
- computeInverseSineTables() ;
- }
-
- /**
- * Quantize the floating point normal to a 6-bit octant/sextant plus u,v
- * components of [0..6] bits. Full resolution is 18 bits and the minimum
- * is 6 bits.
- *
- * @param stream CompressionStream associated with this element
- * @param table HuffmanTable for collecting data about the quantized
- * representation of this element
- */
- @Override
- void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
- double nx, ny, nz, t ;
-
- // Clamp UV quantization.
- int quant =
- (stream.normalQuant < 0? 0 :
- (stream.normalQuant > 6? 6 : stream.normalQuant)) ;
-
- nx = normalX ;
- ny = normalY ;
- nz = normalZ ;
-
- octant = 0 ;
- sextant = 0 ;
- u = 0 ;
- v = 0 ;
-
- // Normalize the fixed point normal to the positive signed octant.
- if (nx < 0.0) {
- octant |= 4 ;
- nx = -nx ;
- }
- if (ny < 0.0) {
- octant |= 2 ;
- ny = -ny ;
- }
- if (nz < 0.0) {
- octant |= 1 ;
- nz = -nz ;
- }
-
- // Normalize the fixed point normal to the proper sextant of the octant.
- if (nx < ny) {
- sextant |= 1 ;
- t = nx ;
- nx = ny ;
- ny = t ;
- }
- if (nz < ny) {
- sextant |= 2 ;
- t = ny ;
- ny = nz ;
- nz = t ;
- }
- if (nx < nz) {
- sextant |= 4 ;
- t = nx ;
- nx = nz ;
- nz = t ;
- }
-
- // Convert the floating point y component to s1.14 fixed point.
- int yInt = (int)(ny * UNITY_14) ;
-
- // The y component of the normal is the sine of the y angle. Quantize
- // the y angle by using the fixed point y component as an index into
- // the inverse sine table of the correct size for the quantization
- // level. (12 - quant) bits of the s1.14 y normal component are
- // rolled off with a right shift; the remaining bits then match the
- // number of bits used to represent the delta sine of the table.
- int yIndex = inverseSine[quant][yInt >> (12-quant)] ;
-
- // Search the two xz rows near y for the best match.
- int ii = 0 ;
- int jj = 0 ;
- int n = 1 << quant ;
- double dot, bestDot = -1 ;
-
- for (int j = yIndex-1 ; j < yIndex+1 && j <= n ; j++) {
- if (j < 0)
- continue ;
-
- for (int i = 0 ; i <= n ; i++) {
- if (i+j > n)
- continue ;
-
- dot = nx * cgNormals[quant][j][i][0] +
- ny * cgNormals[quant][j][i][1] +
- nz * cgNormals[quant][j][i][2] ;
-
- if (dot > bestDot) {
- bestDot = dot ;
- ii = i ;
- jj = j ;
- }
- }
- }
-
- // Convert u and v to standard grid form.
- u = ii << (6 - quant) ;
- v = jj << (6 - quant) ;
-
- // Check for special normals and specially encode them.
- specialNormal = false ;
- if (u == 64 && v == 0) {
- // six coordinate axes case
- if (sextant == 0 || sextant == 2) {
- // +/- x-axis
- specialSextant = 0x6 ;
- specialOctant = ((octant & 4) != 0)? 0x2 : 0 ;
-
- } else if (sextant == 3 || sextant == 1) {
- // +/- y-axis
- specialSextant = 0x6 ;
- specialOctant = 4 | (((octant & 2) != 0)? 0x2 : 0) ;
-
- } else if (sextant == 5 || sextant == 4) {
- // +/- z-axis
- specialSextant = 0x7 ;
- specialOctant = ((octant & 1) != 0)? 0x2 : 0 ;
- }
- specialNormal = true ;
- u = v = 0 ;
-
- } else if (u == 0 && v == 64) {
- // eight mid point case
- specialSextant = 6 | (octant >> 2) ;
- specialOctant = ((octant & 0x3) << 1) | 1 ;
- specialNormal = true ;
- u = v = 0 ;
- }
-
- // Compute deltas if possible.
- // Use the non-normalized ii and jj indices.
- int du = 0 ;
- int dv = 0 ;
- int uv64 = 64 >> (6 - quant) ;
-
- absolute = false ;
- if (stream.firstNormal || stream.normalQuantChanged ||
- stream.lastSpecialNormal || specialNormal) {
- // The first normal by definition is absolute, and normals cannot
- // be represented as deltas to or from special normals, nor from
- // normals with a different quantization.
- absolute = true ;
- stream.firstNormal = false ;
- stream.normalQuantChanged = false ;
-
- } else if (stream.lastOctant == octant &&
- stream.lastSextant == sextant) {
- // Deltas are always allowed within the same sextant/octant.
- du = ii - stream.lastU ;
- dv = jj - stream.lastV ;
-
- } else if (stream.lastOctant != octant &&
- stream.lastSextant == sextant &&
- (((sextant == 1 || sextant == 5) &&
- (stream.lastOctant & 3) == (octant & 3)) ||
- ((sextant == 0 || sextant == 4) &&
- (stream.lastOctant & 5) == (octant & 5)) ||
- ((sextant == 2 || sextant == 3) &&
- (stream.lastOctant & 6) == (octant & 6)))) {
- // If the sextants are the same, the octants can differ only when
- // they are bordering each other on the same edge that the
- // sextant has.
- du = ii - stream.lastU ;
- dv = -jj - stream.lastV ;
-
- // Can't delta by less than -64.
- if (dv < -uv64) absolute = true ;
-
- // Can't delta doubly defined points.
- if (jj == 0) absolute = true ;
-
- } else if (stream.lastOctant == octant &&
- stream.lastSextant != sextant &&
- ((sextant == 0 && stream.lastSextant == 4) ||
- (sextant == 4 && stream.lastSextant == 0) ||
- (sextant == 1 && stream.lastSextant == 5) ||
- (sextant == 5 && stream.lastSextant == 1) ||
- (sextant == 2 && stream.lastSextant == 3) ||
- (sextant == 3 && stream.lastSextant == 2))) {
- // If the octants are the same, the sextants must border on
- // the i side (this case) or the j side (next case).
- du = -ii - stream.lastU ;
- dv = jj - stream.lastV ;
-
- // Can't delta by less than -64.
- if (du < -uv64) absolute = true ;
-
- // Can't delta doubly defined points.
- if (ii == 0) absolute = true ;
-
- } else if (stream.lastOctant == octant &&
- stream.lastSextant != sextant &&
- ((sextant == 0 && stream.lastSextant == 2) ||
- (sextant == 2 && stream.lastSextant == 0) ||
- (sextant == 1 && stream.lastSextant == 3) ||
- (sextant == 3 && stream.lastSextant == 1) ||
- (sextant == 4 && stream.lastSextant == 5) ||
- (sextant == 5 && stream.lastSextant == 4))) {
- // If the octants are the same, the sextants must border on
- // the j side (this case) or the i side (previous case).
- if (((ii + jj ) != uv64) && (ii != 0) && (jj != 0)) {
- du = uv64 - ii - stream.lastU ;
- dv = uv64 - jj - stream.lastV ;
-
- // Can't delta by greater than +63.
- if ((du >= uv64) || (dv >= uv64))
- absolute = true ;
- } else
- // Can't delta doubly defined points.
- absolute = true ;
-
- } else
- // Can't delta this normal.
- absolute = true ;
-
- if (absolute == false) {
- // Convert du and dv to standard grid form.
- u = du << (6 - quant) ;
- v = dv << (6 - quant) ;
- }
-
- // Compute length and shift common to all components.
- computeLengthShift(u, v) ;
-
- if (absolute && length > 6) {
- // Absolute normal u, v components are unsigned 6-bit integers, so
- // truncate the 0 sign bit for values > 0x001f.
- length = 6 ;
- }
-
- // Add this element to the Huffman table associated with this stream.
- huffmanTable.addNormalEntry(length, shift, absolute) ;
-
- // Save current normal as last.
- stream.lastSextant = sextant ;
- stream.lastOctant = octant ;
- stream.lastU = ii ;
- stream.lastV = jj ;
- stream.lastSpecialNormal = specialNormal ;
-
- // Copy and retain absolute normal for mesh buffer lookup.
- uAbsolute = ii ;
- vAbsolute = jj ;
- }
-
- /**
- * Output a setNormal command.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- @Override
- void outputCommand(HuffmanTable table, CommandStream output) {
- outputNormal(table, output, CommandStream.SET_NORM, 8) ;
- }
-
- /**
- * Output a normal subcommand.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- void outputSubcommand(HuffmanTable table, CommandStream output) {
- outputNormal(table, output, 0, 6) ;
- }
-
- //
- // Output the final compressed bits to the output command stream.
- //
- private void outputNormal(HuffmanTable table, CommandStream output,
- int header, int headerLength) {
-
- HuffmanNode t ;
-
- // Look up the Huffman token for this compression stream element.
- t = table.getNormalEntry(length, shift, absolute) ;
-
- // Construct the normal subcommand.
- int componentLength = t.dataLength - t.shift ;
- int subcommandLength = 0 ;
- long normalSubcommand = 0 ;
-
- if (absolute) {
- // A 3-bit sextant and a 3-bit octant are always present.
- subcommandLength = t.tagLength + 6 ;
-
- if (specialNormal)
- // Use the specially-encoded sextant and octant.
- normalSubcommand =
- (t.tag << 6) | (specialSextant << 3) | specialOctant ;
- else
- // Use the general encoding rule.
- normalSubcommand =
- (t.tag << 6) | (sextant << 3) | octant ;
- } else {
- // The tag is immediately followed by the u and v delta components.
- subcommandLength = t.tagLength ;
- normalSubcommand = t.tag ;
- }
-
- // Add the u and v values to the subcommand.
- subcommandLength += (2 * componentLength) ;
-
- u = (u >> t.shift) & (int)lengthMask[componentLength] ;
- v = (v >> t.shift) & (int)lengthMask[componentLength] ;
-
- normalSubcommand =
- (normalSubcommand << (2 * componentLength)) |
- (u << (1 * componentLength)) |
- (v << (0 * componentLength)) ;
-
- if (subcommandLength < 6) {
- // The header will have some empty bits. The Huffman tag
- // computation will prevent this if necessary.
- header |= (int)(normalSubcommand << (6 - subcommandLength)) ;
- subcommandLength = 0 ;
- }
- else {
- // Move the 1st 6 bits of the subcommand into the header.
- header |= (int)(normalSubcommand >>> (subcommandLength - 6)) ;
- subcommandLength -= 6 ;
- }
-
- // Add the header and body to the output buffer.
- output.addCommand(header, headerLength,
- normalSubcommand, subcommandLength) ;
- }
-
- @Override
- public String toString() {
- String fixed ;
-
- if (specialNormal)
- fixed = " special normal, sextant " + specialSextant +
- " octant " + specialOctant ;
-
- else if (absolute)
- fixed = " sextant " + sextant + " octant " + octant +
- " u " + u + " v " + v ;
- else
- fixed = " du " + u + " dv " + v ;
-
- return
- "normal: " + normalX + " " + normalY + " " + normalZ + "\n"
- + fixed + "\n" + " length " + length + " shift " + shift +
- (absolute? " absolute" : " relative") ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamVertex.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamVertex.java
deleted file mode 100644
index fb52482..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStreamVertex.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3f;
-
-/**
- * This class represents a vertex in a compression stream. It maintains both
- * floating-point and quantized representations of the vertex position along
- * with meshing and vertex replacement flags for line and surface
- * primitives. If normals or colors are bundled with geometry vertices then
- * instances of this class will also contain references to normal or color
- * stream elements.
- */
-class CompressionStreamVertex extends CompressionStreamElement {
- private int X, Y, Z ;
- private int meshFlag ;
- private int stripFlag ;
- private float floatX, floatY, floatZ ;
-
- int xAbsolute, yAbsolute, zAbsolute ;
- CompressionStreamColor color = null ;
- CompressionStreamNormal normal = null ;
-
- /**
- * Create a CompressionStreamVertex with the given parameters.
- *
- * @param stream CompressionStream associated with this vertex
- * @param p position
- * @param n normal bundled with this vertex or null if not bundled
- * @param c color bundled with this vertex or null if not bundled
- * @param stripFlag CompressionStream.RESTART,
- * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
- * @param meshFlag CompressionStream.MESH_PUSH or
- * CompressionStream.NO_MESH_PUSH
- */
- CompressionStreamVertex(CompressionStream stream,
- Point3f p, Vector3f n, Color3f c,
- int stripFlag, int meshFlag) {
-
- this(stream, p, n, stripFlag, meshFlag) ;
-
- if (stream.vertexColor3)
- color = new CompressionStreamColor(stream, c) ;
- }
-
- /**
- * Create a CompressionStreamVertex with the given parameters.
- *
- * @param stream CompressionStream associated with this vertex
- * @param p position
- * @param n normal bundled with this vertex or null if not bundled
- * @param c color bundled with this vertex or null if not bundled
- * @param stripFlag CompressionStream.RESTART,
- * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
- * @param meshFlag CompressionStream.MESH_PUSH or
- * CompressionStream.NO_MESH_PUSH
- */
- CompressionStreamVertex(CompressionStream stream,
- Point3f p, Vector3f n, Color4f c,
- int stripFlag, int meshFlag) {
-
- this(stream, p, n, stripFlag, meshFlag) ;
-
- if (stream.vertexColor4)
- color = new CompressionStreamColor(stream, c) ;
- }
-
- /**
- * Create a CompressionStreamVertex with the given parameters.
- *
- * @param stream CompressionStream associated with this vertex
- * @param p position
- * @param n normal bundled with this vertex or null if not bundled
- * @param stripFlag CompressionStream.RESTART,
- * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
- * @param meshFlag CompressionStream.MESH_PUSH or
- * CompressionStream.NO_MESH_PUSH
- */
- CompressionStreamVertex(CompressionStream stream, Point3f p, Vector3f n,
- int stripFlag, int meshFlag) {
-
- this.stripFlag = stripFlag ;
- this.meshFlag = meshFlag ;
- this.floatX = p.x ;
- this.floatY = p.y ;
- this.floatZ = p.z ;
-
- stream.byteCount += 12 ;
- stream.vertexCount++ ;
-
- if (p.x < stream.mcBounds[0].x) stream.mcBounds[0].x = p.x ;
- if (p.y < stream.mcBounds[0].y) stream.mcBounds[0].y = p.y ;
- if (p.z < stream.mcBounds[0].z) stream.mcBounds[0].z = p.z ;
-
- if (p.x > stream.mcBounds[1].x) stream.mcBounds[1].x = p.x ;
- if (p.y > stream.mcBounds[1].y) stream.mcBounds[1].y = p.y ;
- if (p.z > stream.mcBounds[1].z) stream.mcBounds[1].z = p.z ;
-
- if (stream.vertexNormals)
- normal = new CompressionStreamNormal(stream, n) ;
- }
-
- /**
- * Quantize the floating point position to fixed point integer components
- * of the specified number of bits. The bit length can range from 1 to 16.
- *
- * @param stream CompressionStream associated with this element
- * @param table HuffmanTable for collecting data about the quantized
- * representation of this element
- */
- @Override
- void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
- double px, py, pz ;
-
- // Clamp quantization.
- int quant =
- (stream.positionQuant < 1? 1 :
- (stream.positionQuant > 16? 16 : stream.positionQuant)) ;
-
- absolute = false ;
- if (stream.firstPosition || stream.positionQuantChanged) {
- absolute = true ;
- stream.lastPosition[0] = 0 ;
- stream.lastPosition[1] = 0 ;
- stream.lastPosition[2] = 0 ;
- stream.firstPosition = false ;
- stream.positionQuantChanged = false ;
- }
-
- // Normalize position to the unit cube. This is bounded by the open
- // intervals (-1..1) on each axis.
- px = (floatX - stream.center[0]) * stream.scale ;
- py = (floatY - stream.center[1]) * stream.scale ;
- pz = (floatZ - stream.center[2]) * stream.scale ;
-
- // Convert the floating point position to s.15 2's complement.
- // ~1.0 -> 32767 (0x00007fff) [ ~1.0 = 32767.0/32768.0]
- // ~-1.0 -> -32767 (0xffff8001) [~-1.0 = -32767.0/32768.0]
- X = (int)(px * 32768.0) ;
- Y = (int)(py * 32768.0) ;
- Z = (int)(pz * 32768.0) ;
-
- // Compute quantized values.
- X &= quantizationMask[quant] ;
- Y &= quantizationMask[quant] ;
- Z &= quantizationMask[quant] ;
-
- // Update quantized bounds.
- if (X < stream.qcBounds[0].x) stream.qcBounds[0].x = X ;
- if (Y < stream.qcBounds[0].y) stream.qcBounds[0].y = Y ;
- if (Z < stream.qcBounds[0].z) stream.qcBounds[0].z = Z ;
-
- if (X > stream.qcBounds[1].x) stream.qcBounds[1].x = X ;
- if (Y > stream.qcBounds[1].y) stream.qcBounds[1].y = Y ;
- if (Z > stream.qcBounds[1].z) stream.qcBounds[1].z = Z ;
-
- // Copy and retain absolute position for mesh buffer lookup.
- xAbsolute = X ;
- yAbsolute = Y ;
- zAbsolute = Z ;
-
- // Compute deltas.
- X -= stream.lastPosition[0] ;
- Y -= stream.lastPosition[1] ;
- Z -= stream.lastPosition[2] ;
-
- // Update last values.
- stream.lastPosition[0] += X ;
- stream.lastPosition[1] += Y ;
- stream.lastPosition[2] += Z ;
-
- // Deltas which exceed the range of 16-bit signed 2's complement
- // numbers are handled by sign-extension of the 16th bit in order to
- // effect a 16-bit wrap-around.
- X = (X << 16) >> 16 ;
- Y = (Y << 16) >> 16 ;
- Z = (Z << 16) >> 16 ;
-
- // Compute length and shift common to all components.
- computeLengthShift(X, Y, Z) ;
-
- // 0-length components are allowed only for normals.
- if (length == 0)
- length = 1 ;
-
- // Add this element to the Huffman table associated with this stream.
- huffmanTable.addPositionEntry(length, shift, absolute) ;
-
- // Quantize any bundled color or normal.
- if (color != null)
- color.quantize(stream, huffmanTable) ;
-
- if (normal != null)
- normal.quantize(stream, huffmanTable) ;
-
- // Push this vertex into the mesh buffer mirror, if necessary, so it
- // can be retrieved for computing deltas when mesh buffer references
- // are subsequently encountered during the quantization pass.
- if (meshFlag == stream.MESH_PUSH)
- stream.meshBuffer.push(this) ;
- }
-
- /**
- * Output the final compressed bits to the compression command stream.
- *
- * @param table HuffmanTable mapping quantized representations to
- * compressed encodings
- * @param output CommandStream for collecting compressed output
- */
- @Override
- void outputCommand(HuffmanTable huffmanTable, CommandStream outputBuffer) {
-
- HuffmanNode t ;
- int command = CommandStream.VERTEX ;
-
- // Look up the Huffman token for this compression stream element. The
- // values of length and shift found there will override the
- // corresponding fields in this element, which represent best-case
- // compression without regard to tag length.
- t = huffmanTable.getPositionEntry(length, shift, absolute) ;
-
- // Construct the position subcommand.
- int componentLength = t.dataLength - t.shift ;
- int subcommandLength = t.tagLength + (3 * componentLength) ;
-
- X = (X >> t.shift) & (int)lengthMask[componentLength] ;
- Y = (Y >> t.shift) & (int)lengthMask[componentLength] ;
- Z = (Z >> t.shift) & (int)lengthMask[componentLength] ;
-
- long positionSubcommand =
- (((long)t.tag) << (3 * componentLength)) |
- (((long)X) << (2 * componentLength)) |
- (((long)Y) << (1 * componentLength)) |
- (((long)Z) << (0 * componentLength)) ;
-
- if (subcommandLength < 6) {
- // The header will have some empty bits. The Huffman tag
- // computation will prevent this if necessary.
- command |= (int)(positionSubcommand << (6 - subcommandLength)) ;
- subcommandLength = 0 ;
- }
- else {
- // Move the 1st 6 bits of the subcommand into the header.
- command |= (int)(positionSubcommand >>> (subcommandLength - 6)) ;
- subcommandLength -= 6 ;
- }
-
- // Construct the vertex command body.
- long body =
- (((long)stripFlag) << (subcommandLength + 1)) |
- (((long)meshFlag) << (subcommandLength + 0)) |
- (positionSubcommand & lengthMask[subcommandLength]) ;
-
- // Add the vertex command to the output buffer.
- outputBuffer.addCommand(command, 8, body, subcommandLength + 3) ;
-
- // Output any normal and color subcommands.
- if (normal != null)
- normal.outputSubcommand(huffmanTable, outputBuffer) ;
-
- if (color != null)
- color.outputSubcommand(huffmanTable, outputBuffer) ;
- }
-
- @Override
- public String toString() {
- String d = absolute? "" : "delta " ;
- String c = (color == null? "": "\n\n " + color.toString()) ;
- String n = (normal == null? "": "\n\n " + normal.toString()) ;
-
- return
- "position: " + floatX + " " + floatY + " " + floatZ + "\n" +
- "fixed point " + d + + X + " " + Y + " " + Z + "\n" +
- "length " + length + " shift " + shift +
- (absolute? " absolute" : " relative") + "\n" +
- "strip flag " + stripFlag + " mesh flag " + meshFlag +
- c + n ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStrip.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStrip.java
deleted file mode 100644
index 029fd0b..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStrip.java
+++ /dev/null
@@ -1,904 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-
-/**
- * This class provides static methods to support topological
- * transformations on generalized strips. This is used by the
- * GeometryDecompressor. These methods only need to look at the
- * vertex replacement flags to determine how the vertices in the strip
- * are connected. The connections are rearranged in different ways to
- * transform generalized strips to GeometryArray representations.
- *
- * @see GeneralizedStripFlags
- * @see GeneralizedVertexList
- * @see GeometryDecompressor
- */
-class GeneralizedStrip {
- private static final boolean debug = false ;
-
- // Private convenience copies of various constants.
- private static final int CW =
- GeneralizedStripFlags.FRONTFACE_CW ;
- private static final int CCW =
- GeneralizedStripFlags.FRONTFACE_CCW ;
- private static final int RESTART_CW =
- GeneralizedStripFlags.RESTART_CW ;
- private static final int RESTART_CCW =
- GeneralizedStripFlags.RESTART_CCW ;
- private static final int REPLACE_MIDDLE =
- GeneralizedStripFlags.REPLACE_MIDDLE ;
- private static final int REPLACE_OLDEST =
- GeneralizedStripFlags.REPLACE_OLDEST ;
-
- /**
- * The IntList is like an ArrayList, but avoids the Integer
- * object wrapper and accessor overhead for simple lists of ints.
- */
- static class IntList {
- /**
- * The array of ints.
- */
- int ints[] ;
-
- /**
- * The number of ints in this instance.
- */
- int count ;
-
- /**
- * Construct a new empty IntList of the given initial size.
- * @param initialSize initial size of the backing array
- */
- IntList(int initialSize) {
- ints = new int[initialSize] ;
- count = 0 ;
- }
-
- /**
- * Constructs an IntList with the given contents.
- * @param ints the array of ints to use as the contents
- */
- IntList(int ints[]) {
- this.ints = ints ;
- this.count = ints.length ;
- }
-
- /**
- * Add a new int to the end of this list.
- * @param i the int to be appended to this list
- */
- void add(int i) {
- if (count == ints.length) {
- int newints[] = new int[2*count] ;
- System.arraycopy(ints, 0, newints, 0, count) ;
- ints = newints ;
- if (debug)
- System.out.println
- ("GeneralizedStrip.IntList: reallocated " +
- (2*count) + " ints") ;
- }
- ints[count++] = i ;
- }
-
- /**
- * Trim the backing array to the current count and return the
- * resulting backing array.
- */
- int[] trim() {
- if (count != ints.length) {
- int newints[] = new int[count] ;
- System.arraycopy(ints, 0, newints, 0, count) ;
- ints = newints ;
- }
- return ints ;
- }
-
- /**
- * Fill the list with consecutive integers starting from 0.
- */
- void fillAscending() {
- for (int i = 0 ; i < ints.length ; i++)
- ints[i] = i ;
-
- count = ints.length ;
- }
-
- @Override
- public String toString() {
- String s = new String("[") ;
- for (int i = 0 ; i < count-1 ; i++)
- s = s + Integer.toString(ints[i]) + ", " ;
- return s + Integer.toString(ints[count-1]) + "]" ;
- }
- }
-
- /**
- * The StripArray class is used as the output of some conversion methods
- * in the GeneralizedStrip class.
- */
- static class StripArray {
- /**
- * A list of indices into the vertices of the original generalized
- * strip. It specifies the order in which vertices in the original
- * strip should be followed to build GeometryArray objects.
- */
- IntList vertices ;
-
- /**
- * A list of strip counts.
- */
- IntList stripCounts ;
-
- /**
- * Creates a StripArray with the specified vertices and stripCounts.
- * @param vertices IntList containing vertex indicies.
- * @param stripCounts IntList containing strip lengths.
- */
- StripArray(IntList vertices, IntList stripCounts) {
- this.vertices = vertices ;
- this.stripCounts = stripCounts ;
- }
- }
-
- /**
- * Interprets the vertex flags associated with a class implementing
- * GeneralizedStripFlags, constructing and returning a 2-element array of
- * StripArray objects. The first StripArray will contain triangle strips
- * and the second will contain triangle fans.
- *
- * @param vertices an object implementing GeneralizedStripFlags
- * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
- * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
- * @return a 2-element array containing strips in 0 and fans in 1
- */
- static StripArray[] toStripsAndFans(GeneralizedStripFlags vertices,
- int frontFace) {
-
- int size = vertices.getFlagCount() ;
-
- // Initialize IntLists to worst-case sizes.
- IntList stripVerts = new IntList(size*3) ;
- IntList fanVerts = new IntList(size*3) ;
- IntList stripCounts = new IntList(size) ;
- IntList fanCounts = new IntList(size) ;
-
- toStripsAndFans(vertices, frontFace,
- stripVerts, stripCounts, fanVerts, fanCounts) ;
-
- // Construct the StripArray output.
- StripArray sa[] = new StripArray[2] ;
-
- if (stripCounts.count > 0)
- sa[0] = new StripArray(stripVerts, stripCounts) ;
-
- if (fanCounts.count > 0)
- sa[1] = new StripArray(fanVerts, fanCounts) ;
-
- return sa ;
- }
-
- private static void toStripsAndFans(GeneralizedStripFlags vertices,
- int frontFace,
- IntList stripVerts,
- IntList stripCounts,
- IntList fanVerts,
- IntList fanCounts) {
- int newFlag, curFlag, winding ;
- int v, size, stripStart, stripLength ;
- boolean transition = false ;
-
- stripStart = 0 ;
- stripLength = 3 ;
- curFlag = vertices.getFlag(0) ;
- winding = (curFlag == RESTART_CW ? CW : CCW) ;
- size = vertices.getFlagCount() ;
-
- // Vertex replace flags for the first 3 vertices are irrelevant since
- // they can only define a single triangle. The first meaningful
- // replace flag starts at the 4th vertex.
- v = 3 ;
- if (v < size)
- curFlag = vertices.getFlag(v) ;
-
- while (v < size) {
- newFlag = vertices.getFlag(v) ;
-
- if ((newFlag == curFlag) &&
- (newFlag != RESTART_CW) && (newFlag != RESTART_CCW)) {
- // The last flag was the same as this one, and it wasn't a
- // restart: proceed to the next vertex.
- stripLength++ ;
- v++ ;
-
- } else {
- // Either this vertex flag changed from the last one, or
- // the flag explicitly specifies a restart: process the
- // last strip and start up a new one.
- if (curFlag == REPLACE_MIDDLE)
- addFan(fanVerts, fanCounts, stripStart, stripLength,
- frontFace, winding, transition) ;
- else
- addStrip(stripVerts, stripCounts, stripStart, stripLength,
- frontFace, winding) ;
-
- // Restart: skip to the 4th vertex of the new strip.
- if ((newFlag == RESTART_CW) || (newFlag == RESTART_CCW)) {
- winding = (newFlag == RESTART_CW ? CW : CCW) ;
- stripStart = v ;
- stripLength = 3 ;
- v += 3 ;
- transition = false ;
- if (v < size)
- curFlag = vertices.getFlag(v) ;
- }
- // Strip/fan transition: decrement start of strip.
- else {
- if (newFlag == REPLACE_OLDEST) {
- // Flip winding order when transitioning from fans
- // to strips.
- winding = (winding == CW ? CCW : CW) ;
- stripStart = v-2 ;
- stripLength = 3 ;
- } else {
- // Flip winding order when transitioning from
- // strips to fans only if the preceding strip has
- // an even number of vertices.
- if ((stripLength & 0x01) == 0)
- winding = (winding == CW ? CCW : CW) ;
- stripStart = v-3 ;
- stripLength = 4 ;
- }
- v++ ;
- transition = true ;
- curFlag = newFlag ;
- }
- }
- }
-
- // Finish off the last strip or fan.
- // If v > size then the strip is degenerate.
- if (v == size)
- if (curFlag == REPLACE_MIDDLE)
- addFan(fanVerts, fanCounts, stripStart, stripLength,
- frontFace, winding, transition) ;
- else
- addStrip(stripVerts, stripCounts, stripStart, stripLength,
- frontFace, winding) ;
- else
- throw new IllegalArgumentException
- (J3dUtilsI18N.getString("GeneralizedStrip0")) ;
-
- if (debug) {
- System.out.println("GeneralizedStrip.toStripsAndFans") ;
- if (v > size)
- System.out.println(" ended with a degenerate triangle:" +
- " number of vertices: " + (v-size)) ;
-
- System.out.println("\n number of strips: " + stripCounts.count) ;
- if (stripCounts.count > 0) {
- System.out.println(" number of vertices: " + stripVerts.count) ;
- System.out.println(" vertices/strip: " +
- (float)stripVerts.count/stripCounts.count) ;
- System.out.println(" strip counts: " + stripCounts.toString()) ;
- // System.out.println(" indices: " + stripVerts.toString()) ;
- }
-
- System.out.println("\n number of fans: " + fanCounts.count) ;
- if (fanCounts.count > 0) {
- System.out.println(" number of vertices: " + fanVerts.count) ;
- System.out.println(" vertices/strip: " +
- (float)fanVerts.count/fanCounts.count) ;
- System.out.println(" fan counts: " + fanCounts.toString()) ;
- // System.out.println(" indices: " + fanVerts.toString()) ;
- }
- System.out.println("\n total vertices: " +
- (stripVerts.count + fanVerts.count) +
- "\n original number of vertices: " + size +
- "\n") ;
- }
- }
-
- //
- // Java 3D specifies that the vertices of front-facing polygons
- // have counter-clockwise (CCW) winding order when projected to
- // the view surface. Polygons with clockwise (CW) vertex winding
- // will be culled as back-facing by default.
- //
- // Generalized triangle strips can flip the orientation of their
- // triangles with the RESTART_CW and RESTART_CCW vertex flags.
- // Strips flagged with an orientation opposite to what has been
- // specified as front-facing must have their windings reversed in
- // order to have the correct face orientation when represented as
- // GeometryArray objects.
- //
- private static void addStrip(IntList stripVerts,
- IntList stripCounts,
- int start, int length,
- int frontFace, int winding) {
- int vindex = start ;
-
- if (winding == frontFace) {
- // Maintain original order.
- stripCounts.add(length) ;
- while (vindex < start + length) {
- stripVerts.add(vindex++) ;
- }
- } else if ((length & 0x1) == 1) {
- // Reverse winding order if number of vertices is odd.
- stripCounts.add(length) ;
- vindex += length-1 ;
- while (vindex >= start) {
- stripVerts.add(vindex--) ;
- }
- } else if (length == 4) {
- // Swap middle vertices.
- stripCounts.add(4) ;
- stripVerts.add(vindex) ;
- stripVerts.add(vindex+2) ;
- stripVerts.add(vindex+1) ;
- stripVerts.add(vindex+3) ;
- } else {
- // Make the 1st triangle a singleton with reverse winding.
- stripCounts.add(3) ;
- stripVerts.add(vindex) ;
- stripVerts.add(vindex+2) ;
- stripVerts.add(vindex+1) ;
- if (length > 3) {
- // Copy the rest of the vertices in original order.
- vindex++ ;
- stripCounts.add(length-1) ;
- while (vindex < start + length) {
- stripVerts.add(vindex++) ;
- }
- }
- }
- }
-
- private static void addFan(IntList fanVerts,
- IntList fanCounts,
- int start, int length,
- int frontFace, int winding,
- boolean transition) {
- int vindex = start ;
- fanVerts.add(vindex++) ;
-
- if (winding == frontFace) {
- if (transition) {
- // Skip 1st triangle if this is the result of a transition.
- fanCounts.add(length-1) ;
- vindex++ ;
- } else {
- fanCounts.add(length) ;
- fanVerts.add(vindex++) ;
- }
- while (vindex < start + length) {
- fanVerts.add(vindex++) ;
- }
- } else {
- // Reverse winding order.
- vindex += length-2 ;
- while (vindex > start+1) {
- fanVerts.add(vindex--) ;
- }
- if (transition) {
- // Skip 1st triangle if this is the result of a transition.
- fanCounts.add(length-1) ;
- } else {
- fanCounts.add(length) ;
- fanVerts.add(vindex) ;
- }
- }
- }
-
- /**
- * Interprets the vertex flags associated with a class implementing
- * GeneralizedStripFlags, constructing and returning a StripArray containing
- * exclusively strips.
- *
- * @param vertices an object implementing GeneralizedStripFlags
- * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
- * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
- * @return a StripArray containing the converted strips
- */
- static StripArray toTriangleStrips(GeneralizedStripFlags vertices,
- int frontFace) {
-
- int size = vertices.getFlagCount() ;
-
- // initialize lists to worst-case sizes.
- IntList stripVerts = new IntList(size*3) ;
- IntList fanVerts = new IntList(size*3) ;
- IntList stripCounts = new IntList(size) ;
- IntList fanCounts = new IntList(size) ;
-
- toStripsAndFans(vertices, frontFace,
- stripVerts, stripCounts, fanVerts, fanCounts) ;
-
- if (fanCounts.count == 0)
- if (stripCounts.count > 0)
- return new StripArray(stripVerts, stripCounts) ;
- else
- return null ;
-
- // convert each fan to one or more strips
- int i, v = 0 ;
- for (i = 0 ; i < fanCounts.count ; i++) {
- fanToStrips(v, fanCounts.ints[i], fanVerts.ints,
- stripVerts, stripCounts, false) ;
- v += fanCounts.ints[i] ;
- }
-
- // create the StripArray output
- StripArray sa = new StripArray(stripVerts, stripCounts) ;
-
- if (debug) {
- System.out.println("GeneralizedStrip.toTriangleStrips" +
- "\n number of strips: " +
- sa.stripCounts.count) ;
- if (sa.stripCounts.count > 0) {
- System.out.println(" number of vertices: " +
- sa.vertices.count +
- "\n vertices/strip: " +
- ((float)sa.vertices.count /
- (float)sa.stripCounts.count)) ;
- System.out.print(" strip counts: [") ;
- for (i = 0 ; i < sa.stripCounts.count-1 ; i++)
- System.out.print(sa.stripCounts.ints[i] + ", ") ;
- System.out.println(sa.stripCounts.ints[i] + "]") ;
- }
- System.out.println() ;
- }
- return sa ;
- }
-
- private static void fanToStrips(int v, int length, int fans[],
- IntList stripVerts,
- IntList stripCounts,
- boolean convexPlanar) {
- if (convexPlanar) {
- // Construct a strip by criss-crossing across the interior.
- stripCounts.add(length) ;
- stripVerts.add(fans[v]) ;
-
- int j = v + 1 ;
- int k = v + (length - 1) ;
- while (j <= k) {
- stripVerts.add(fans[j++]) ;
- if (j > k) break ;
- stripVerts.add(fans[k--]) ;
- }
- } else {
- // Traverse non-convex or non-planar fan, biting off 3-triangle
- // strips or less. First 5 vertices produce 1 strip of 3
- // triangles, and every 4 vertices after that produce another
- // strip of 3 triangles. Each remaining strip adds 2 vertices.
- int fanStart = v ;
- v++ ;
- while (v+4 <= fanStart + length) {
- stripVerts.add(fans[v]) ;
- stripVerts.add(fans[v+1]) ;
- stripVerts.add(fans[fanStart]) ;
- stripVerts.add(fans[v+2]) ;
- stripVerts.add(fans[v+3]) ;
- stripCounts.add(5) ;
- v += 3 ;
- }
-
- // Finish off the fan.
- if (v+1 < fanStart + length) {
- stripVerts.add(fans[v]) ;
- stripVerts.add(fans[v+1]) ;
- stripVerts.add(fans[fanStart]) ;
- v++ ;
-
- if (v+1 < fanStart + length) {
- stripVerts.add(fans[v+1]) ;
- stripCounts.add(4) ;
- }
- else
- stripCounts.add(3) ;
- }
- }
- }
-
- /**
- * Interprets the vertex flags associated with a class implementing
- * GeneralizedStripFlags, constructing and returning an array of vertex
- * references representing the original generalized strip as individual
- * triangles. Each sequence of three consecutive vertex references in the
- * output defines a single triangle.
- *
- * @param vertices an object implementing GeneralizedStripFlags
- * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
- * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
- * @return an array of indices into the original vertex array
- */
- static int[] toTriangles(GeneralizedStripFlags vertices, int frontFace) {
-
- int vertexCount = 0 ;
- StripArray sa[] = toStripsAndFans(vertices, frontFace) ;
-
- if (sa[0] != null)
- vertexCount = 3 * getTriangleCount(sa[0].stripCounts) ;
- if (sa[1] != null)
- vertexCount += 3 * getTriangleCount(sa[1].stripCounts) ;
-
- if (debug)
- System.out.println("GeneralizedStrip.toTriangles\n" +
- " number of triangles: " + vertexCount/3 + "\n" +
- " number of vertices: " + vertexCount + "\n") ;
- int t = 0 ;
- int triangles[] = new int[vertexCount] ;
-
- if (sa[0] != null)
- t = stripsToTriangles(t, triangles,
- 0, sa[0].vertices.ints,
- 0, sa[0].stripCounts.ints,
- sa[0].stripCounts.count) ;
- if (sa[1] != null)
- t = fansToTriangles(t, triangles,
- 0, sa[1].vertices.ints,
- 0, sa[1].stripCounts.ints,
- sa[1].stripCounts.count) ;
- return triangles ;
- }
-
- private static int stripsToTriangles(int tstart, int tbuff[],
- int vstart, int vertices[],
- int stripStart, int stripCounts[],
- int stripCount) {
- int t = tstart ;
- int v = vstart ;
- for (int i = 0 ; i < stripCount ; i++) {
- for (int j = 0 ; j < stripCounts[i+stripStart] - 2 ; j++) {
- if ((j & 0x01) == 0) {
- // even-numbered triangles
- tbuff[t*3 +0] = vertices[v+0] ;
- tbuff[t*3 +1] = vertices[v+1] ;
- tbuff[t*3 +2] = vertices[v+2] ;
- } else {
- // odd-numbered triangles
- tbuff[t*3 +0] = vertices[v+1] ;
- tbuff[t*3 +1] = vertices[v+0] ;
- tbuff[t*3 +2] = vertices[v+2] ;
- }
- t++ ; v++ ;
- }
- v += 2 ;
- }
- return t ;
- }
-
- private static int fansToTriangles(int tstart, int tbuff[],
- int vstart, int vertices[],
- int stripStart, int stripCounts[],
- int stripCount) {
- int t = tstart ;
- int v = vstart ;
- for (int i = 0 ; i < stripCount ; i++) {
- for (int j = 0 ; j < stripCounts[i+stripStart] - 2 ; j++) {
- tbuff[t*3 +0] = vertices[v] ;
- tbuff[t*3 +1] = vertices[v+j+1] ;
- tbuff[t*3 +2] = vertices[v+j+2] ;
- t++ ;
- }
- v += stripCounts[i+stripStart] ;
- }
- return t ;
- }
-
- /**
- * Interprets the vertex flags associated with a class implementing
- * GeneralizedStripFlags, constructing and returning a 2-element array of
- * StripArray objects. The first StripArray will contain triangle strips
- * and the second will contain individual triangles in the vertices
- * field. Short strips will be converted to individual triangles.
- *
- * @param vertices an object implementing GeneralizedStripFlags
- * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
- * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
- * @param shortStripSize strips this size or less will be converted to
- * individual triangles if there are more than maxShortStrips of them
- * @param maxShortStrips maximum number of short strips allowed before
- * creating individual triangles
- * @return a 2-element array containing strips in 0 and triangles in 1
- */
- static StripArray[] toStripsAndTriangles(GeneralizedStripFlags vertices,
- int frontFace, int shortStripSize,
- int maxShortStrips) {
- int longStripCount = 0 ;
- int longStripVertexCount = 0 ;
- int shortStripCount = 0 ;
- int triangleCount = 0 ;
-
- StripArray sa[] = new StripArray[2] ;
- StripArray ts = toTriangleStrips(vertices, frontFace) ;
-
- for (int i = 0 ; i < ts.stripCounts.count ; i++)
- if (ts.stripCounts.ints[i] <= shortStripSize) {
- shortStripCount++ ;
- triangleCount += ts.stripCounts.ints[i] - 2 ;
- } else {
- longStripCount++ ;
- longStripVertexCount += ts.stripCounts.ints[i] ;
- }
-
- if (debug)
- System.out.print("GeneralizedStrip.toStripsAndTriangles\n" +
- " short strip size: " + shortStripSize +
- " short strips tolerated: " + maxShortStrips +
- " number of short strips: " + shortStripCount +
- "\n\n") ;
-
- if (shortStripCount <= maxShortStrips) {
- sa[0] = ts ;
- sa[1] = null ;
- } else {
- int si = 0 ; int newStripVerts[] = new int[longStripVertexCount] ;
- int ci = 0 ; int newStripCounts[] = new int[longStripCount] ;
- int ti = 0 ; int triangles[] = new int[3*triangleCount] ;
- int vi = 0 ;
-
- for (int i = 0 ; i < ts.stripCounts.count ; i++) {
- if (ts.stripCounts.ints[i] <= shortStripSize) {
- ti = stripsToTriangles(ti, triangles,
- vi, ts.vertices.ints,
- i, ts.stripCounts.ints, 1) ;
- vi += ts.stripCounts.ints[i] ;
- } else {
- newStripCounts[ci++] = ts.stripCounts.ints[i] ;
- for (int j = 0 ; j < ts.stripCounts.ints[i] ; j++)
- newStripVerts[si++] = ts.vertices.ints[vi++] ;
- }
- }
-
- if (longStripCount > 0)
- sa[0] = new StripArray(new IntList(newStripVerts),
- new IntList(newStripCounts)) ;
- else
- sa[0] = null ;
-
- sa[1] = new StripArray(new IntList(triangles), null) ;
-
- if (debug) {
- System.out.println(" triangles separated: " + triangleCount) ;
- if (longStripCount > 0) {
- System.out.println
- (" new vertices/strip: " +
- ((float)longStripVertexCount/(float)longStripCount)) ;
-
- System.out.print(" long strip counts: [") ;
- for (int i = 0 ; i < longStripCount-1 ; i++)
- System.out.print(newStripCounts[i++] + ", ") ;
-
- System.out.println
- (newStripCounts[longStripCount-1] + "]\n") ;
- }
- }
- }
- return sa ;
- }
-
- /**
- * Interprets the vertex flags associated with a class implementing
- * GeneralizedStripFlags, constructing and returning a StripArray.
- *
- * RESTART_CW and RESTART_CCW are treated as equivalent, as are
- * REPLACE_MIDDLE and REPLACE_OLDEST.
- *
- * @param vertices an object implementing GeneralizedStripFlags
- * @return a StripArray representing an array of line strips
- */
- static StripArray toLineStrips(GeneralizedStripFlags vertices) {
- int v, size, stripStart, stripLength, flag ;
-
- stripStart = 0 ;
- stripLength = 2 ;
- size = vertices.getFlagCount() ;
-
- // Initialize IntLists to worst-case sizes.
- IntList stripVerts = new IntList(size*2) ;
- IntList stripCounts = new IntList(size) ;
-
- // Vertex replace flags for the first two vertices are irrelevant.
- v = 2 ;
- while (v < size) {
- flag = vertices.getFlag(v) ;
-
- if ((flag != RESTART_CW) && (flag != RESTART_CCW)) {
- // proceed to the next vertex.
- stripLength++ ;
- v++ ;
-
- } else {
- // Record the last strip.
- stripCounts.add(stripLength) ;
- for (int i = stripStart ; i < stripStart+stripLength ; i++)
- stripVerts.add(i) ;
-
- // Start a new strip and skip to its 3rd vertex.
- stripStart = v ;
- stripLength = 2 ;
- v += 2 ;
- }
- }
-
- // Finish off the last strip.
- // If v > size then the strip is degenerate.
- if (v == size) {
- stripCounts.add(stripLength) ;
- for (int i = stripStart ; i < stripStart+stripLength ; i++)
- stripVerts.add(i) ;
- } else
- throw new IllegalArgumentException
- (J3dUtilsI18N.getString("GeneralizedStrip0")) ;
-
- if (debug) {
- System.out.println("GeneralizedStrip.toLineStrips\n") ;
- if (v > size)
- System.out.println(" ended with a degenerate line") ;
-
- System.out.println(" number of strips: " + stripCounts.count) ;
- if (stripCounts.count > 0) {
- System.out.println(" number of vertices: " + stripVerts.count) ;
- System.out.println(" vertices/strip: " +
- (float)stripVerts.count/stripCounts.count) ;
- System.out.println(" strip counts: " + stripCounts.toString()) ;
- // System.out.println(" indices: " + stripVerts.toString()) ;
- }
- System.out.println() ;
- }
-
- if (stripCounts.count > 0)
- return new StripArray(stripVerts, stripCounts) ;
- else
- return null ;
- }
-
- /**
- * Counts the number of lines defined by arrays of line strips.
- *
- * @param stripCounts array of strip counts, as used by the
- * GeometryStripArray object
- * @return number of lines in the strips
- */
- static int getLineCount(int stripCounts[]) {
- int count = 0 ;
- for (int i = 0 ; i < stripCounts.length ; i++)
- count += (stripCounts[i] - 1) ;
- return count ;
- }
-
- /**
- * Counts the number of triangles defined by arrays of
- * triangle strips or fans.
- *
- * @param stripCounts array of strip counts, as used by the
- * GeometryStripArray object
- * @return number of triangles in the strips or fans
- */
- static int getTriangleCount(int stripCounts[]) {
- int count = 0 ;
- for (int i = 0 ; i < stripCounts.length ; i++)
- count += (stripCounts[i] - 2) ;
- return count ;
- }
-
- /**
- * Counts the number of triangles defined by arrays of
- * triangle strips or fans.
- *
- * @param stripCounts IntList of strip counts
- * @return number of triangles in the strips or fans
- */
- static int getTriangleCount(IntList stripCounts) {
- int count = 0 ;
- for (int i = 0 ; i < stripCounts.count ; i++)
- count += (stripCounts.ints[i] - 2) ;
- return count ;
- }
-
- /**
- * Breaks up triangle strips into separate triangles.
- *
- * @param stripCounts array of strip counts, as used by the
- * GeometryStripArray object
- * @return array of ints which index into the original vertex array; each
- * set of three consecutive vertex indices defines a single triangle
- */
- static int[] stripsToTriangles(int stripCounts[]) {
- int triangleCount = getTriangleCount(stripCounts) ;
- int tbuff[] = new int[3*triangleCount] ;
- IntList vertices = new IntList(triangleCount + 2*stripCounts.length) ;
-
- vertices.fillAscending() ;
- stripsToTriangles(0, tbuff,
- 0, vertices.ints,
- 0, stripCounts,
- stripCounts.length) ;
- return tbuff ;
- }
-
- /**
- * Breaks up triangle fans into separate triangles.
- *
- * @param stripCounts array of strip counts, as used by the
- * GeometryStripArray object
- * @return array of ints which index into the original vertex array; each
- * set of three consecutive vertex indices defines a single triangle
- */
- static int[] fansToTriangles(int stripCounts[]) {
- int triangleCount = getTriangleCount(stripCounts) ;
- int tbuff[] = new int[3*triangleCount] ;
- IntList vertices = new IntList(triangleCount + 2*stripCounts.length) ;
-
- vertices.fillAscending() ;
- fansToTriangles(0, tbuff,
- 0, vertices.ints,
- 0, stripCounts,
- stripCounts.length) ;
- return tbuff ;
- }
-
- /**
- * Takes a fan and converts it to one or more strips.
- *
- * @param v index into the fans array of the first vertex in the fan
- * @param length number of vertices in the fan
- * @param fans array of vertex indices representing one or more fans
- * @param convexPlanar if true indicates that the fan is convex and
- * planar; such fans will always be converted into a single strip
- * @return a StripArray containing the converted strips
- */
- static StripArray fanToStrips(int v, int length, int fans[],
- boolean convexPlanar) {
-
- // Initialize IntLists to worst-case sizes.
- IntList stripVerts = new IntList(length*3) ;
- IntList stripCounts = new IntList(length) ;
-
- fanToStrips(v, length, fans, stripVerts, stripCounts, convexPlanar) ;
- return new StripArray(stripVerts, stripCounts) ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStripFlags.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStripFlags.java
deleted file mode 100644
index 9fd75ea..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedStripFlags.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-/**
- * A class which implements GeneralizedStripFlags provides the means to access
- * the vertex replace code flags associated with each vertex of a generalized
- * strip. This allows a flexible representation of generalized strips for
- * various classes and makes it possible to provide a common subset of static
- * methods which operate only on their topology.
- *
- * @see GeneralizedStrip
- * @see GeneralizedVertexList
- */
-interface GeneralizedStripFlags {
-
- /**
- * This flag indicates that a vertex starts a new strip with clockwise
- * winding.
- */
- static final int RESTART_CW = 0 ;
-
- /**
- * This flag indicates that a vertex starts a new strip with
- * counter-clockwise winding.
- */
- static final int RESTART_CCW = 1 ;
-
- /**
- * This flag indicates that the next triangle in the strip is defined by
- * replacing the middle vertex of the previous triangle in the strip.
- */
- static final int REPLACE_MIDDLE = 2 ;
-
- /**
- * This flag indicates that the next triangle in the strip is defined by
- * replacing the oldest vertex of the previous triangle in the strip.
- */
- static final int REPLACE_OLDEST = 3 ;
-
- /**
- * This constant is used to indicate that triangles with clockwise vertex
- * winding are front facing.
- */
- static final int FRONTFACE_CW = 0 ;
-
- /**
- * This constant is used to indicate that triangles with counter-clockwise
- * vertex winding are front facing.
- */
- static final int FRONTFACE_CCW = 1 ;
-
- /**
- * Return the number of flags. This should be the same as the number of
- * vertices in the generalized strip.
- */
- int getFlagCount() ;
-
- /**
- * Return the flag associated with the vertex at the specified index.
- */
- int getFlag(int index) ;
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedVertexList.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedVertexList.java
deleted file mode 100644
index b5832af..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeneralizedVertexList.java
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import java.util.ArrayList;
-
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.GeometryStripArray;
-import javax.media.j3d.LineStripArray;
-import javax.media.j3d.PointArray;
-import javax.media.j3d.TriangleArray;
-import javax.media.j3d.TriangleFanArray;
-import javax.media.j3d.TriangleStripArray;
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3f;
-
-/**
- * The GeneralizedVertexList class is a variable-size list used to
- * collect the vertices for a generalized strip of points, lines, or
- * triangles. This is used by the GeometryDecompressor. This class
- * implements the GeneralizedStripFlags interface and provides methods
- * for copying instance vertex data into various fixed-size
- * GeometryArray representations.
- *
- * @see GeneralizedStrip
- * @see GeometryDecompressor
- */
-class GeneralizedVertexList implements GeneralizedStripFlags {
-
- // The ArrayList containing the vertices.
- private ArrayList vertices ;
-
- // Booleans for individual vertex components.
- private boolean hasColor3 = false ;
- private boolean hasColor4 = false ;
- private boolean hasNormals = false ;
-
- // Indicates the vertex winding of front-facing triangles in this strip.
- private int frontFace ;
-
- /**
- * Count of number of strips generated after conversion to GeometryArray.
- */
- int stripCount ;
-
- /**
- * Count of number of vertices generated after conversion to GeometryArray.
- */
- int vertexCount ;
-
- /**
- * Count of number of triangles generated after conversion to GeometryArray.
- */
- int triangleCount ;
-
- /**
- * Bits describing the data bundled with each vertex. This is specified
- * using the GeometryArray mask components.
- */
- int vertexFormat ;
-
- /**
- * Creates a new GeneralizedVertexList for the specified vertex format.
- * @param vertexFormat a mask indicating which components are
- * present in each vertex, as used by GeometryArray.
- * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
- * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
- * @param initSize initial number of elements
- * @see GeometryArray
- */
- GeneralizedVertexList(int vertexFormat, int frontFace, int initSize) {
- this.frontFace = frontFace ;
- setVertexFormat(vertexFormat) ;
-
- if (initSize == 0)
- vertices = new ArrayList() ;
- else
- vertices = new ArrayList(initSize) ;
-
- stripCount = 0 ;
- vertexCount = 0 ;
- triangleCount = 0 ;
- }
-
- /**
- * Creates a new GeneralizedVertexList for the specified vertex format.
- * @param vertexFormat a mask indicating which components are
- * present in each vertex, as used by GeometryArray.
- * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
- * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
- * @see GeometryArray
- */
- GeneralizedVertexList(int vertexFormat, int frontFace) {
- this(vertexFormat, frontFace, 0) ;
- }
-
- /**
- * Sets the vertex format for this vertex list.
- * @param vertexFormat a mask indicating which components are
- * present in each vertex, as used by GeometryArray.
- */
- void setVertexFormat(int vertexFormat) {
- this.vertexFormat = vertexFormat ;
-
- if ((vertexFormat & GeometryArray.NORMALS) != 0)
- hasNormals = true ;
-
- if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4)
- hasColor4 = true ;
- else if ((vertexFormat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3)
- hasColor3 = true ;
- }
-
- /**
- * A class with fields corresponding to all the data that can be bundled
- * with the vertices of generalized strips.
- */
- class Vertex {
- int flag ;
- Point3f coord ;
- Color3f color3 ;
- Color4f color4 ;
- Vector3f normal ;
-
- Vertex(Point3f p, Vector3f n, Color4f c, int flag) {
- this.flag = flag ;
- coord = new Point3f(p) ;
-
- if (hasNormals)
- normal = new Vector3f(n) ;
-
- if (hasColor3)
- color3 = new Color3f(c.x, c.y, c.z) ;
-
- else if (hasColor4)
- color4 = new Color4f(c) ;
- }
- }
-
- /**
- * Copy vertex data to a new Vertex object and add it to this list.
- */
- void addVertex(Point3f pos, Vector3f norm, Color4f color, int flag) {
- vertices.add(new Vertex(pos, norm, color, flag)) ;
- }
-
- /**
- * Return the number of vertices in this list.
- */
- int size() {
- return vertices.size() ;
- }
-
- // GeneralizedStripFlags interface implementation
- @Override
- public int getFlagCount() {
- return vertices.size() ;
- }
-
- // GeneralizedStripFlags interface implementation
- @Override
- public int getFlag(int index) {
- return ((Vertex)vertices.get(index)).flag ;
- }
-
- // Copy vertices in the given order to a fixed-length GeometryArray.
- // Using the array versions of the GeometryArray set() methods results in
- // a significant performance improvement despite needing to create
- // fixed-length arrays to hold the vertex elements.
- private void copyVertexData(GeometryArray ga,
- GeneralizedStrip.IntList indices) {
- Vertex v ;
- Point3f p3f[] = new Point3f[indices.count] ;
-
- if (hasNormals) {
- Vector3f v3f[] = new Vector3f[indices.count] ;
- if (hasColor3) {
- Color3f c3f[] = new Color3f[indices.count] ;
- for (int i = 0 ; i < indices.count ; i++) {
- v = (Vertex)vertices.get(indices.ints[i]) ;
- p3f[i] = v.coord ;
- v3f[i] = v.normal ;
- c3f[i] = v.color3 ;
- }
- ga.setColors(0, c3f) ;
-
- } else if (hasColor4) {
- Color4f c4f[] = new Color4f[indices.count] ;
- for (int i = 0 ; i < indices.count ; i++) {
- v = (Vertex)vertices.get(indices.ints[i]) ;
- p3f[i] = v.coord ;
- v3f[i] = v.normal ;
- c4f[i] = v.color4 ;
- }
- ga.setColors(0, c4f) ;
-
- } else {
- for (int i = 0 ; i < indices.count ; i++) {
- v = (Vertex)vertices.get(indices.ints[i]) ;
- p3f[i] = v.coord ;
- v3f[i] = v.normal ;
- }
- }
- ga.setNormals(0, v3f) ;
-
- } else {
- if (hasColor3) {
- Color3f c3f[] = new Color3f[indices.count] ;
- for (int i = 0 ; i < indices.count ; i++) {
- v = (Vertex)vertices.get(indices.ints[i]) ;
- p3f[i] = v.coord ;
- c3f[i] = v.color3 ;
- }
- ga.setColors(0, c3f) ;
-
- } else if (hasColor4) {
- Color4f c4f[] = new Color4f[indices.count] ;
- for (int i = 0 ; i < indices.count ; i++) {
- v = (Vertex)vertices.get(indices.ints[i]) ;
- p3f[i] = v.coord ;
- c4f[i] = v.color4 ;
- }
- ga.setColors(0, c4f) ;
-
- } else {
- for (int i = 0 ; i < indices.count ; i++) {
- v = (Vertex)vertices.get(indices.ints[i]) ;
- p3f[i] = v.coord ;
- }
- }
- }
- ga.setCoordinates(0, p3f) ;
- }
-
- /**
- * Output a PointArray.
- */
- PointArray toPointArray() {
- int size = vertices.size() ;
-
- if (size > 0) {
- PointArray pa = new PointArray(size, vertexFormat) ;
- GeneralizedStrip.IntList il = new GeneralizedStrip.IntList(size) ;
-
- il.fillAscending() ;
- copyVertexData(pa, il) ;
-
- vertexCount += size ;
- return pa ;
- }
- else
- return null ;
- }
-
- /**
- * Output a TriangleArray.
- */
- TriangleArray toTriangleArray() {
- int vertices[] = GeneralizedStrip.toTriangles(this, frontFace) ;
-
- if (vertices != null) {
- TriangleArray ta ;
- GeneralizedStrip.IntList il ;
-
- ta = new TriangleArray(vertices.length, vertexFormat) ;
- il = new GeneralizedStrip.IntList(vertices) ;
- copyVertexData(ta, il) ;
-
- vertexCount += vertices.length ;
- triangleCount += vertices.length/3 ;
- return ta ;
- } else
- return null ;
- }
-
- /**
- * Output a LineStripArray.
- */
- LineStripArray toLineStripArray() {
- GeneralizedStrip.StripArray stripArray =
- GeneralizedStrip.toLineStrips(this) ;
-
- if (stripArray != null) {
- LineStripArray lsa ;
- lsa = new LineStripArray(stripArray.vertices.count,
- vertexFormat,
- stripArray.stripCounts.trim()) ;
-
- copyVertexData(lsa, stripArray.vertices) ;
-
- vertexCount += stripArray.vertices.count ;
- stripCount += stripArray.stripCounts.count ;
- return lsa ;
- } else
- return null ;
- }
-
- /**
- * Output a TriangleStripArray.
- */
- TriangleStripArray toTriangleStripArray() {
- GeneralizedStrip.StripArray stripArray =
- GeneralizedStrip.toTriangleStrips(this, frontFace) ;
-
- if (stripArray != null) {
- TriangleStripArray tsa ;
- tsa = new TriangleStripArray(stripArray.vertices.count,
- vertexFormat,
- stripArray.stripCounts.trim()) ;
-
- copyVertexData(tsa, stripArray.vertices) ;
-
- vertexCount += stripArray.vertices.count ;
- stripCount += stripArray.stripCounts.count ;
- return tsa ;
- } else
- return null ;
- }
-
- /**
- * Output triangle strip and triangle fan arrays.
- * @return a 2-element array of GeometryStripArray; element 0 if non-null
- * will contain a TriangleStripArray, and element 1 if non-null will
- * contain a TriangleFanArray.
- */
- GeometryStripArray[] toStripAndFanArrays() {
- GeneralizedStrip.StripArray stripArray[] =
- GeneralizedStrip.toStripsAndFans(this, frontFace) ;
-
- GeometryStripArray gsa[] = new GeometryStripArray[2] ;
-
- if (stripArray[0] != null) {
- gsa[0] = new TriangleStripArray(stripArray[0].vertices.count,
- vertexFormat,
- stripArray[0].stripCounts.trim()) ;
-
- copyVertexData(gsa[0], stripArray[0].vertices) ;
-
- vertexCount += stripArray[0].vertices.count ;
- stripCount += stripArray[0].stripCounts.count ;
- }
-
- if (stripArray[1] != null) {
- gsa[1] = new TriangleFanArray(stripArray[1].vertices.count,
- vertexFormat,
- stripArray[1].stripCounts.trim()) ;
-
- copyVertexData(gsa[1], stripArray[1].vertices) ;
-
- vertexCount += stripArray[1].vertices.count ;
- stripCount += stripArray[1].stripCounts.count ;
- }
- return gsa ;
- }
-
- /**
- * Output triangle strip and and triangle arrays.
- * @return a 2-element array of GeometryArray; element 0 if non-null
- * will contain a TriangleStripArray, and element 1 if non-null will
- * contain a TriangleArray.
- */
- GeometryArray[] toStripAndTriangleArrays() {
- GeneralizedStrip.StripArray stripArray[] =
- GeneralizedStrip.toStripsAndTriangles(this, frontFace, 4, 12) ;
-
- GeometryArray ga[] = new GeometryArray[2] ;
-
- if (stripArray[0] != null) {
- ga[0] = new TriangleStripArray(stripArray[0].vertices.count,
- vertexFormat,
- stripArray[0].stripCounts.trim()) ;
-
- copyVertexData(ga[0], stripArray[0].vertices) ;
-
- vertexCount += stripArray[0].vertices.count ;
- stripCount += stripArray[0].stripCounts.count ;
- }
-
- if (stripArray[1] != null) {
- ga[1] = new TriangleArray(stripArray[1].vertices.count,
- vertexFormat) ;
-
- copyVertexData(ga[1], stripArray[1].vertices) ;
- triangleCount += stripArray[1].vertices.count/3 ;
- }
- return ga ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryCompressor.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryCompressor.java
deleted file mode 100644
index c64a691..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryCompressor.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import java.io.IOException;
-
-import javax.vecmath.Point3d;
-
-/**
- * A GeometryCompressor takes a stream of geometric elements and
- * quantization parameters (the CompressionStream object) and
- * compresses it into a stream of commands as defined by appendix B
- * of the Java 3D specification. The resulting data may be output
- * in the form of a CompressedGeometryData node component or appended
- * to a CompressedGeometryFile.
- *
- * @see CompressionStream
- * @see CompressedGeometryData
- * @see CompressedGeometryFile
- *
- * @since Java 3D 1.5
- */
-public class GeometryCompressor {
- private static final boolean benchmark = false ;
- private static final boolean printStream = false ;
- private static final boolean printHuffman = false ;
-
- private HuffmanTable huffmanTable ;
- private CommandStream outputBuffer ;
- private CompressedGeometryData.Header cgHeader ;
- private long startTime ;
-
- public GeometryCompressor() {
- // Create a compressed geometry header.
- cgHeader = new CompressedGeometryData.Header() ;
-
- // v1.0.0 - pre-FCS
- // v1.0.1 - fixed winding order, FCS version (J3D 1.1.2)
- // v1.0.2 - normal component length maximum 6, LII hardware (J3D 1.2)
- cgHeader.majorVersionNumber = 1 ;
- cgHeader.minorVersionNumber = 0 ;
- cgHeader.minorMinorVersionNumber = 2 ;
- }
-
- /**
- * Compress a stream into a CompressedGeometryData node component.
- *
- *
- * @param stream CompressionStream containing the geometry to be compressed
- * @return a CompressedGeometryData node component
- */
- public CompressedGeometryData compress(CompressionStream stream) {
- CompressedGeometryData cg ;
-
- compressStream(stream) ;
- cg = new CompressedGeometryData(cgHeader, outputBuffer.getBytes()) ;
-
- outputBuffer.clear() ;
- return cg ;
- }
-
- /**
- * Compress a stream and append the output to a CompressedGeometryFile.
- * The resource remains open for subsequent updates; its close() method
- * must be called to create a valid compressed geometry resource file.
- *
- * @param stream CompressionStream containing the geometry to be compressed
- * @param f a currently open CompressedGeometryFile with write access
- * @exception IOException if write fails
- */
- public void compress(CompressionStream stream, CompressedGeometryFile f)
- throws IOException {
-
- compressStream(stream) ;
- f.write(cgHeader, outputBuffer.getBytes()) ;
-
- outputBuffer.clear() ;
- }
-
- //
- // Compress the stream and put the results in the output buffer.
- // Set up the CompressedGeometryData.Header object.
- //
- private void compressStream(CompressionStream stream) {
- if (benchmark) startTime = System.currentTimeMillis() ;
-
- // Create the Huffman table.
- huffmanTable = new HuffmanTable() ;
-
- // Quantize the stream, compute deltas between consecutive elements if
- // possible, and histogram the data length distribution.
- stream.quantize(huffmanTable) ;
-
- // Compute tags for stream tokens.
- huffmanTable.computeTags() ;
-
- // Create the output buffer and assemble the compressed output.
- outputBuffer = new CommandStream(stream.getByteCount() / 3) ;
- stream.outputCommands(huffmanTable, outputBuffer) ;
-
- // Print any desired info.
- if (benchmark) printBench(stream) ;
- if (printStream) stream.print() ;
- if (printHuffman) huffmanTable.print() ;
-
- // Set up the compressed geometry header object.
- cgHeader.bufferType = stream.streamType ;
- cgHeader.bufferDataPresent = 0 ;
- cgHeader.lowerBound = new Point3d(stream.ncBounds[0]) ;
- cgHeader.upperBound = new Point3d(stream.ncBounds[1]) ;
-
- if (stream.vertexNormals)
- cgHeader.bufferDataPresent |=
- CompressedGeometryData.Header.NORMAL_IN_BUFFER ;
-
- if (stream.vertexColor3 || stream.vertexColor4)
- cgHeader.bufferDataPresent |=
- CompressedGeometryData.Header.COLOR_IN_BUFFER ;
-
- if (stream.vertexColor4)
- cgHeader.bufferDataPresent |=
- CompressedGeometryData.Header.ALPHA_IN_BUFFER ;
-
- cgHeader.start = 0 ;
- cgHeader.size = outputBuffer.getByteCount() ;
-
- // Clear the huffman table for next use.
- huffmanTable.clear() ;
- }
-
- private void printBench(CompressionStream stream) {
- long t = System.currentTimeMillis() - startTime ;
- int vertexCount = stream.getVertexCount() ;
- int meshReferenceCount = stream.getMeshReferenceCount() ;
- int totalVertices = meshReferenceCount + vertexCount ;
- float meshPercent = 100f * meshReferenceCount/(float)totalVertices ;
-
- float compressionRatio =
- stream.getByteCount() / ((float)outputBuffer.getByteCount()) ;
-
- int vertexBytes =
- 12 + (stream.vertexColor3 ? 12 : 0) +
- (stream.vertexColor4 ? 16 : 0) + (stream.vertexNormals ? 12 : 0) ;
-
- float compressedVertexBytes =
- outputBuffer.getByteCount() / (float)totalVertices ;
-
- System.out.println
- ("\nGeometryCompressor:\n" + totalVertices + " total vertices\n" +
- vertexCount + " streamed vertices\n" + meshReferenceCount +
- " mesh buffer references (" + meshPercent + "%)\n" +
- stream.getByteCount() + " bytes streamed geometry compressed to " +
- outputBuffer.getByteCount() + " in " + (t/1000f) + " sec\n" +
- (stream.getByteCount()/(float)t) + " kbytes/sec, " +
- "stream compression ratio " + compressionRatio + "\n\n" +
- vertexBytes + " original bytes per vertex, " +
- compressedVertexBytes + " compressed bytes per vertex\n" +
- "total vertex compression ratio " +
- (vertexBytes / (float)compressedVertexBytes) + "\n\n" +
- "lower bound " + stream.ncBounds[0].toString() +"\n" +
- "upper bound " + stream.ncBounds[1].toString()) ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressor.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressor.java
deleted file mode 100644
index bbbaa94..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressor.java
+++ /dev/null
@@ -1,1234 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import javax.media.j3d.CompressedGeometryHeader;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3f;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-/**
- * This abstract class provides the base methods needed to create a geometry
- * decompressor. Subclasses must implement a backend to handle the output,
- * consisting of a generalized triangle strip, line strip, or point array,
- * along with possible global color and normal changes.
- */
-abstract class GeometryDecompressor {
- private static final boolean debug = false ;
- private static final boolean benchmark = false ;
-
- /**
- * Compressed geometry format version supported.
- */
- static final int majorVersionNumber = 1 ;
- static final int minorVersionNumber = 0 ;
- static final int minorMinorVersionNumber = 2 ;
-
- /**
- * This method is called when a SetState command is encountered in the
- * decompression stream.
- *
- * @param bundlingNorm true indicates normals are bundled with vertices
- * @param bundlingColor true indicates colors are bundled with vertices
- * @param doingAlpha true indicates alpha values are bundled with vertices
- */
- abstract void outputVertexFormat(boolean bundlingNorm,
- boolean bundlingColor,
- boolean doingAlpha) ;
-
- /**
- * This method captures the vertex output of the decompressor. The normal
- * or color references may be null if the corresponding data is not
- * bundled with the vertices in the compressed geometry buffer. Alpha
- * values may be included in the color.
- *
- * @param position The coordinates of the vertex.
- * @param normal The normal bundled with the vertex. May be null.
- * @param color The color bundled with the vertex. May be null.
- * Alpha may be present.
- * @param vertexReplaceCode Specifies the generalized strip flag
- * that is bundled with each vertex.
- * @see GeneralizedStripFlags
- * @see CompressedGeometryHeader
- */
- abstract void outputVertex(Point3f position, Vector3f normal,
- Color4f color, int vertexReplaceCode) ;
-
- /**
- * This method captures the global color output of the decompressor. It
- * is only invoked if colors are not bundled with the vertex data. The
- * global color applies to all succeeding vertices until the next time the
- * method is invoked.
- *
- * @param color The current global color.
- */
- abstract void outputColor(Color4f color) ;
-
- /**
- * This method captures the global normal output of the decompressor. It
- * is only invoked if normals are not bundled with the vertex data. The
- * global normal applies to all succeeding vertices until the next time the
- * method is invoked.
- *
- * @param normal The current global normal.
- */
- abstract void outputNormal(Vector3f normal) ;
-
- // Geometry compression opcodes.
- private static final int GC_VERTEX = 0x40 ;
- private static final int GC_SET_NORM = 0xC0 ;
- private static final int GC_SET_COLOR = 0x80 ;
- private static final int GC_MESH_B_R = 0x20 ;
- private static final int GC_SET_STATE = 0x18 ;
- private static final int GC_SET_TABLE = 0x10 ;
- private static final int GC_PASS_THROUGH = 0x08 ;
- private static final int GC_EOS = 0x00 ;
- private static final int GC_V_NO_OP = 0x01 ;
- private static final int GC_SKIP_8 = 0x07 ;
-
- // Three 64-entry decompression tables are used: gctables[0] for
- // positions, gctables[1] for colors, and gctables[2] for normals.
- private HuffmanTableEntry gctables[][] ;
-
- /**
- * Decompression table entry.
- */
- static class HuffmanTableEntry {
- int tagLength, dataLength ;
- int rightShift, absolute ;
-
- @Override
- public String toString() {
- return
- " tag length: " + tagLength +
- " data length: " + dataLength +
- " shift: " + rightShift +
- " abs/rel: " + absolute ;
- }
- }
-
- // A 16-entry mesh buffer is used.
- private MeshBufferEntry meshBuffer[] ;
- private int meshIndex = 15 ;
- private int meshState ;
-
- // meshState values. These are needed to determine if colors and/or
- // normals should come from meshBuffer or from SetColor or SetNormal.
- private static final int USE_MESH_NORMAL = 0x1 ;
- private static final int USE_MESH_COLOR = 0x2 ;
-
- /**
- * Mesh buffer entry containing position, normal, and color.
- */
- static class MeshBufferEntry {
- short x, y, z ;
- short octant, sextant, u, v ;
- short r, g, b, a ;
- }
-
- // Geometry compression state variables.
- private short curX, curY, curZ ;
- private short curR, curG, curB, curA ;
- private int curSex, curOct, curU, curV ;
-
- // Current vertex data.
- private Point3f curPos ;
- private Vector3f curNorm ;
- private Color4f curColor ;
- private int repCode ;
-
- // Flags indicating what data is bundled with the vertex.
- private boolean bundlingNorm ;
- private boolean bundlingColor ;
- private boolean doingAlpha ;
-
- // Internal decompression buffering variables.
- private int currentHeader = 0 ;
- private int nextHeader = 0 ;
- private int bitBuffer = 0 ;
- private int bitBufferCount = 32 ;
-
- // Used for benchmarking if so configured.
- private long startTime ;
- private int vertexCount ;
-
- // Bit-field masks: BMASK[i] = (1< 64) continue ;
-
- psi = NORMAL_MAX_Y_ANG * (i / 64.0) ;
- th = Math.asin(Math.tan(NORMAL_MAX_Y_ANG * ((64-j)/64.0))) ;
-
- qnx = Math.cos(th) * Math.cos(psi) ;
- qny = Math.sin(psi) ;
- qnz = Math.sin(th) * Math.cos(psi) ;
-
- // Convert the floating point normal to s1.14 bit notation,
- // then back again.
- qnx = qnx*16384.0 ; inx = (int)qnx ;
- qnx = (double)inx ; qnx = qnx/16384.0 ;
-
- qny = qny*16384.0 ; iny = (int)qny ;
- qny = (double)iny ; qny = qny/16384.0 ;
-
- qnz = qnz*16384.0 ; inz = (int)qnz ;
- qnz = (double)inz ; qnz = qnz/16384.0 ;
-
- gcNormals[i][j][0] = qnx ;
- gcNormals[i][j][1] = qny ;
- gcNormals[i][j][2] = qnz ;
- }
- }
-
- if (printNormalTable) {
- System.out.println("struct {") ;
- System.out.println(" double nx, ny, nz ;") ;
- System.out.println("} gcNormals[65][65] = {");
- for (i = 0 ; i <= 64 ; i++) {
- System.out.println("{") ;
- for (j = 0 ; j <= 64 ; j++) {
- if (j+i > 64) continue ;
- System.out.println("{ " + gcNormals[i][j][0] +
- ", " + gcNormals[i][j][1] +
- ", " + gcNormals[i][j][2] + " }") ;
- }
- System.out.println("},") ;
- }
- System.out.println("}") ;
- }
- }
-
- //
- // The constructor.
- //
- GeometryDecompressor() {
- curPos = new Point3f() ;
- curNorm = new Vector3f() ;
- curColor = new Color4f() ;
- gctables = new HuffmanTableEntry[3][64] ;
-
- for (int i = 0 ; i < 64 ; i++) {
- gctables[0][i] = new HuffmanTableEntry() ;
- gctables[1][i] = new HuffmanTableEntry() ;
- gctables[2][i] = new HuffmanTableEntry() ;
- }
-
- meshBuffer = new MeshBufferEntry[16] ;
- for (int i = 0 ; i < 16 ; i++)
- meshBuffer[i] = new MeshBufferEntry() ;
- }
-
- /**
- * Check version numbers and return true if compatible.
- */
- boolean checkVersion(int majorVersionNumber, int minorVersionNumber) {
- return ((majorVersionNumber < this.majorVersionNumber) ||
- ((majorVersionNumber == this.majorVersionNumber) &&
- (minorVersionNumber <= this.minorVersionNumber))) ;
- }
-
- /**
- * Decompress data and invoke abstract output methods.
- *
- * @param start byte offset to start of compressed geometry in data array
- * @param length size of compressed geometry in bytes
- * @param data array containing compressed geometry buffer of the
- * specified length at the given offset from the start of the array
- * @exception ArrayIndexOutOfBoundsException if start+length > data size
- */
- void decompress(int start, int length, byte data[]) {
- if (debug)
- System.out.println("GeometryDecompressor.decompress\n" +
- " start: " + start +
- " length: " + length +
- " data array size: " + data.length) ;
- if (benchmark)
- benchmarkStart(length) ;
-
- if (start+length > data.length)
- throw new ArrayIndexOutOfBoundsException
- (J3dUtilsI18N.getString("GeometryDecompressor0")) ;
-
- // Set reference to compressed data and skip to start of data.
- gcData = data ;
- gcIndex = start ;
-
- // Initialize state.
- bitBufferCount = 0 ;
- meshState = 0 ;
- bundlingNorm = false ;
- bundlingColor = false ;
- doingAlpha = false ;
- repCode = 0 ;
-
- // Headers are interleaved for hardware implementations, so the
- // first is always a nullop.
- nextHeader = GC_V_NO_OP ;
-
- // Enter decompression loop.
- while (gcIndex < start+length)
- processDecompression() ;
-
- // Finish out any bits left in bitBuffer.
- while (bitBufferCount > 0)
- processDecompression() ;
-
- if (benchmark)
- benchmarkPrint(length) ;
- }
-
- //
- // Return the next bitCount bits of compressed data.
- //
- private int getBits(int bitCount, String d) {
- int bits ;
-
- if (debug)
- System.out.print(" getBits(" + bitCount + ") " + d + ", " +
- bitBufferCount + " available at gcIndex " +
- gcIndex) ;
-
- if (bitCount == 0) {
- if (debug) System.out.println(": got 0x0") ;
- return 0 ;
- }
-
- if (bitBufferCount == 0) {
- bitBuffer = (((gcData[gcIndex++] & 0xff) << 24) |
- ((gcData[gcIndex++] & 0xff) << 16) |
- ((gcData[gcIndex++] & 0xff) << 8) |
- ((gcData[gcIndex++] & 0xff))) ;
-
- bitBufferCount = 32 ;
- }
-
- if (bitBufferCount >= bitCount) {
- bits = (bitBuffer >>> (32 - bitCount)) & BMASK[bitCount] ;
- bitBuffer = bitBuffer << bitCount ;
- bitBufferCount -= bitCount ;
- } else {
- bits = (bitBuffer >>> (32 - bitCount)) & BMASK[bitCount] ;
- bits = bits >>> (bitCount - bitBufferCount) ;
- bits = bits << (bitCount - bitBufferCount) ;
-
- bitBuffer = (((gcData[gcIndex++] & 0xff) << 24) |
- ((gcData[gcIndex++] & 0xff) << 16) |
- ((gcData[gcIndex++] & 0xff) << 8) |
- ((gcData[gcIndex++] & 0xff))) ;
-
- bits = bits |
- ((bitBuffer >>> (32 - (bitCount - bitBufferCount))) &
- BMASK[bitCount - bitBufferCount]) ;
-
- bitBuffer = bitBuffer << (bitCount - bitBufferCount) ;
- bitBufferCount = 32 - (bitCount - bitBufferCount) ;
- }
-
- if (debug)
- System.out.println(": got 0x" + Integer.toHexString(bits)) ;
-
- return bits ;
- }
-
- //
- // Shuffle interleaved headers and opcodes.
- //
- private void processDecompression() {
- int mbp ;
- currentHeader = nextHeader ;
-
- if ((currentHeader & 0xC0) == GC_VERTEX) {
- // Process a vertex.
- if (!bundlingNorm && !bundlingColor) {
- // get next opcode, process current position opcode
- nextHeader = getBits(8, "header") ;
- mbp = processDecompressionOpcode(0) ;
-
- } else if (bundlingNorm && !bundlingColor) {
- // get normal header, process current position opcode
- nextHeader = getBits(6, "normal") ;
- mbp = processDecompressionOpcode(0) ;
- currentHeader = nextHeader | GC_SET_NORM ;
-
- // get next opcode, process current normal opcode
- nextHeader = getBits(8, "header") ;
- processDecompressionOpcode(mbp) ;
-
- } else if (!bundlingNorm && bundlingColor) {
- // get color header, process current position opcode
- nextHeader = getBits(6, "color") ;
- mbp = processDecompressionOpcode(0) ;
- currentHeader = nextHeader | GC_SET_COLOR ;
-
- // get next opcode, process current color opcode
- nextHeader = getBits(8, "header") ;
- processDecompressionOpcode(mbp) ;
-
- } else {
- // get normal header, process current position opcode
- nextHeader = getBits(6, "normal") ;
- mbp = processDecompressionOpcode(0) ;
- currentHeader = nextHeader | GC_SET_NORM ;
-
- // get color header, process current normal opcode
- nextHeader = getBits(6, "color") ;
- processDecompressionOpcode(mbp) ;
- currentHeader = nextHeader | GC_SET_COLOR ;
-
- // get next opcode, process current color opcode
- nextHeader = getBits(8, "header") ;
- processDecompressionOpcode(mbp) ;
- }
-
- // Send out the complete vertex.
- outputVertex(curPos, curNorm, curColor, repCode) ;
- if (benchmark) vertexCount++ ;
-
- // meshState bits get turned off in the setColor and setNormal
- // routines in order to keep track of what data a mesh buffer
- // reference should use.
- meshState |= USE_MESH_NORMAL ;
- meshState |= USE_MESH_COLOR ;
-
- } else {
- // Non-vertex case: get next opcode, then process current opcode.
- nextHeader = getBits(8, "header") ;
- processDecompressionOpcode(0) ;
- }
- }
-
- //
- // Decode the opcode in currentHeader, and dispatch to the appropriate
- // processing method.
- //
- private int processDecompressionOpcode(int mbp) {
- if ((currentHeader & 0xC0) == GC_SET_NORM)
- processSetNormal(mbp) ;
- else if ((currentHeader & 0xC0) == GC_SET_COLOR)
- processSetColor(mbp) ;
- else if ((currentHeader & 0xC0) == GC_VERTEX)
- // Return the state of the mesh buffer push bit
- // when processing a vertex.
- return processVertex() ;
- else if ((currentHeader & 0xE0) == GC_MESH_B_R) {
- processMeshBR() ;
-
- // Send out the complete vertex.
- outputVertex(curPos, curNorm, curColor, repCode) ;
- if (benchmark) vertexCount++ ;
-
- // meshState bits get turned off in the setColor and setNormal
- // routines in order to keep track of what data a mesh buffer
- // reference should use.
- meshState |= USE_MESH_NORMAL ;
- meshState |= USE_MESH_COLOR ;
- }
- else if ((currentHeader & 0xF8) == GC_SET_STATE)
- processSetState() ;
- else if ((currentHeader & 0xF8) == GC_SET_TABLE)
- processSetTable() ;
- else if ((currentHeader & 0xFF) == GC_EOS)
- processEos() ;
- else if ((currentHeader & 0xFF) == GC_V_NO_OP)
- processVNoop() ;
- else if ((currentHeader & 0xFF) == GC_PASS_THROUGH)
- processPassThrough() ;
- else if ((currentHeader & 0xFF) == GC_SKIP_8)
- processSkip8() ;
-
- return 0 ;
- }
-
- //
- // Process a set state opcode.
- //
- private void processSetState() {
- int ii ;
- if (debug)
- System.out.println("GeometryDecompressor.processSetState") ;
-
- ii = getBits(3, "bundling") ;
-
- bundlingNorm = ((currentHeader & 0x1) != 0) ;
- bundlingColor = (((ii >>> 2) & 0x1) != 0) ;
- doingAlpha = (((ii >>> 1) & 0x1) != 0) ;
-
- if (debug)
- System.out.println(" bundling normal: " + bundlingNorm +
- " bundling color: " + bundlingColor +
- " alpha present: " + doingAlpha) ;
-
- // Call the abstract output implementation.
- outputVertexFormat(bundlingNorm, bundlingColor, doingAlpha) ;
- }
-
- //
- // Process a set decompression table opcode.
- //
- // Extract the parameters of the table set command,
- // and set the approprate table entries.
- //
- private void processSetTable() {
- HuffmanTableEntry gct[] ;
- int i, adr, tagLength, dataLength, rightShift, absolute ;
- int ii, index ;
-
- if (debug)
- System.out.println("GeometryDecompressor.processSetTable") ;
-
- // Get reference to approprate 64 entry table.
- index = (currentHeader & 0x6) >>> 1 ;
- gct = gctables[index] ;
-
- // Get the remaining bits of the set table command.
- ii = getBits(15, "set table") ;
-
- // Extract the individual fields from the two bit strings.
- adr = ((currentHeader & 0x1) << 6) | ((ii >>> 9) & 0x3F) ;
-
- // Get data length. For positions and colors, 0 really means 16, as 0
- // lengths are meaningless for them. Normal components are allowed to
- // have lengths of 0.
- dataLength = (ii >>> 5) & 0x0F ;
- if (dataLength == 0 && index != 2)
- dataLength = 16 ;
-
- rightShift = ii & 0x0F ;
- absolute = (ii >>> 4) & 0x1 ;
-
- //
- // Decode the tag length from the address field by finding the
- // first set 1 from the left in the bitfield.
- //
- for (tagLength = 6 ; tagLength > 0 ; tagLength--) {
- if ((adr >> tagLength) != 0) break ;
- }
-
- // Shift the address bits up into place, and off the leading 1.
- adr = (adr << (6 - tagLength)) & 0x3F ;
-
- if (debug)
- System.out.println(" table " + ((currentHeader & 0x6) >>> 1) +
- " address " + adr +
- " tag length " + tagLength +
- " data length " + dataLength +
- " shift " + rightShift +
- " absolute " + absolute) ;
-
- // Fill in the table fields with the specified values.
- for (i = 0 ; i < (1 << (6 - tagLength)) ; i++) {
- gct[adr+i].tagLength = tagLength ;
- gct[adr+i].dataLength = dataLength ;
- gct[adr+i].rightShift = rightShift ;
- gct[adr+i].absolute = absolute ;
- }
- }
-
-
- //
- // Process a vertex opcode. Any bundled normal and/or color will be
- // processed by separate methods. Return the mesh buffer push indicator.
- //
- private int processVertex() {
- HuffmanTableEntry gct ;
- float fX, fY, fZ ;
- short dx, dy, dz ;
- int mbp, x, y, z, dataLen ;
- int ii ;
-
- // If the next command is a mesh buffer reference
- // then use colors and normals from the mesh buffer.
- meshState = 0 ;
-
- // Get a reference to the approprate tag table entry.
- gct = gctables[0][currentHeader & 0x3F] ;
-
- if (debug) System.out.println("GeometryDecompressor.processVertex\n" +
- gct.toString()) ;
-
- // Get the true length of the data.
- dataLen = gct.dataLength - gct.rightShift ;
-
- // Read in the replace code and mesh buffer push bits,
- // if they're not in the current header.
- if (6 - (3 * dataLen) - gct.tagLength > 0) {
- int numBits = 6 - (3 * dataLen) - gct.tagLength ;
- int jj ;
-
- jj = currentHeader & BMASK[numBits] ;
- ii = getBits(3 - numBits, "repcode/mbp") ;
- ii |= (jj << (3 - numBits)) ;
- }
- else
- ii = getBits(3, "repcode/mbp") ;
-
- repCode = ii >>> 1 ;
- mbp = ii & 0x1 ;
-
- // Read in x, y, and z components.
- x = currentHeader & BMASK[6-gct.tagLength] ;
-
- if (gct.tagLength + dataLen == 6) {
- y = getBits(dataLen, "y") ;
- z = getBits(dataLen, "z") ;
- } else if (gct.tagLength + dataLen < 6) {
- x = x >> (6 - gct.tagLength - dataLen) ;
-
- y = currentHeader & BMASK[6 - gct.tagLength - dataLen] ;
- if (gct.tagLength + 2*dataLen == 6) {
- z = getBits(dataLen, "z") ;
- } else if (gct.tagLength + 2*dataLen < 6) {
- y = y >> (6 - gct.tagLength - 2*dataLen) ;
-
- z = currentHeader & BMASK[6 - gct.tagLength - 2*dataLen] ;
- if (gct.tagLength + 3*dataLen < 6) {
- z = z >> (6 - gct.tagLength - 3*dataLen) ;
- } else if (gct.tagLength + 3*dataLen > 6) {
- ii = getBits(dataLen - (6 - gct.tagLength - 2*dataLen),
- "z") ;
- z = (z << (dataLen - (6 - gct.tagLength - 2*dataLen)))
- | ii ;
- }
- } else {
- ii = getBits(dataLen - (6 - gct.tagLength - dataLen), "y") ;
- y = (y << (dataLen - (6 - gct.tagLength - dataLen))) | ii ;
- z = getBits(dataLen, "z") ;
- }
- } else {
- ii = getBits(dataLen - (6 - gct.tagLength), "x") ;
- x = (x << (dataLen - (6 - gct.tagLength))) | ii ;
- y = getBits(dataLen, "y") ;
- z = getBits(dataLen, "z") ;
- }
-
- // Sign extend delta x y z components.
- x = x << (32 - dataLen) ; x = x >> (32 - dataLen) ;
- y = y << (32 - dataLen) ; y = y >> (32 - dataLen) ;
- z = z << (32 - dataLen) ; z = z >> (32 - dataLen) ;
-
- // Normalize values.
- dx = (short)(x << gct.rightShift) ;
- dy = (short)(y << gct.rightShift) ;
- dz = (short)(z << gct.rightShift) ;
-
- // Update current position, first adding deltas if in relative mode.
- if (gct.absolute != 0) {
- curX = dx ; curY = dy ; curZ = dz ;
- if (debug) System.out.println(" absolute position: " +
- curX + " " + curY + " " + curZ) ;
- } else {
- curX += dx ; curY += dy ; curZ += dz ;
- if (debug) System.out.println(" delta position: " +
- dx + " " + dy + " " + dz) ;
- }
-
- // Do optional mesh buffer push.
- if (mbp != 0) {
- // Increment to next position (meshIndex is initialized to 15).
- meshIndex = (meshIndex + 1) & 0xF ;
- meshBuffer[meshIndex].x = curX ;
- meshBuffer[meshIndex].y = curY ;
- meshBuffer[meshIndex].z = curZ ;
- if (debug)
- System.out.println(" pushed position into mesh buffer at " +
- meshIndex) ;
- }
-
- // Convert point back to [-1..1] floating point.
- fX = curX ; fX /= 32768.0 ;
- fY = curY ; fY /= 32768.0 ;
- fZ = curZ ; fZ /= 32768.0 ;
- if (debug)
- System.out.println(" result position " + fX + " " + fY + " " + fZ) ;
-
- curPos.set(fX, fY, fZ) ;
- return mbp ;
- }
-
-
- //
- // Process a set current normal opcode.
- //
- private void processSetNormal(int mbp) {
- HuffmanTableEntry gct ;
- int index, du, dv, n, dataLength ;
- int ii ;
-
- // if next command is a mesh buffer reference, use this normal
- meshState &= ~USE_MESH_NORMAL ;
-
- // use table 2 for normals
- gct = gctables[2][currentHeader & 0x3F] ;
-
- if (debug)
- System.out.println("GeometryDecompressor.processSetNormal\n" +
- gct.toString()) ;
-
- // subtract up-shift amount to get true data (u, v) length
- dataLength = gct.dataLength - gct.rightShift ;
-
- if (gct.absolute != 0) {
- //
- // Absolute normal case. Extract index from 6-bit tag.
- //
- index = currentHeader & BMASK[6-gct.tagLength] ;
-
- if (gct.tagLength != 0) {
- // read in the rest of the 6-bit sex/oct pair (index)
- ii = getBits(6 - (6 - gct.tagLength), "sex/oct") ;
- index = (index << (6 - (6 - gct.tagLength))) | ii ;
- }
-
- // read in u and v data
- curU = getBits(dataLength, "u") ;
- curV = getBits(dataLength, "v") ;
-
- // normalize u, v, sextant, and octant
- curU = curU << gct.rightShift ;
- curV = curV << gct.rightShift ;
-
- curSex = (index >> 3) & 0x7 ;
- curOct = index & 0x7 ;
-
- if (debug) {
- if (curSex < 6)
- System.out.println(" absolute normal: sex " + curSex +
- " oct " + curOct +
- " u " + curU + " v " + curV) ;
- else
- System.out.println(" special normal: sex " + curSex +
- " oct " + curOct) ;
- }
- } else {
- //
- // Relative normal case. Extract du from 6-bit tag.
- //
- du = currentHeader & BMASK[6-gct.tagLength] ;
-
- if (gct.tagLength + dataLength < 6) {
- // normalize du, get dv
- du = du >> (6 - gct.tagLength - dataLength) ;
- dv = currentHeader & BMASK[6 - gct.tagLength - dataLength] ;
-
- if (gct.tagLength + 2*dataLength < 6) {
- // normalize dv
- dv = dv >> (6 - gct.tagLength - 2*dataLength) ;
- } else if (gct.tagLength + 2*dataLength > 6) {
- // read in rest of dv and normalize it
- ii = getBits(dataLength -
- (6 - gct.tagLength - dataLength), "dv") ;
- dv = (dv << (dataLength -
- (6 - gct.tagLength - dataLength))) | ii ;
- }
- } else if (gct.tagLength + dataLength > 6) {
- // read in rest of du and normalize it
- ii = getBits(dataLength - (6 - gct.tagLength), "du") ;
- du = (du << (dataLength - (6 - gct.tagLength))) | ii ;
- // read in dv
- dv = getBits(dataLength, "dv") ;
- } else {
- // read in dv
- dv = getBits(dataLength, "dv") ;
- }
-
- // Sign extend delta uv components.
- du = du << (32 - dataLength) ; du = du >> (32 - dataLength) ;
- dv = dv << (32 - dataLength) ; dv = dv >> (32 - dataLength) ;
-
- // normalize values
- du = du << gct.rightShift ;
- dv = dv << gct.rightShift ;
-
- // un-delta
- curU += du ;
- curV += dv ;
-
- if (debug)
- System.out.println(" delta normal: du " + du + " dv " + dv) ;
-
- //
- // Check for normal wrap.
- //
- if (! ((curU >= 0) && (curV >= 0) && (curU + curV <= 64)))
- if ((curU < 0) && (curV >= 0)) {
- // wrap on u, same octant, different sextant
- curU = -curU ;
- switch (curSex) {
- case 0: curSex = 4 ; break ;
- case 1: curSex = 5 ; break ;
- case 2: curSex = 3 ; break ;
- case 3: curSex = 2 ; break ;
- case 4: curSex = 0 ; break ;
- case 5: curSex = 1 ; break ;
- }
- } else if ((curU >= 0) && (curV < 0)) {
- // wrap on v, same sextant, different octant
- curV = -curV ;
- switch (curSex) {
- case 1: case 5:
- curOct = curOct ^ 4 ; // invert x axis
- break ;
- case 0: case 4:
- curOct = curOct ^ 2 ; // invert y axis
- break ;
- case 2: case 3:
- curOct = curOct ^ 1 ; // invert z axis
- break ;
- }
- } else if (curU + curV > 64) {
- // wrap on uv, same octant, different sextant
- curU = 64 - curU ;
- curV = 64 - curV ;
- switch (curSex) {
- case 0: curSex = 2 ; break ;
- case 1: curSex = 3 ; break ;
- case 2: curSex = 0 ; break ;
- case 3: curSex = 1 ; break ;
- case 4: curSex = 5 ; break ;
- case 5: curSex = 4 ; break ;
- }
- } else {
- throw new IllegalArgumentException
- (J3dUtilsI18N.getString("GeometryDecompressor1")) ;
- }
- }
-
- // do optional mesh buffer push
- if (mbp != 0) {
- if (debug)
- System.out.println(" pushing normal into mesh buffer at " +
- meshIndex) ;
-
- meshBuffer[meshIndex].sextant = (short)curSex ;
- meshBuffer[meshIndex].octant = (short)curOct ;
- meshBuffer[meshIndex].u = (short)curU ;
- meshBuffer[meshIndex].v = (short)curV ;
- }
-
- // convert normal back to [-1..1] floating point
- indexNormal(curSex, curOct, curU, curV, curNorm) ;
-
- // a set normal opcode when normals aren't bundled with the vertices
- // is a global normal change.
- if (! bundlingNorm) outputNormal(curNorm) ;
- }
-
-
- //
- // Get the floating point normal from its sextant, octant, u, and v.
- //
- private void indexNormal(int sex, int oct, int u, int v, Vector3f n) {
- float nx, ny, nz, t ;
-
- if (debug) System.out.println(" sextant " + sex + " octant " + oct +
- " u " + u + " v " + v) ;
- if (sex > 5) {
- // special normals
- switch (oct & 0x1) {
- case 0: // six coordinate axes
- switch (((sex & 0x1) << 1) | ((oct & 0x4) >> 2)) {
- case 0: nx = 1.0f ; ny = nz = 0.0f ; break ;
- case 1: ny = 1.0f ; nx = nz = 0.0f ; break ;
- default:
- case 2: nz = 1.0f ; nx = ny = 0.0f ; break ;
- }
- sex = 0 ; oct = (oct & 0x2) >> 1 ;
- oct = (oct << 2) | (oct << 1) | oct ;
- break ;
- case 1: // eight mid
- default:
- oct = ((sex & 0x1) << 2) | (oct >> 1) ;
- sex = 0 ;
- nx = ny = nz = (float)(1.0/Math.sqrt(3.0)) ;
- break ;
- }
- if ((oct & 0x1) != 0) nz = -nz ;
- if ((oct & 0x2) != 0) ny = -ny ;
- if ((oct & 0x4) != 0) nx = -nx ;
-
- } else {
- // regular normals
- nx = (float)gcNormals[v][u][0] ;
- ny = (float)gcNormals[v][u][1] ;
- nz = (float)gcNormals[v][u][2] ;
-
- // reverse the swap
- if ((sex & 0x4) != 0) { t = nx ; nx = nz ; nz = t ; }
- if ((sex & 0x2) != 0) { t = ny ; ny = nz ; nz = t ; }
- if ((sex & 0x1) != 0) { t = nx ; nx = ny ; ny = t ; }
-
- // reverse the sign flip
- if ((oct & 0x1) != 0) nz = -nz ;
- if ((oct & 0x2) != 0) ny = -ny ;
- if ((oct & 0x4) != 0) nx = -nx ;
- }
-
- // return resulting normal
- n.set(nx, ny, nz) ;
- if (debug)
- System.out.println(" result normal: " + nx + " " + ny + " " + nz) ;
- }
-
-
- //
- // Process a set current color command.
- //
- private void processSetColor(int mbp) {
- HuffmanTableEntry gct ;
- short dr, dg, db, da ;
- float fR, fG, fB, fA ;
- int r, g, b, a, index, dataLength ;
- int ii ;
-
- // If the next command is a mesh buffer reference, use this color.
- meshState &= ~USE_MESH_COLOR ;
-
- // Get the huffman table entry.
- gct = gctables[1][currentHeader & 0x3F] ;
-
- if (debug)
- System.out.println("GeometryDecompressor.processSetColor\n" +
- gct.toString()) ;
-
- // Get the true length of the data.
- dataLength = gct.dataLength - gct.rightShift ;
-
- // Read in red, green, blue, and possibly alpha.
- r = currentHeader & BMASK[6 - gct.tagLength] ;
- a = 0 ;
-
- if (gct.tagLength + dataLength == 6) {
- g = getBits(dataLength, "g") ;
- b = getBits(dataLength, "b") ;
- if (doingAlpha)
- a = getBits(dataLength, "a") ;
- }
- else if (gct.tagLength + dataLength < 6) {
- r = r >> (6 - gct.tagLength - dataLength) ;
-
- g = currentHeader & BMASK[6-gct.tagLength-dataLength] ;
- if (gct.tagLength + 2*dataLength == 6) {
- b = getBits(dataLength, "b") ;
- if (doingAlpha)
- a = getBits(dataLength, "a") ;
- }
- else if (gct.tagLength + 2*dataLength < 6) {
- g = g >> (6 - gct.tagLength - 2*dataLength) ;
-
- b = currentHeader & BMASK[6-gct.tagLength-2*dataLength] ;
- if (gct.tagLength + 3*dataLength == 6) {
- if (doingAlpha)
- a = getBits(dataLength, "a") ;
- }
- else if (gct.tagLength + 3*dataLength < 6) {
- b = b >> (6 - gct.tagLength - 3*dataLength) ;
-
- if (doingAlpha) {
- a = currentHeader &
- BMASK[6 - gct.tagLength - 4*dataLength] ;
- if (gct.tagLength + 4 * dataLength < 6) {
- a = a >> (6 - gct.tagLength - 3*dataLength) ;
- }
- else if (gct.tagLength + 4 * dataLength > 6) {
- ii = getBits(dataLength -
- (6-gct.tagLength - 3*dataLength), "a") ;
- a = (a << (dataLength -
- (6-gct.tagLength - 3*dataLength))) | ii ;
- }
- }
- } else {
- ii = getBits(dataLength -
- (6 - gct.tagLength - 2*dataLength), "b") ;
- b = (b << (dataLength -
- (6 - gct.tagLength - 2*dataLength))) | ii ;
- if (doingAlpha)
- a = getBits(dataLength, "a") ;
- }
- } else {
- ii = getBits(dataLength - (6 - gct.tagLength - dataLength),
- "g") ;
- g = (g << (dataLength -
- (6 - gct.tagLength - dataLength))) | ii ;
- b = getBits(dataLength, "b") ;
- if (doingAlpha)
- a = getBits(dataLength, "a") ;
- }
- } else {
- ii = getBits(dataLength - (6 - gct.tagLength), "r") ;
- r = (r << (dataLength - (6 - gct.tagLength))) | ii ;
- g = getBits(dataLength, "g") ;
- b = getBits(dataLength, "b") ;
- if (doingAlpha)
- a = getBits(dataLength, "a") ;
- }
-
- // Sign extend delta x y z components.
- r <<= (32 - dataLength) ; r >>= (32 - dataLength) ;
- g <<= (32 - dataLength) ; g >>= (32 - dataLength) ;
- b <<= (32 - dataLength) ; b >>= (32 - dataLength) ;
- a <<= (32 - dataLength) ; a >>= (32 - dataLength) ;
-
- // Normalize values.
- dr = (short)(r << gct.rightShift) ;
- dg = (short)(g << gct.rightShift) ;
- db = (short)(b << gct.rightShift) ;
- da = (short)(a << gct.rightShift) ;
-
- // Update current position, first adding deltas if in relative mode.
- if (gct.absolute != 0) {
- curR = dr ; curG = dg ; curB = db ;
- if (doingAlpha) curA = da ;
- if (debug) System.out.println(" absolute color: r " + curR +
- " g " + curG + " b " + curB +
- " a " + curA) ;
- } else {
- curR += dr ; curG += dg ; curB += db ;
- if (doingAlpha) curA += da ;
- if (debug) System.out.println(" delta color: dr " + dr +
- " dg " + dg + " db " + db +
- " da " + da) ;
- }
-
- // Do optional mesh buffer push.
- if (mbp != 0) {
- if (debug)
- System.out.println(" pushing color into mesh buffer at " +
- meshIndex) ;
-
- meshBuffer[meshIndex].r = curR ;
- meshBuffer[meshIndex].g = curG ;
- meshBuffer[meshIndex].b = curB ;
- meshBuffer[meshIndex].a = curA ;
- }
-
- // Convert point back to [-1..1] floating point.
- fR = curR ; fR /= 32768.0 ;
- fG = curG ; fG /= 32768.0 ;
- fB = curB ; fB /= 32768.0 ;
- fA = curA ; fA /= 32768.0 ;
-
- curColor.set(fR, fG, fB, fA) ;
- if (debug) System.out.println(" result color: " + fR +
- " " + fG + " " + fB + " " + fA) ;
-
- // A set color opcode when colors aren't bundled with the vertices
- // is a global color change.
- if (! bundlingColor) outputColor(curColor) ;
- }
-
-
- //
- // Process a mesh buffer reference command.
- //
- private void processMeshBR() {
- MeshBufferEntry entry ;
- int index, normal ;
- int ii ;
-
- if (debug)
- System.out.println("GeometryDecompressor.processMeshBR") ;
-
- ii = getBits(1, "mbr") ;
-
- index = (currentHeader >>> 1) & 0xF ;
- repCode = ((currentHeader & 0x1) << 1) | ii ;
-
- // Adjust index to proper place in fifo.
- index = (meshIndex - index) & 0xf ;
- if (debug)
- System.out.println(" using index " + index) ;
-
- // Get reference to mesh buffer entry.
- entry = meshBuffer[index] ;
- curX = entry.x ;
- curY = entry.y ;
- curZ = entry.z ;
-
- // Convert point back to [-1..1] floating point.
- curPos.set(((float)curX)/32768.0f,
- ((float)curY)/32768.0f,
- ((float)curZ)/32768.0f) ;
-
- if (debug) System.out.println(" retrieved position " + curPos.x +
- " " + curPos.y + " " + curPos.z +
- " replace code " + repCode) ;
-
- // Get mesh buffer normal if previous opcode was not a setNormal.
- if (bundlingNorm && ((meshState & USE_MESH_NORMAL) != 0)) {
- curSex = entry.sextant ;
- curOct = entry.octant ;
- curU = entry.u ;
- curV = entry.v ;
-
- // Convert normal back to -1.0 - 1.0 floating point from index.
- normal = (curSex<<15) | (curOct<<12) | (curU<<6) | curV ;
-
- if (debug) System.out.println(" retrieving normal") ;
- indexNormal(curSex, curOct, curU, curV, curNorm) ;
- }
-
- // Get mesh buffer color if previous opcode was not a setColor.
- if (bundlingColor && ((meshState & USE_MESH_COLOR) != 0)) {
- curR = entry.r ;
- curG = entry.g ;
- curB = entry.b ;
-
- // Convert point back to -1.0 - 1.0 floating point.
- curColor.x = curR ; curColor.x /= 32768.0 ;
- curColor.y = curG ; curColor.y /= 32768.0 ;
- curColor.z = curB ; curColor.z /= 32768.0 ;
-
- if (doingAlpha) {
- curA = entry.a ;
- curColor.w = curA ; curColor.w /= 32768.0 ;
- }
- if (debug)
- System.out.println(" retrieved color " + curColor.x +
- " " + curColor.y + " " + curColor.z +
- " " + curColor.w) ;
- }
-
- // Reset meshState.
- meshState = 0 ;
- }
-
-
- // Process a end-of-stream opcode.
- private void processEos() {
- if (debug) System.out.println("GeometryDecompressor.processEos") ;
- }
-
- // Process a variable length no-op opcode.
- private void processVNoop() {
- int ii, ct ;
- if (debug) System.out.println("GeometryDecompressor.processVNoop") ;
-
- ct = getBits(5, "noop count") ;
- ii = getBits(ct, "noop bits") ;
- }
-
- // Process a pass-through opcode.
- private void processPassThrough() {
- int ignore ;
- if (debug)
- System.out.println("GeometryDecompressor.processPassThrough") ;
-
- ignore = getBits(24, "passthrough") ;
- ignore = getBits(32, "passthrough") ;
- }
-
- // Process a skip-8 opcode.
- private void processSkip8() {
- int skip ;
- if (debug) System.out.println("GeometryDecompressor.processSkip8") ;
-
- skip = getBits(8, "skip8") ;
- }
-
- private void benchmarkStart(int length) {
- vertexCount = 0 ;
- System.out.println(" GeometryDecompressor: decompressing " +
- length + " bytes...") ;
- startTime = System.currentTimeMillis() ;
- }
-
- private void benchmarkPrint(int length) {
- float t = (System.currentTimeMillis() - startTime) / 1000.0f ;
- System.out.println
- (" done in " + t + " sec." + "\n" +
- " decompressed " + vertexCount + " vertices at " +
- (vertexCount/t) + " vertices/sec\n") ;
-
- System.out.print(" vertex data present: coords") ;
- int floatVertexSize = 12 ;
- if (bundlingNorm) {
- System.out.print(" normals") ;
- floatVertexSize += 12 ;
- }
- if (bundlingColor) {
- System.out.println(" colors") ;
- floatVertexSize += 12 ;
- }
- if (doingAlpha) {
- System.out.println(" alpha") ;
- floatVertexSize += 4 ;
- }
- System.out.println() ;
-
- System.out.println
- (" bytes of data in generalized strip output: " +
- (vertexCount * floatVertexSize) + "\n" +
- " compression ratio: " +
- (length / (float)(vertexCount * floatVertexSize)) + "\n") ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressorShape3D.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressorShape3D.java
deleted file mode 100644
index b412f9f..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/GeometryDecompressorShape3D.java
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import java.util.ArrayList;
-
-import javax.media.j3d.Appearance;
-import javax.media.j3d.CompressedGeometry;
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.GeometryStripArray;
-import javax.media.j3d.LineStripArray;
-import javax.media.j3d.Material;
-import javax.media.j3d.PointArray;
-import javax.media.j3d.Shape3D;
-import javax.media.j3d.TriangleArray;
-import javax.media.j3d.TriangleStripArray;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3f;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-/**
- * This class implements a Shape3D backend for the abstract
- * GeometryDecompressor.
- */
-class GeometryDecompressorShape3D extends GeometryDecompressor {
- private static final boolean debug = false ;
- private static final boolean benchmark = false ;
- private static final boolean statistics = false ;
- private static final boolean printInfo = debug || benchmark || statistics ;
-
- // Type of connections in the compressed data:
- // TYPE_POINT (1), TYPE_LINE (2), or TYPE_TRIANGLE (4).
- private int bufferDataType ;
-
- // Data bundled with each vertex: bitwise combination of
- // NORMAL_IN_BUFFER (1), COLOR_IN_BUFFER (2), ALPHA_IN_BUFFER (4).
- private int dataPresent ;
-
- // List for accumulating the output of the decompressor and converting to
- // GeometryArray representations.
- private GeneralizedVertexList vlist ;
-
- // Accumulates Shape3D objects constructed from decompressor output.
- private ArrayList shapes ;
-
- // Decompressor output state variables.
- private Color4f curColor ;
- private Vector3f curNormal ;
-
- // Variables for gathering statistics.
- private int origVertexCount ;
- private int stripCount ;
- private int vertexCount ;
- private int triangleCount ;
- private long startTime ;
- private long endTime ;
-
- // Triangle array type to construct.
- private int triOutputType ;
-
- // Types of triangle output available.
- private static final int TRI_SET = 0 ;
- private static final int TRI_STRIP_SET = 1 ;
- private static final int TRI_STRIP_AND_FAN_SET = 2 ;
- private static final int TRI_STRIP_AND_TRI_SET = 3 ;
-
- // Private convenience copies of various constants.
- private static final int TYPE_POINT =
- CompressedGeometryRetained.TYPE_POINT ;
- private static final int TYPE_LINE =
- CompressedGeometryRetained.TYPE_LINE ;
- private static final int TYPE_TRIANGLE =
- CompressedGeometryRetained.TYPE_TRIANGLE ;
- private static final int FRONTFACE_CCW =
- GeneralizedStripFlags.FRONTFACE_CCW ;
-
- /**
- * Decompress the given compressed geometry.
- * @param cgr CompressedGeometryRetained object with compressed geometry
- * @return an array of Shape3D with TriangleArray geometry if compressed
- * data contains triangles; otherwise, Shape3D array containing PointArray
- * or LineStripArray geometry
- * @see CompressedGeometry
- * @see GeometryDecompressor
- */
- Shape3D[] toTriangleArrays(CompressedGeometryRetained cgr) {
- return decompress(cgr, TRI_SET) ;
- }
-
-
- /**
- * Decompress the given compressed geometry.
- * @param cgr CompressedGeometryRetained object with compressed geometry
- * @return an array of Shape3D with TriangleStripArray geometry if
- * compressed data contains triangles; otherwise, Shape3D array containing
- * PointArray or LineStripArray geometry
- * @see CompressedGeometry
- * @see GeometryDecompressor
- */
- Shape3D[] toTriangleStripArrays(CompressedGeometryRetained cgr) {
- return decompress(cgr, TRI_STRIP_SET) ;
- }
-
-
- /**
- * Decompress the given compressed geometry.
- * @param cgr CompressedGeometryRetained object with compressed geometry
- * @return an array of Shape3D with TriangleStripArray and
- * TriangleFanArray geometry if compressed data contains triangles;
- * otherwise, Shape3D array containing PointArray or LineStripArray
- * geometry
- * @see CompressedGeometry
- * @see GeometryDecompressor
- */
- Shape3D[] toStripAndFanArrays(CompressedGeometryRetained cgr) {
- return decompress(cgr, TRI_STRIP_AND_FAN_SET) ;
- }
-
-
- /**
- * Decompress the given compressed geometry.
- * @param cgr CompressedGeometryRetained object with compressed geometry
- * @return an array of Shape3D with TriangleStripArray and
- * TriangleArray geometry if compressed data contains triangles;
- * otherwise, Shape3D array containing PointArray or LineStripArray
- * geometry
- * @see CompressedGeometry
- * @see GeometryDecompressor
- */
- Shape3D[] toStripAndTriangleArrays(CompressedGeometryRetained cgr) {
- return decompress(cgr, TRI_STRIP_AND_TRI_SET) ;
- }
-
- /**
- * Decompress the data contained in a CompressedGeometryRetained and
- * return an array of Shape3D objects using the specified triangle output
- * type. The triangle output type is ignored if the compressed data
- * contains points or lines.
- */
- private Shape3D[] decompress(CompressedGeometryRetained cgr,
- int triOutputType) {
-
- if (! checkVersion(cgr.majorVersionNumber, cgr.minorVersionNumber)) {
- return null ;
- }
-
- vlist = null ;
- curColor = null ;
- curNormal = null ;
-
- // Get descriptors for compressed data.
- bufferDataType = cgr.bufferType ;
- dataPresent = cgr.bufferContents ;
- if (printInfo) beginPrint() ;
-
- // Initialize the decompressor backend.
- this.triOutputType = triOutputType ;
- shapes = new ArrayList() ;
-
- // Call the superclass decompress() method which calls the output
- // methods of this subclass. The results are stored in vlist.
- super.decompress(cgr.offset, cgr.size, cgr.compressedGeometry) ;
-
- // Convert the decompressor output to Shape3D objects.
- addShape3D() ;
- if (printInfo) endPrint() ;
-
- // Return the fixed-length output array.
- Shape3D shapeArray[] = new Shape3D[shapes.size()] ;
- return (Shape3D[])shapes.toArray(shapeArray) ;
- }
-
- /**
- * Initialize the vertex output list based on the vertex format provided
- * by the SetState decompression command.
- */
- @Override
- void outputVertexFormat(boolean bundlingNorm, boolean bundlingColor,
- boolean doingAlpha) {
-
- if (vlist != null)
- // Construct shapes using the current vertex format.
- addShape3D() ;
-
- int vertexFormat = GeometryArray.COORDINATES ;
-
- if (bundlingNorm) {
- vertexFormat |= GeometryArray.NORMALS ;
- }
-
- if (bundlingColor) {
- if (doingAlpha) {
- vertexFormat |= GeometryArray.COLOR_4;
- } else {
- vertexFormat |= GeometryArray.COLOR_3;
- }
- }
-
- vlist = new GeneralizedVertexList(vertexFormat, FRONTFACE_CCW) ;
- }
-
- /**
- * Add a new decompressed vertex to the current list.
- */
- @Override
- void outputVertex(Point3f position, Vector3f normal,
- Color4f color, int vertexReplaceCode) {
-
- if (curNormal != null) normal = curNormal ;
- vlist.addVertex(position, normal, color, vertexReplaceCode) ;
-
- if (debug) {
- System.out.println(" outputVertex: flag " + vertexReplaceCode) ;
- System.out.println(" position " + position.toString()) ;
- if (normal != null)
- System.out.println(" normal " + normal.toString()) ;
- if (color != null)
- System.out.println(" color " + color.toString()) ;
- }
- }
-
- /**
- * Create a Shape3D using the current color for both the ambient and
- * diffuse material colors, then start a new vertex list for the new
- * color. The outputColor() method is never called if colors are bundled
- * with each vertex in the compressed buffer.
- */
- @Override
- void outputColor(Color4f color) {
- if (debug) System.out.println(" outputColor: " + color.toString()) ;
-
- if (vlist.size() > 0) {
- // Construct Shape3D using the current color.
- addShape3D() ;
-
- // Start a new vertex list for the new color.
- vlist = new GeneralizedVertexList(vlist.vertexFormat,
- FRONTFACE_CCW) ;
- }
- if (curColor == null) curColor = new Color4f() ;
- curColor.set(color) ;
- }
-
- /**
- * Set the current normal that will be copied to each succeeding vertex
- * output by the decompressor. The per-vertex copy is needed since in
- * Java 3D a normal is always associated with a vertex. This method is
- * never called if normals are bundled with each vertex in the compressed
- * buffer.
- */
- @Override
- void outputNormal(Vector3f normal) {
- if (debug) System.out.println(" outputNormal: " + normal.toString()) ;
-
- if ((vlist.vertexFormat & GeometryArray.NORMALS) == 0) {
- if (vlist.size() > 0)
- // Construct Shape3D using the current vertex format.
- addShape3D() ;
-
- // Start a new vertex list with the new format.
- vlist = new GeneralizedVertexList
- (vlist.vertexFormat|GeometryArray.NORMALS, FRONTFACE_CCW) ;
- }
- if (curNormal == null) curNormal = new Vector3f() ;
- curNormal.set(normal) ;
- }
-
- /**
- * Create a Shape3D object of the desired type from the current vertex
- * list. Apply the current color, if non-null, as a Material attribute.
- */
- private void addShape3D() {
- Material m = new Material() ;
-
- if (curColor != null) {
- if ((vlist.vertexFormat & GeometryArray.COLOR_4) != GeometryArray.COLOR_4) {
- m.setAmbientColor(curColor.x, curColor.y, curColor.z) ;
- m.setDiffuseColor(curColor.x, curColor.y, curColor.z) ;
- }
- else {
- m.setAmbientColor(curColor.x, curColor.y, curColor.z) ;
- m.setDiffuseColor(curColor.x, curColor.y, curColor.z,
- curColor.w) ;
- }
- }
-
- if ((vlist.vertexFormat & GeometryArray.NORMALS) == 0)
- m.setLightingEnable(false) ;
- else
- m.setLightingEnable(true) ;
-
- Appearance a = new Appearance() ;
- a.setMaterial(m) ;
-
- switch(bufferDataType) {
- case TYPE_TRIANGLE:
- switch(triOutputType) {
- case TRI_SET:
- TriangleArray ta = vlist.toTriangleArray() ;
- if (ta != null)
- shapes.add(new Shape3D(ta, a)) ;
- break ;
- case TRI_STRIP_SET:
- TriangleStripArray tsa = vlist.toTriangleStripArray() ;
- if (tsa != null)
- shapes.add(new Shape3D(tsa, a)) ;
- break ;
- case TRI_STRIP_AND_FAN_SET:
- GeometryStripArray gsa[] = vlist.toStripAndFanArrays() ;
- if (gsa[0] != null)
- shapes.add(new Shape3D(gsa[0], a)) ;
- if (gsa[1] != null)
- shapes.add(new Shape3D(gsa[1], a)) ;
- break ;
- case TRI_STRIP_AND_TRI_SET:
- GeometryArray ga[] = vlist.toStripAndTriangleArrays() ;
- if (ga[0] != null)
- shapes.add(new Shape3D(ga[0], a)) ;
- if (ga[1] != null)
- shapes.add(new Shape3D(ga[1], a)) ;
- break ;
- default:
- throw new IllegalArgumentException
- (J3dUtilsI18N.getString("GeometryDecompressorShape3D0")) ;
- }
- break ;
-
- case TYPE_LINE:
- LineStripArray lsa = vlist.toLineStripArray() ;
- if (lsa != null)
- shapes.add(new Shape3D(lsa, a)) ;
- break ;
-
- case TYPE_POINT:
- PointArray pa = vlist.toPointArray() ;
- if (pa != null)
- shapes.add(new Shape3D(pa, a)) ;
- break ;
-
- default:
- throw new IllegalArgumentException
- (J3dUtilsI18N.getString("GeometryDecompressorShape3D1")) ;
- }
-
- if (benchmark || statistics) {
- origVertexCount += vlist.size() ;
- vertexCount += vlist.vertexCount ;
- stripCount += vlist.stripCount ;
- triangleCount += vlist.triangleCount ;
- }
- }
-
- private void beginPrint() {
- System.out.println("\nGeometryDecompressorShape3D") ;
-
- switch(bufferDataType) {
- case TYPE_TRIANGLE:
- System.out.println(" buffer TYPE_TRIANGLE") ;
- break ;
- case TYPE_LINE:
- System.out.println(" buffer TYPE_LINE") ;
- break ;
- case TYPE_POINT:
- System.out.println(" buffer TYPE_POINT") ;
- break ;
- default:
- throw new IllegalArgumentException
- (J3dUtilsI18N.getString("GeometryDecompressorShape3D1")) ;
- }
-
- System.out.print(" buffer data present: coords") ;
-
- if ((dataPresent & CompressedGeometryData.Header.NORMAL_IN_BUFFER) != 0)
- System.out.print(" normals") ;
- if ((dataPresent & CompressedGeometryData.Header.COLOR_IN_BUFFER) != 0)
- System.out.print(" colors") ;
- if ((dataPresent & CompressedGeometryData.Header.ALPHA_IN_BUFFER) != 0)
- System.out.print(" alpha") ;
-
- System.out.println() ;
-
- stripCount = 0 ;
- vertexCount = 0 ;
- triangleCount = 0 ;
- origVertexCount = 0 ;
-
- startTime = System.currentTimeMillis() ;
- }
-
- private void endPrint() {
- endTime = System.currentTimeMillis() ;
-
- if (benchmark || statistics)
- printBench() ;
-
- if (statistics)
- printStats() ;
- }
-
- private void printBench() {
- float t = (endTime - startTime) / 1000.0f ;
- System.out.println
- (" decompression + strip conversion took " + t + " sec.") ;
-
- switch(bufferDataType) {
- case TYPE_POINT:
- System.out.println
- (" points decompressed: " + vertexCount + "\n" +
- " net decompression rate: " + (vertexCount/t) +
- " points/sec.\n") ;
- break ;
- case TYPE_LINE:
- System.out.println
- (" lines decompressed: " + (vertexCount - stripCount) + "\n" +
- " net decompression rate: " + ((vertexCount - stripCount)/t) +
- " lines/sec.\n") ;
- break ;
- case TYPE_TRIANGLE:
- System.out.println
- (" triangles decompressed: " +
- (vertexCount - 2*stripCount) + "\n" +
- " net decompression rate: " +
- ((vertexCount - 2*stripCount)/t) + " triangles/sec.\n") ;
- break ;
- }
- }
-
- private void printStats() {
- switch(triOutputType) {
- case TRI_SET:
- System.out.println(" using individual triangle output") ;
- break ;
- case TRI_STRIP_SET:
- System.out.println(" using strip output") ;
- break ;
- case TRI_STRIP_AND_FAN_SET:
- System.out.println(" using strips and fans for output") ;
- break ;
- case TRI_STRIP_AND_TRI_SET:
- System.out.println(" using strips and triangles for output") ;
- break ;
- }
-
- System.out.print
- (" number of Shape3D objects: " + shapes.size() +
- "\n number of Shape3D decompressed vertices: ") ;
-
- if (triOutputType == TRI_SET || bufferDataType == TYPE_POINT) {
- System.out.println(vertexCount) ;
- }
- else if (triOutputType == TRI_STRIP_AND_TRI_SET) {
- System.out.println((vertexCount + triangleCount*3) +
- "\n number of strips: " + stripCount +
- "\n number of individual triangles: " +
- triangleCount) ;
- if (stripCount > 0)
- System.out.println
- (" vertices/strip: " + (float)vertexCount/stripCount +
- "\n triangles represented in strips: " +
- (vertexCount - 2*stripCount)) ;
- }
- else {
- System.out.println(vertexCount +
- "\n number of strips: " + stripCount) ;
- if (stripCount > 0)
- System.out.println
- (" vertices/strip: " + (float)vertexCount/stripCount) ;
- }
-
- System.out.print(" vertex data present in last Shape3D: coords") ;
- if ((vlist.vertexFormat & GeometryArray.NORMALS) != 0)
- System.out.print(" normals") ;
-
- boolean color4 =
- (vlist.vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4;
- boolean color3 = !color4 &&
- (vlist.vertexFormat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3;
- if (color3 || color4) {
- System.out.print(" colors") ;
- if (color4)
- System.out.print(" alpha") ;
- }
- System.out.println() ;
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanNode.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanNode.java
deleted file mode 100644
index b0f16b5..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanNode.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import java.util.Collection;
-import java.util.Comparator;
-
-/**
- * Instances of this class are used as the nodes of binary trees representing
- * mappings of tags to compression stream elements. Tags are descriptors
- * inserted into the compression command stream that specify the encoding of
- * immediately succeeding data elements.
- *
- * The tag assignments in such a tree are computed from the paths taken from
- * the root to the leaf nodes. Each leaf node represents the particular way
- * one or more compression stream elements wound up being encoded with respect
- * to various combinations of data lengths, shifts, and absolute/relative
- * status.
- *
- * Huffman's algorithm for constructing binary trees with minimal weighted
- * path lengths can be used to optimize the bit lengths of the tags with
- * respect to the frequency of occurrence of their associated data encodings
- * in the compression stream. The weighted path length is the sum of the
- * frequencies of all the leaf nodes times their path lengths to the root of
- * the tree.
- *
- * The length of the longest tag determines the size of the table mapping tags
- * to data representations. The geometry compression specification limits the
- * size of the table to 64 entries, so tags cannot be longer than 6 bits. The
- * depth of the tree is reduced through a process of increasing the data
- * lengths of less frequently occuring nodes so they can be merged with other
- * more frequent nodes.
- */
-class HuffmanNode {
- int tag, tagLength ;
- int shift, dataLength ;
- boolean absolute ;
-
- private int frequency ;
- private HuffmanNode child0, child1, mergeNode ;
- private boolean merged, unmergeable, cleared ;
-
- void clear() {
- tag = -1 ;
- tagLength = -1 ;
-
- shift = -1 ;
- dataLength = -1 ;
- absolute = false ;
-
- child0 = null ;
- child1 = null ;
- mergeNode = null ;
-
- frequency = 0 ;
- merged = false ;
- unmergeable = false ;
- cleared = true ;
- }
-
- HuffmanNode() {
- clear() ;
- }
-
- HuffmanNode(int length, int shift, boolean absolute) {
- this() ;
- set(length, shift, absolute) ;
- }
-
- final void set(int length, int shift, boolean absolute) {
- this.dataLength = length ;
- this.shift = shift ;
- this.absolute = absolute ;
- this.cleared = false ;
- }
-
- final boolean cleared() {
- return cleared ;
- }
-
- final void addCount() {
- frequency++ ;
- }
-
- final boolean hasCount() {
- return frequency > 0 ;
- }
-
- final boolean tokenEquals(HuffmanNode node) {
- return
- this.absolute == node.absolute &&
- this.dataLength == node.dataLength &&
- this.shift == node.shift ;
- }
-
- void addChildren(HuffmanNode child0, HuffmanNode child1) {
- this.child0 = child0 ;
- this.child1 = child1 ;
- this.frequency = child0.frequency + child1.frequency ;
- }
-
- void collectLeaves(int tag, int tagLength, Collection collection) {
- if (child0 == null) {
- this.tag = tag ;
- this.tagLength = tagLength ;
- collection.add(this) ;
- } else {
- child0.collectLeaves((tag << 1) | 0, tagLength + 1, collection) ;
- child1.collectLeaves((tag << 1) | 1, tagLength + 1, collection) ;
- }
- }
-
- boolean mergeInto(HuffmanNode node) {
- if (this.absolute == node.absolute) {
- if (this.dataLength > node.dataLength)
- node.dataLength = this.dataLength ;
-
- if (this.shift < node.shift)
- node.shift = this.shift ;
-
- node.frequency += this.frequency ;
- this.mergeNode = node ;
- this.merged = true ;
- return true ;
-
- } else
- return false ;
- }
-
- int incrementLength() {
- if (shift > 0)
- shift-- ;
- else
- dataLength++ ;
-
- return dataLength - shift ;
- }
-
- final boolean merged() {
- return merged ;
- }
-
- final HuffmanNode getMergeNode() {
- return mergeNode ;
- }
-
- void setUnmergeable() {
- unmergeable = true ;
- }
-
- final boolean unmergeable() {
- return unmergeable ;
- }
-
- @Override
- public String toString() {
- return
- "shift " + shift + " data length " + dataLength +
- (absolute? " absolute " : " relative ") +
- "\ntag 0x" + Integer.toHexString(tag) + " tag length " + tagLength +
- "\nfrequency: " + frequency ;
- }
-
- /**
- * Sorts nodes in ascending order by frequency.
- */
- static class FrequencyComparator implements Comparator {
- @Override
- public final int compare(Object o1, Object o2) {
- return ((HuffmanNode)o1).frequency - ((HuffmanNode)o2).frequency ;
- }
- }
-
- /**
- * Sorts nodes in descending order by tag bit length.
- */
- static class TagLengthComparator implements Comparator {
- @Override
- public final int compare(Object o1, Object o2) {
- return ((HuffmanNode)o2).tagLength - ((HuffmanNode)o1).tagLength ;
- }
- }
-
- static FrequencyComparator frequencyComparator = new FrequencyComparator() ;
- static TagLengthComparator tagLengthComparator = new TagLengthComparator() ;
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanTable.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanTable.java
deleted file mode 100644
index f874e5a..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/HuffmanTable.java
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.ListIterator;
-
-/**
- * This class maintains a map from compression stream elements (tokens) onto
- * HuffmanNode objects. A HuffmanNode contains a tag describing the
- * associated token's data length, right shift value, and absolute/relative
- * status.
- *
- * The tags are computed using Huffman's algorithm to build a binary tree with
- * a minimal total weighted path length. The frequency of each token is
- * used as its node's weight when building the tree. The path length from the
- * root to the token's node then indicates the bit length that should be used
- * for that token's tag in order to minimize the total size of the compressed
- * stream.
- */
-class HuffmanTable {
- private static final int MAX_TAG_LENGTH = 6 ;
-
- private HuffmanNode positions[] ;
- private HuffmanNode normals[] ;
- private HuffmanNode colors[] ;
-
- /**
- * Create a new HuffmanTable with entries for all possible position,
- * normal, and color tokens.
- */
- HuffmanTable() {
- //
- // Position and color components can have data lengths up to 16
- // bits, with right shifts up to 15 bits. The position and color
- // lookup tables are therefore 2*17*16=544 entries in length to
- // account for all possible combinations of data lengths, shifts,
- // and relative or absolute status.
- //
- colors = new HuffmanNode[544] ;
- positions = new HuffmanNode[544] ;
-
- //
- // Delta normals can have uv components up to 7 bits in length with
- // right shifts up to 6 bits. Absolute normals can have uv components
- // up to 6 bits in length with right shifts up to 5 bits. The normal
- // lookup table is therefore 2*8*7=112 entries in length.
- //
- normals = new HuffmanNode[112] ;
- }
-
- private final int getPositionIndex(int len, int shift, boolean absolute) {
- return (absolute? 1:0)*272 + len*16 + shift ;
- }
-
- private final int getNormalIndex(int length, int shift, boolean absolute) {
- return (absolute? 1:0)*56 + length*7 + shift ;
- }
-
- private final int getColorIndex(int length, int shift, boolean absolute) {
- return getPositionIndex(length, shift, absolute) ;
- }
-
-
- /**
- * Add a position entry with the given length, shift, and absolute
- * status.
- *
- * @param length number of bits in each X, Y, and Z component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous vertex in the compression stream
- */
- void addPositionEntry(int length, int shift, boolean absolute) {
- addEntry(positions, getPositionIndex(length, shift, absolute),
- length, shift, absolute) ;
- }
-
- /**
- * Get the position entry associated with the specified length, shift, and
- * absolute status. This will contain a tag indicating the actual
- * encoding to be used in the compression command stream, not necessarily
- * the same as the original length and shift with which the the entry was
- * created.
- *
- * @param length number of bits in each X, Y, and Z component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous vertex in the compression stream
- * @return HuffmanNode mapped to the specified parameters
- */
- HuffmanNode getPositionEntry(int length, int shift, boolean absolute) {
- return getEntry(positions, getPositionIndex(length, shift, absolute)) ;
- }
-
- /**
- * Add a color entry with the given length, shift, and absolute
- * status.
- *
- * @param length number of bits in each R, G, B, and A component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous color in the compression stream
- */
- void addColorEntry(int length, int shift, boolean absolute) {
- addEntry(colors, getColorIndex(length, shift, absolute),
- length, shift, absolute) ;
- }
-
- /**
- * Get the color entry associated with the specified length, shift, and
- * absolute status. This will contain a tag indicating the actual
- * encoding to be used in the compression command stream, not necessarily
- * the same as the original length and shift with which the the entry was
- * created.
- *
- * @param length number of bits in each R, G, B, and A component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous color in the compression stream
- * @return HuffmanNode mapped to the specified parameters
- */
- HuffmanNode getColorEntry(int length, int shift, boolean absolute) {
- return getEntry(colors, getColorIndex(length, shift, absolute)) ;
- }
-
- /**
- * Add a normal entry with the given length, shift, and absolute
- * status.
- *
- * @param length number of bits in each U and V component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous normal in the compression stream
- */
- void addNormalEntry(int length, int shift, boolean absolute) {
- addEntry(normals, getNormalIndex(length, shift, absolute),
- length, shift, absolute) ;
- }
-
- /**
- * Get the normal entry associated with the specified length, shift, and
- * absolute status. This will contain a tag indicating the actual
- * encoding to be used in the compression command stream, not necessarily
- * the same as the original length and shift with which the the entry was
- * created.
- *
- * @param length number of bits in each U and V component
- * @param shift number of trailing zeros in each component
- * @param absolute if false, value represented is a delta from the
- * previous normal in the compression stream
- * @return HuffmanNode mapped to the specified parameters
- */
- HuffmanNode getNormalEntry(int length, int shift, boolean absolute) {
- return getEntry(normals, getNormalIndex(length, shift, absolute)) ;
- }
-
-
- private void addEntry(HuffmanNode table[], int index,
- int length, int shift, boolean absolute) {
-
- if (table[index] == null)
- table[index] = new HuffmanNode(length, shift, absolute) ;
-
- else if (table[index].cleared())
- table[index].set(length, shift, absolute) ;
-
- table[index].addCount() ;
- }
-
- private HuffmanNode getEntry(HuffmanNode table[], int index) {
- HuffmanNode t = table[index] ;
-
- while (t.merged())
- t = t.getMergeNode() ;
-
- return t ;
- }
-
- private void getEntries(HuffmanNode table[], Collection c) {
- for (int i = 0 ; i < table.length ; i++)
- if (table[i] != null && !table[i].cleared() &&
- table[i].hasCount() && !table[i].merged())
- c.add(table[i]) ;
- }
-
-
- /**
- * Clear this HuffmanTable instance.
- */
- void clear() {
- for (int i = 0 ; i < positions.length ; i++)
- if (positions[i] != null)
- positions[i].clear() ;
-
- for (int i = 0 ; i < colors.length ; i++)
- if (colors[i] != null)
- colors[i].clear() ;
-
- for (int i = 0 ; i < normals.length ; i++)
- if (normals[i] != null)
- normals[i].clear() ;
- }
-
- /**
- * Compute optimized tags for each position, color, and normal entry.
- */
- void computeTags() {
- LinkedList nodeList = new LinkedList() ;
- getEntries(positions, nodeList) ;
- computeTags(nodeList, 3) ;
-
- nodeList.clear() ;
- getEntries(colors, nodeList) ;
- computeTags(nodeList, 3) ;
-
- nodeList.clear() ;
- getEntries(normals, nodeList) ;
- computeTags(nodeList, 2) ;
- }
-
- //
- // Compute tags for a list of Huffman tokens.
- //
- private void computeTags(LinkedList nodes, int minComponentCount) {
- HuffmanNode node0, node1, node2 ;
-
- // Return if there's nothing to do.
- if (nodes.isEmpty())
- return ;
-
- while (true) {
- // Sort the nodes in ascending order by frequency.
- Collections.sort(nodes, HuffmanNode.frequencyComparator) ;
-
- // Apply Huffman's algorithm to construct a binary tree with a
- // minimum total weighted path length.
- node0 = (HuffmanNode)nodes.removeFirst() ;
- while (nodes.size() > 0) {
- node1 = (HuffmanNode)nodes.removeFirst() ;
- node2 = new HuffmanNode() ;
-
- node2.addChildren(node0, node1) ;
- addNodeInOrder(nodes, node2, HuffmanNode.frequencyComparator) ;
-
- node0 = (HuffmanNode)nodes.removeFirst() ;
- }
-
- // node0 is the root of the resulting binary tree. Traverse it
- // assigning tags and lengths to the leaf nodes. The leaves are
- // collected into the now empty node list.
- node0.collectLeaves(0, 0, nodes) ;
-
- // Sort the nodes in descending order by tag length.
- Collections.sort(nodes, HuffmanNode.tagLengthComparator) ;
-
- // Check for tag length overrun.
- if (((HuffmanNode)nodes.getFirst()).tagLength > MAX_TAG_LENGTH) {
- // Tokens need to be merged and the tree rebuilt with the new
- // combined frequencies.
- merge(nodes) ;
-
- } else {
- // Increase tag length + data length if they're too small.
- expand(nodes, minComponentCount) ;
- break ;
- }
- }
- }
-
- //
- // Merge a token with a long tag into some other token. The merged token
- // will be removed from the list along with any duplicate node the merge
- // created, reducing the size of the list by 1 or 2 elements until only
- // unmergeable tokens are left.
- //
- private void merge(LinkedList nodes) {
- ListIterator i = nodes.listIterator(0) ;
- HuffmanNode node0, node1, node2 ;
- int index = 0 ;
-
- while (i.hasNext()) {
- // Get the node with the longest possibly mergeable tag.
- node0 = (HuffmanNode)i.next() ;
- if (node0.unmergeable()) continue ;
-
- // Try to find a node that can be merged with node0. This is any
- // node that matches its absolute/relative status.
- i.remove() ;
- while (i.hasNext()) {
- node1 = (HuffmanNode)i.next() ;
- if (node0.mergeInto(node1)) {
- // Search for a duplicate of the possibly modified node1
- // and merge into it so that node weights remain valid.
- // If a duplicate exists it must be further in the list,
- // otherwise node0 would have merged into it.
- i.remove() ;
- while (i.hasNext()) {
- node2 = (HuffmanNode)i.next() ;
- if (node1.tokenEquals(node2)) {
- node1.mergeInto(node2) ;
- return ;
- }
- }
- // node1 has no duplicate, so return it to the list.
- i.add(node1) ;
- return ;
- }
- }
-
- // node0 can't be merged with any other node; it must be the only
- // relative or absolute node in the list. Mark it as unmergeable
- // to avoid unnecessary searches on subsequent calls to merge()
- // and return it to the list.
- node0.setUnmergeable() ;
- i.add(node0) ;
-
- // Restart the iteration.
- i = nodes.listIterator(0) ;
- }
- }
-
- //
- // Empty bits within a compression command header are not allowed. If
- // the tag length plus the total data length is less than 6 bits then
- // the token's length must be increased.
- //
- private void expand(LinkedList nodes, int minComponentCount) {
- Iterator i = nodes.iterator() ;
-
- while (i.hasNext()) {
- HuffmanNode n = (HuffmanNode)i.next() ;
-
- while (n.tagLength +
- (minComponentCount * (n.dataLength - n.shift)) < 6) {
-
- n.incrementLength() ;
- }
- }
- }
-
- //
- // Insert a node into the correct place in a sorted list of nodes.
- //
- private void addNodeInOrder(LinkedList l, HuffmanNode node, Comparator c) {
- ListIterator i = l.listIterator(0) ;
-
- while (i.hasNext()) {
- HuffmanNode n = (HuffmanNode)i.next() ;
- if (c.compare(n, node) > 0) {
- n = (HuffmanNode)i.previous() ;
- break ;
- }
- }
- i.add(node) ;
- }
-
- /**
- * Create compression stream commands for decompressors to use to set up
- * their decompression tables.
- *
- * @param output CommandStream which receives the compression commands
- */
- void outputCommands(CommandStream output) {
- LinkedList nodeList = new LinkedList() ;
- getEntries(positions, nodeList) ;
- outputCommands(nodeList, output, CommandStream.POSITION_TABLE) ;
-
- nodeList.clear() ;
- getEntries(colors, nodeList) ;
- outputCommands(nodeList, output, CommandStream.COLOR_TABLE) ;
-
- nodeList.clear() ;
- getEntries(normals, nodeList) ;
- outputCommands(nodeList, output, CommandStream.NORMAL_TABLE) ;
- }
-
- //
- // Output a setTable command for each unique token.
- //
- private void outputCommands(Collection nodes,
- CommandStream output, int tableId) {
-
- Iterator i = nodes.iterator() ;
- while (i.hasNext()) {
- HuffmanNode n = (HuffmanNode)i.next() ;
- int addressRange = (1 << n.tagLength) | n.tag ;
- int dataLength = (n.dataLength == 16? 0 : n.dataLength) ;
-
- int command =
- CommandStream.SET_TABLE | (tableId << 1) | (addressRange >> 6) ;
-
- long body =
- ((addressRange & 0x3f) << 9) | (dataLength << 5) |
- (n.absolute? 0x10 : 0) | n.shift ;
-
- output.addCommand(command, 8, body, 15) ;
- }
- }
-
- /**
- * Print a collection of HuffmanNode objects to standard out.
- *
- * @param header descriptive string
- * @param nodes Collection of HuffmanNode objects to print
- */
- void print(String header, Collection nodes) {
- System.out.println(header + "\nentries: " + nodes.size() + "\n") ;
-
- Iterator i = nodes.iterator() ;
- while(i.hasNext()) {
- HuffmanNode n = (HuffmanNode)i.next() ;
- System.out.println(n.toString() + "\n") ;
- }
- }
-
- /**
- * Print the contents of this instance to standard out.
- */
- void print() {
- LinkedList nodeList = new LinkedList() ;
-
- getEntries(positions, nodeList) ;
- Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
- print("\nposition tokens and tags", nodeList) ;
-
- nodeList.clear() ;
- getEntries(colors, nodeList) ;
- Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
- print("\ncolor tokens and tags", nodeList) ;
-
- nodeList.clear() ;
- getEntries(normals, nodeList) ;
- Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
- print("\nnormal tokens and tags", nodeList) ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/MeshBuffer.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/MeshBuffer.java
deleted file mode 100644
index 0c2ab94..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/MeshBuffer.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3f;
-
-/**
- * This class mirrors the vertex mesh buffer stack supported by the geometry
- * compression semantics.
- */
-class MeshBuffer {
- //
- // The fixed-length mesh buffer stack is represented by circular buffers.
- // Three stack representations are provided: vertices, positions, and
- // indices.
- //
- // The vertex representation stores references to CompressionStreamVertex
- // objects. The position representation stores references to Point3f,
- // Vector3f, Color3f, and Color4f objects, while the index representation
- // stores indices into externally maintained arrays of those objects. All
- // these representations may be used independently and all provide access
- // to the stored references via a mesh buffer index.
- //
- // In addition, the position and index representations provide lookup
- // mechanisms to check if positions or indices exist in the mesh buffer
- // and return their mesh buffer indices if they do. This is used to
- // implement a limited meshing algorithm which reduces the number of
- // vertices when non-stripped abutting facets are added to a compression
- // stream.
- //
- static final int NOT_FOUND = -1 ;
-
- private static final int SIZE = 16 ;
- private static final int NAN_HASH =
- new Point3f(Float.NaN, Float.NaN, Float.NaN).hashCode() ;
-
- private int topIndex = SIZE - 1 ;
- private int positionIndices[] = new int[SIZE] ;
- private int normalIndices[] = new int[SIZE] ;
- private int colorIndices[] = new int[SIZE] ;
-
- private int topPosition = SIZE - 1 ;
- private int positionHashCodes[] = new int[SIZE] ;
- private Point3f positions[] = new Point3f[SIZE] ;
- private Vector3f normals[] = new Vector3f[SIZE] ;
- private Color3f colors3[] = new Color3f[SIZE] ;
- private Color4f colors4[] = new Color4f[SIZE] ;
-
- private int topVertex = SIZE - 1 ;
- private CompressionStreamVertex vertices[] =
- new CompressionStreamVertex[SIZE] ;
-
- MeshBuffer() {
- for (int i = 0 ; i < SIZE ; i++) {
- positionHashCodes[i] = NAN_HASH ;
-
- positionIndices[i] = NOT_FOUND ;
- normalIndices[i] = NOT_FOUND ;
- colorIndices[i] = NOT_FOUND ;
- }
- }
-
- private static int nextTop(int top) {
- // The stack top references an element in the fixed-length backing
- // array in which the stack is stored. Stack elements below it have
- // decreasing indices into the backing array until element 0, at which
- // point the indices wrap to the end of the backing array and back to
- // the top.
- //
- // A push is accomplished by incrementing the stack top in a circular
- // buffer and storing the data into the new stack element it
- // references. The bottom of the stack is the element with the next
- // higher index from the top in the backing array, and is overwritten
- // with each new push.
- return (top + 1) % SIZE ;
- }
-
- private static int flipOffset(int top, int offset) {
- // Flips an offset relative to the beginning of the backing array to
- // an offset from the top of the stack. Also works in reverse, from
- // an offset from the top of the stack to an offset from the beginning
- // of the backing array.
- if (offset > top) offset -= SIZE ;
- return top - offset ;
- }
-
- //
- // Mesh buffer vertex stack. This is currently only used for vertex
- // lookup during the quantization pass in order to compute delta values;
- // no mesh reference lookup is necessary.
- //
- void push(CompressionStreamVertex v) {
- topVertex = nextTop(topVertex) ;
- vertices[topVertex] = v ;
- }
-
- CompressionStreamVertex getVertex(int meshReference) {
- return vertices[flipOffset(topVertex, meshReference)] ;
- }
-
-
- //
- // Mesh buffer index stack and index reference lookup support.
- //
- void push(int positionIndex, int normalIndex) {
- topIndex = nextTop(topIndex) ;
-
- positionIndices[topIndex] = positionIndex ;
- normalIndices[topIndex] = normalIndex ;
- }
-
- void push(int positionIndex, int colorIndex, int normalIndex) {
- push(positionIndex, normalIndex) ;
- colorIndices[topIndex] = colorIndex ;
- }
-
- int getMeshReference(int positionIndex) {
- int index ;
- for (index = 0 ; index < SIZE ; index++)
- if (positionIndices[index] == positionIndex)
- break ;
-
- if (index == SIZE) return NOT_FOUND ;
- return flipOffset(topIndex, index) ;
- }
-
- int getPositionIndex(int meshReference) {
- return positionIndices[flipOffset(topIndex, meshReference)] ;
- }
-
- int getColorIndex(int meshReference) {
- return colorIndices[flipOffset(topIndex, meshReference)] ;
- }
-
- int getNormalIndex(int meshReference) {
- return normalIndices[flipOffset(topIndex, meshReference)] ;
- }
-
-
- //
- // Mesh buffer position stack and position reference lookup support.
- //
- void push(Point3f position, Vector3f normal) {
- topPosition = nextTop(topPosition) ;
-
- positionHashCodes[topPosition] = position.hashCode() ;
- positions[topPosition] = position ;
- normals[topPosition] = normal ;
- }
-
- void push(Point3f position, Color3f color, Vector3f normal) {
- push(position, normal) ;
- colors3[topPosition] = color ;
- }
-
- void push(Point3f position, Color4f color, Vector3f normal) {
- push(position, normal) ;
- colors4[topPosition] = color ;
- }
-
- void push(Point3f position, Object color, Vector3f normal) {
- push(position, normal) ;
- if (color instanceof Color3f)
- colors3[topPosition] = (Color3f)color ;
- else
- colors4[topPosition] = (Color4f)color ;
- }
-
- int getMeshReference(Point3f position) {
- int index ;
- int hashCode = position.hashCode() ;
-
- for (index = 0 ; index < SIZE ; index++)
- if (positionHashCodes[index] == hashCode)
- if (positions[index].equals(position))
- break ;
-
- if (index == SIZE) return NOT_FOUND ;
- return flipOffset(topPosition, index) ;
- }
-
- Point3f getPosition(int meshReference) {
- return positions[flipOffset(topPosition, meshReference)] ;
- }
-
- Color3f getColor3(int meshReference) {
- return colors3[flipOffset(topPosition, meshReference)] ;
- }
-
- Color4f getColor4(int meshReference) {
- return colors4[flipOffset(topPosition, meshReference)] ;
- }
-
- Vector3f getNormal(int meshReference) {
- return normals[flipOffset(topPosition, meshReference)] ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/package.html b/src/classes/share/com/sun/j3d/utils/geometry/compression/package.html
deleted file mode 100644
index 2977b07..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/package.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
- Provides compressed geometry utility classes.
- This package supersedes the javax.media.j3d.CompressedGeometry class and
- the com.sun.j3d.utils.compression package. Provides geometry construction, triangulation, and optimization
-utility classes.
- * Note that non-power-of-two textures may not be supported by all graphics
- * cards. Applications should check whether a particular Canvas3D supports
- * non-power-of-two textures by calling the {@link Canvas3D#queryProperties}
- * method, and checking whether the
- * Provides texture image utility classes.
- * The pick tolerance specifies the distance from the
- * pick center to include in the pick shape. A tolerance of 0.0 may speedup
- * picking slightly, but also make it very difficult to pick points and lines.
- *
- * The pick canvas can be used to make a series of picks. For example, to
- * initialize the pick canvas:
- *
- * Then for each mouse event:
- *
- * NOTE: For the pickAllSorted or pickClosest methods, the picks will be sorted
- * by the distance from the ViewPlatform to the intersection point.
- * @see PickTool
- */
-public class PickCanvas extends PickTool {
-
- /* OPEN ISSUES:
- -- Should restrict the pick shape to the front/back clip plane
- */
-
-
- /** The canvas we are picking into */
- Canvas3D canvas;
-
- /* the pick tolerance, default to 2.0 */
- float tolerance = 2.0f;
- int save_xpos;
- int save_ypos;
-
- /** Constructor with Canvas3D for mouse events and BranchGroup to be picked.
- */
- public PickCanvas (Canvas3D c, BranchGroup b) {
- super (b);
- canvas = c;
- }
-
- /** Constructor with Canvas3D for mouse events and Locale to be picked.
- */
- public PickCanvas (Canvas3D c, Locale l) {
- super (l);
- canvas = c;
- }
-
- /** Inquire the canvas to be used for picking operations.
- @return the canvas.
- */
- public Canvas3D getCanvas() {
- return canvas;
- }
-
- /** Set the picking tolerance. Objects within this distance
- * (in pixels)
- * to the mouse x,y location will be picked. The default tolerance is 2.0.
- * @param t The tolerance
- * @exception IllegalArgumentException if the tolerance is less than 0.
- */
- public void setTolerance(float t) {
- if (t < 0.0f) {
- throw new IllegalArgumentException();
- }
- tolerance = t;
-
- if ((pickShape != null) && (!userDefineShape)) {
- // reset pickShape
- pickShape = null;
- setShapeLocation(save_xpos, save_ypos);
- }
- }
-
- /** Get the pick tolerance.
- */
- public float getTolerance() {
- return tolerance;
- }
-
- /** Set the pick location. Defines the location on the canvas where the
- pick is to be performed.
- @param mevent The MouseEvent for the picking point
- */
- public void setShapeLocation(MouseEvent mevent) {
- setShapeLocation(mevent.getX(), mevent.getY());
- }
- /** Set the pick location. Defines the location on the canvas where the
- pick is to be performed (upper left corner of canvas is 0,0).
- @param xpos the X position of the picking point
- @param ypos the Y position of the picking point
- */
- public void setShapeLocation (int xpos, int ypos) {
- Transform3D motion = new Transform3D();
- Point3d eyePosn = new Point3d();
- Point3d mousePosn = new Point3d();
- Vector3d mouseVec = new Vector3d();
- boolean isParallel = false;
- double radius = 0.0;
- double spreadAngle = 0.0;
-
- this.save_xpos = xpos;
- this.save_ypos = ypos;
- canvas.getCenterEyeInImagePlate(eyePosn);
- canvas.getPixelLocationInImagePlate(xpos,ypos,mousePosn);
-
- if ((canvas.getView() != null) &&
- (canvas.getView().getProjectionPolicy() ==
- View.PARALLEL_PROJECTION)) {
- // Correct for the parallel projection: keep the eye's z
- // coordinate, but make x,y be the same as the mouse, this
- // simulates the eye being at "infinity"
- eyePosn.x = mousePosn.x;
- eyePosn.y = mousePosn.y;
- isParallel = true;
- }
-
- // Calculate radius for PickCylinderRay and spread angle for PickConeRay
- Vector3d eyeToCanvas = new Vector3d();
- eyeToCanvas.sub (mousePosn, eyePosn);
- double distanceEyeToCanvas = eyeToCanvas.length();
-
- Point3d deltaImgPlate = new Point3d();
- canvas.getPixelLocationInImagePlate (xpos+1, ypos, deltaImgPlate);
-
- Vector3d ptToDelta = new Vector3d();
- ptToDelta.sub (mousePosn, deltaImgPlate);
- double distancePtToDelta = ptToDelta.length();
- distancePtToDelta *= tolerance;
-
- canvas.getImagePlateToVworld(motion);
-
- /*
- System.out.println("mouse position " + xpos + " " + ypos);
- System.out.println("before, mouse " + mousePosn + " eye " + eyePosn);
- */
-
- motion.transform(eyePosn);
- start = new Point3d (eyePosn); // store the eye position
- motion.transform(mousePosn);
- mouseVec.sub(mousePosn, eyePosn);
- mouseVec.normalize();
-
- /*
- System.out.println(motion + "\n");
- System.out.println("after, mouse " + mousePosn + " eye " + eyePosn +
- " mouseVec " + mouseVec);
- */
-
- if (tolerance == 0.0) {
- if ((pickShape != null) && (pickShape instanceof PickRay)) {
- ((PickRay)pickShape).set (eyePosn, mouseVec);
- } else {
- pickShape = (PickShape) new PickRay (eyePosn, mouseVec);
- }
- // pickShape = (PickShape) new PickConeRay (eyePosn,
- // mouseVec,1.0*Math.PI/180.0);
- } else {
- if (isParallel) {
- // Parallel projection, use a PickCylinderRay
- distancePtToDelta *= motion.getScale();
- if ((pickShape != null) &&
- (pickShape instanceof PickCylinderRay)) {
- ((PickCylinderRay)pickShape).set (eyePosn, mouseVec,
- distancePtToDelta);
- } else {
- pickShape = (PickShape) new PickCylinderRay (eyePosn,
- mouseVec, distancePtToDelta);
- }
- } else {
- // Perspective projection, use a PickConeRay
-
- // Calculate spread angle
- spreadAngle = Math.atan (distancePtToDelta/distanceEyeToCanvas);
-
- if ((pickShape != null) &&
- (pickShape instanceof PickConeRay)) {
- ((PickConeRay)pickShape).set (eyePosn, mouseVec,
- spreadAngle);
- } else {
- pickShape = (PickShape) new PickConeRay (eyePosn, mouseVec,
- spreadAngle);
- }
- }
- }
- }
-} // PickCanvas
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/pickfast/PickIntersection.java b/src/classes/share/com/sun/j3d/utils/pickfast/PickIntersection.java
deleted file mode 100644
index 0020956..0000000
--- a/src/classes/share/com/sun/j3d/utils/pickfast/PickIntersection.java
+++ /dev/null
@@ -1,1383 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.pickfast;
-
-import javax.media.j3d.Geometry;
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.IndexedGeometryArray;
-import javax.media.j3d.PickInfo;
-import javax.media.j3d.Transform3D;
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3d;
-import javax.vecmath.TexCoord3f;
-import javax.vecmath.Vector3d;
-import javax.vecmath.Vector3f;
-
-/**
- * Holds information about an intersection of a PickShape with a Node
- * as part of a PickInfo.IntersectionInfo. Information about
- * the intersected geometry, intersected primitive, intersection point, and
- * closest vertex can be inquired.
- *
- * The intersected primitive indicates which primitive out of the GeometryArray
- * was intersected (where the primitive is a point, line, triangle or quad,
- * not a
- *
- * The primitive's VWorld coordinates are saved when then intersection is
- * calculated. The local coordinates, normal, color and texture coordinates
- * for the primitive can also be inquired if they are present and readable.
- *
- * The intersection point is the location on the primitive which intersects the
- * pick shape closest to the center of the pick shape. The intersection point's
- * location in VWorld coordinates is saved when the intersection is calculated.
- * The local coordinates, normal, color and texture coordiantes of at the
- * intersection can be interpolated if they are present and readable.
- *
- * The closest vertex is the vertex of the primitive closest to the intersection
- * point. The vertex index, VWorld coordinates and local coordinates of the
- * closest vertex can be inquired. The normal, color and texture coordinate
- * of the closest vertex can be inquired from the geometry array:
- *
- * The color, normal
- * and texture coordinate information for the intersected primitive and the
- * intersection point
- * can be inquired
- * the geometry includes them and the corresponding READ capibility bits are
- * set.
- */
-
-public class PickIntersection {
-
-
- /* The intersection point */
- // Point3d getIntersectionPoint()
-
- /* Distance between start point of pickShape and intersection point */
- // double getDistance()
-
- /* The vertex indices of the intersected primitive in the geometry */
- // int[] getVertexIndices()
-
- /*************************/
-
- /** Weight factors for interpolation, values correspond to vertex indices,
- * sum == 1
- */
- private double[] interpWeights;
-
- private static final boolean debug = false;
-
- // Axis constants
- private static final int X_AXIS = 1;
- private static final int Y_AXIS = 2;
- private static final int Z_AXIS = 3;
-
- // Tolerance for numerical stability
- static final double TOL = 1.0e-5;
-
- /* The references to the intersectionInfo object */
- private PickInfo.IntersectionInfo iInfo = null;
- private Transform3D l2vw = null;
- private Geometry geometry = null;
- private boolean geometryIsIndexed = false;
- private double distance;
-
- private boolean hasColors;
- private boolean hasNormals;
- private boolean hasTexCoords;
-
- // Primitive
- /* indices for the different data types */
- private int[] primitiveCoordinateIndices;
- private int[] primitiveNormalIndices;
- private int[] primitiveColorIndices;
- private int[] primitiveTexCoordIndices;
-
- /** Indices of the intersected primitive */
- private int[] primitiveVertexIndices = null;
-
- /* Local coordinates of the intersected primitive */
- private Point3d[] primitiveCoordinates = null;
-
- /** VWorld coordinates of intersected primitive */
- private Point3d[] primitiveCoordinatesVW = null;
-
- /* Normals of the intersected primitive */
- private Vector3f[] primitiveNormals = null;
-
- /* Colors of the intersected primitive */
- private Color4f[] primitiveColors = null;
-
- /* TextureCoordinates of the intersected primitive */
- private TexCoord3f[] primitiveTexCoords = null;
-
- // Intersection point
- /** VWorld Coordinates of the intersection point */
- private Point3d pointCoordinatesVW = null;
-
- /** Local Coordinates of the intersection point */
- private Point3d pointCoordinates = null;
-
- /** Normal at the intersection point */
- private Vector3f pointNormal = null;
-
- /** Color at the intersection point */
- private Color4f pointColor = null;
-
- /** TexCoord at the intersection point */
- private TexCoord3f pointTexCoord = null;
-
- // Closest Vertex
- /** Index of the closest vertex */
- private int closestVertexIndex = -1;
-
- /** Coordinates of the closest vertex */
- private Point3d closestVertexCoordinates = null;
-
- /** Coordinates of the closest vertex (World coordinates) */
- private Point3d closestVertexCoordinatesVW = null;
-
- /* =================== METHODS ======================= */
-
- /**
- * Constructor
- * @param intersectionInfo The IntersectionInfo this intersection is part of.
- */
- public PickIntersection (Transform3D localToVWorld,
- PickInfo.IntersectionInfo intersectionInfo) {
-
- // Should check and throw NPE if the following is null.
- // localToVWorld can't be null.
- l2vw = localToVWorld;
- // intersectionInfo can't be null.
- iInfo = intersectionInfo;
- // geometry can't be null.
- geometry = iInfo.getGeometry();
-
- pointCoordinates = iInfo.getIntersectionPoint();
- distance = iInfo.getDistance();
- primitiveVertexIndices = iInfo.getVertexIndices();
-
- if (geometry instanceof GeometryArray) {
-
- int vertexFormat = ((GeometryArray)geometry).getVertexFormat();
- hasColors = (0 != (vertexFormat &
- (GeometryArray.COLOR_3 | GeometryArray.COLOR_4)));
- hasNormals = (0 != (vertexFormat & GeometryArray.NORMALS));
- hasTexCoords = (0 != (vertexFormat &
- (GeometryArray.TEXTURE_COORDINATE_2 |
- GeometryArray.TEXTURE_COORDINATE_3)));
-
- if (geometry instanceof IndexedGeometryArray) {
- geometryIsIndexed = true;
- }
- }
- }
-
- /**
- * Returns true if the geometry is indexed
- *
- */
- public boolean geometryIsIndexed() {
- return geometryIsIndexed;
- }
-
- /**
- * Get coordinates of closest vertex (local)
- * @return the coordinates of the vertex closest to the intersection point
- *
- */
- public Point3d getClosestVertexCoordinates() {
- // System.out.println("PI.closestVertexCoordinates " + closestVertexCoordinates);
- GeometryArray geom = (GeometryArray) geometry;
-
- if (closestVertexCoordinates == null) {
- int vertexIndex = getClosestVertexIndex();
- int vformat = geom.getVertexFormat();
- int val;
-
- int[] indices = getPrimitiveCoordinateIndices();
- if ((vformat & GeometryArray.BY_REFERENCE) == 0) {
- closestVertexCoordinates = new Point3d();
- geom.getCoordinate(indices[vertexIndex], closestVertexCoordinates);
- // System.out.println("PI.closestVertexCoordinates " +
-// closestVertexCoordinates + " vertexIndex " +
-// vertexIndex);
- }
- else {
- if ((vformat & GeometryArray.INTERLEAVED) == 0) {
- double[] doubleData = geom.getCoordRefDouble();
- // If data was set as float then ..
- if (doubleData == null) {
- float[] floatData = geom.getCoordRefFloat();
- if (floatData == null) {
- throw new UnsupportedOperationException("Deprecated : BY_REF - p3f and p3d");
- }
- else {
- val = indices[vertexIndex] * 3; // for x,y,z
- closestVertexCoordinates = new Point3d(floatData[val],
- floatData[val+1],
- floatData[val+2]);
- }
- }
- else {
- val = indices[vertexIndex] * 3; // for x,y,z
- closestVertexCoordinates = new Point3d(doubleData[val],
- doubleData[val+1],
- doubleData[val+2]);
- }
- }
- else {
- float[] floatData = geom.getInterleavedVertices();
- int offset = getInterleavedVertexOffset(geom);
- int stride = offset + 3; // for the vertices .
- val = stride * indices[vertexIndex]+offset;
- closestVertexCoordinates = new Point3d(floatData[val],
- floatData[val+1],
- floatData[val+2]);
- }
- }
- }
-
- return closestVertexCoordinates;
- }
-
- /**
- * Get coordinates of closest vertex (world)
- * @return the coordinates of the vertex closest to the intersection point
- *
- */
- public Point3d getClosestVertexCoordinatesVW() {
- if (closestVertexCoordinatesVW == null) {
- int vertexIndex = getClosestVertexIndex();
- Point3d[] coordinatesVW = getPrimitiveCoordinatesVW();
- closestVertexCoordinatesVW = coordinatesVW[vertexIndex];
- }
- return closestVertexCoordinatesVW;
- }
-
- /**
- * Get index of closest vertex
- * @return the index of the closest vertex
- */
- public int getClosestVertexIndex() {
- if (closestVertexIndex == -1) {
- double maxDist = Double.MAX_VALUE;
- double curDist = Double.MAX_VALUE;
- int closestIndex = -1;
- primitiveCoordinates = getPrimitiveCoordinates();
-
- assert(primitiveCoordinates != null);
-
-// System.out.println("PI.getClosestVertexIndex : primitiveCoordinates.length " +
-// primitiveCoordinates.length);
-
- for (int i=0;i
- * The pick mode specifies the detail level of picking before the PickInfo
- * is returned:
- *
- *
- * The pick flags specifies the content of the PickInfo(s) returned by the
- * pick methods. This is specified as one or more individual bits that are
- * bitwise "OR"ed together to describe the PickInfo data. The flags include :
- *
- * When using pickAllSorted or pickClosest methods, the picks
- * will be sorted by the distance from the start point of the pick shape to
- * the intersection point.
- *
- * @see Locale#pickClosest(int,int,javax.media.j3d.PickShape)
- */
-public class PickTool {
-
-
- /**
- * Flag to pass to
- *
- @return An array of
- @return A
- * 1. Create your scene graph.
- *
- * 2. Create this behavior with root and canvas.
- *
- *
- * The above behavior will monitor for any picking events on
- * the scene graph (below root node) and handle mouse rotates on pick hits.
- * Note the root node can also be a subgraph node of the scene graph (rather
- * than the topmost).
- */
-
-public class PickRotateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
- MouseRotate rotate;
- private PickingCallback callback=null;
- private TransformGroup currentTG;
-
- /**
- * Creates a pick/rotate behavior that waits for user mouse events for
- * the scene graph. This method has its pickMode set to BOUNDS picking.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- **/
-
- public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
- super(canvas, root, bounds);
- rotate = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
- rotate.setTransformGroup(currGrp);
- currGrp.addChild(rotate);
- rotate.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- }
-
- /**
- * Creates a pick/rotate behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- * @param pickMode specifys PickTool.PICK_BOUNDS or PickTool.PICK_GEOMETRY.
- * @see PickTool#setMode
- **/
-
- public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
- int pickMode){
- super(canvas, root, bounds);
- rotate = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
- rotate.setTransformGroup(currGrp);
- currGrp.addChild(rotate);
- rotate.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- this.setMode(pickMode);
- }
-
-
- /**
- * Update the scene to manipulate any nodes. This is not meant to be
- * called by users. Behavior automatically calls this. You can call
- * this only if you know what you are doing.
- *
- * @param xpos Current mouse X pos.
- * @param ypos Current mouse Y pos.
- **/
- @Override
- public void updateScene(int xpos, int ypos) {
- TransformGroup tg = null;
-
- if (!mevent.isMetaDown() && !mevent.isAltDown()){
-
- // System.out.println("PickRotateBeh : using pickfast pkg : PickInfo ...");
- pickCanvas.setFlags(PickInfo.NODE | PickInfo.SCENEGRAPHPATH);
-
- pickCanvas.setShapeLocation(xpos, ypos);
- PickInfo pickInfo = pickCanvas.pickClosest();
- if(pickInfo != null) {
- // System.out.println("Intersected!");
- tg = (TransformGroup) pickCanvas.getNode(pickInfo, PickTool.TYPE_TRANSFORM_GROUP);
- if((tg != null) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))) {
- rotate.setTransformGroup(tg);
- rotate.wakeup();
- currentTG = tg;
- }
- } else if (callback!=null)
- callback.transformChanged( PickingCallback.NO_PICK, null );
- }
- }
-
- /**
- * Callback method from MouseRotate
- * This is used when the Picking callback is enabled
- */
- @Override
- public void transformChanged( int type, Transform3D transform ) {
- callback.transformChanged( PickingCallback.ROTATE, currentTG );
- }
-
- /**
- * Register the class @param callback to be called each
- * time the picked object moves
- */
- public void setupCallback( PickingCallback callback ) {
- this.callback = callback;
- if (callback==null)
- rotate.setupCallback( null );
- else
- rotate.setupCallback( this );
- }
-
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickTranslateBehavior.java b/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickTranslateBehavior.java
deleted file mode 100644
index 23037b2..0000000
--- a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickTranslateBehavior.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.pickfast.behaviors;
-
-import javax.media.j3d.Bounds;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.PickInfo;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-
-import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
-import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
-import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
-import com.sun.j3d.utils.pickfast.PickTool;
-
-/**
- * A mouse behavior that allows user to pick and translate scene graph objects.
- * Common usage: 1. Create your scene graph. 2. Create this behavior with
- * the root and canvas. See PickRotateBehavior for more details.
- */
-
-public class PickTranslateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
- MouseTranslate translate;
- private PickingCallback callback = null;
- private TransformGroup currentTG;
-
- /**
- * Creates a pick/translate behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- **/
-
- public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
- super(canvas, root, bounds);
- translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
- translate.setTransformGroup(currGrp);
- currGrp.addChild(translate);
- translate.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- }
-
- /**
- * Creates a pick/translate behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- * @param pickMode specifys PickTool.PICK_BOUNDS or PickTool.PICK_GEOMETRY.
- * @see PickTool#setMode
- **/
- public PickTranslateBehavior(BranchGroup root, Canvas3D canvas,
- Bounds bounds, int pickMode) {
- super(canvas, root, bounds);
- translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
- translate.setTransformGroup(currGrp);
- currGrp.addChild(translate);
- translate.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- this.setMode(pickMode);
- }
-
-
- /**
- * Update the scene to manipulate any nodes. This is not meant to be
- * called by users. Behavior automatically calls this. You can call
- * this only if you know what you are doing.
- *
- * @param xpos Current mouse X pos.
- * @param ypos Current mouse Y pos.
- **/
- @Override
- public void updateScene(int xpos, int ypos){
- TransformGroup tg = null;
-
- if(!mevent.isAltDown() && mevent.isMetaDown()){
-
- pickCanvas.setShapeLocation(xpos, ypos);
-
- // System.out.println("PickTranslateBeh : using pickfast pkg : PickInfo ...");
-
- pickCanvas.setFlags(PickInfo.NODE | PickInfo.SCENEGRAPHPATH);
- PickInfo pickInfo = pickCanvas.pickClosest();
-
- if(pickInfo != null) {
- // System.out.println("Intersected!");
- tg = (TransformGroup) pickCanvas.getNode(pickInfo, PickTool.TYPE_TRANSFORM_GROUP);
- if((tg != null) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))) {
- translate.setTransformGroup(tg);
- translate.wakeup();
- currentTG = tg;
- }
- } else if (callback!=null)
- callback.transformChanged( PickingCallback.NO_PICK, null );
-
- }
-
- }
-
- /**
- * Callback method from MouseTranslate
- * This is used when the Picking callback is enabled
- */
- @Override
- public void transformChanged( int type, Transform3D transform ) {
- callback.transformChanged( PickingCallback.TRANSLATE, currentTG );
- }
-
- /**
- * Register the class @param callback to be called each
- * time the picked object moves
- */
- public void setupCallback( PickingCallback callback ) {
- this.callback = callback;
- if (callback==null)
- translate.setupCallback( null );
- else
- translate.setupCallback( this );
- }
-
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickZoomBehavior.java b/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickZoomBehavior.java
deleted file mode 100644
index a954aab..0000000
--- a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickZoomBehavior.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.pickfast.behaviors;
-
-import javax.media.j3d.Bounds;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.PickInfo;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-
-import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
-import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
-import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
-import com.sun.j3d.utils.pickfast.PickTool;
-
-
-/**
- * A mouse behavior that allows user to pick and zoom scene graph objects.
- * Common usage: 1. Create your scene graph. 2. Create this behavior with
- * the root and canvas. See PickRotateBehavior for more details.
- */
-
-public class PickZoomBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
- MouseZoom zoom;
- private PickingCallback callback = null;
- private TransformGroup currentTG;
-
- /**
- * Creates a pick/zoom behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- **/
-
- public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
- super(canvas, root, bounds);
- zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
- zoom.setTransformGroup(currGrp);
- currGrp.addChild(zoom);
- zoom.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- }
-
- /**
- * Creates a pick/zoom behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- * @param pickMode specifys PickTool.PICK_BOUNDS or PickTool.PICK_GEOMETRY.
- * @see PickTool#setMode
- */
- public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
- int pickMode) {
- super(canvas, root, bounds);
- zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
- zoom.setTransformGroup(currGrp);
- currGrp.addChild(zoom);
- zoom.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- this.setMode(pickMode);
- }
-
- /**
- * Update the scene to manipulate any nodes. This is not meant to be
- * called by users. Behavior automatically calls this. You can call
- * this only if you know what you are doing.
- *
- * @param xpos Current mouse X pos.
- * @param ypos Current mouse Y pos.
- **/
-
- @Override
- public void updateScene(int xpos, int ypos){
- TransformGroup tg = null;
-
- if (mevent.isAltDown() && !mevent.isMetaDown()){
-
- pickCanvas.setShapeLocation(xpos, ypos);
- // System.out.println("PickZoomBeh : using pickfast pkg : PickInfo ...");
-
- pickCanvas.setFlags(PickInfo.NODE | PickInfo.SCENEGRAPHPATH);
-
- PickInfo pickInfo = pickCanvas.pickClosest();
- if(pickInfo != null) {
- // System.out.println("Intersected!");
- tg = (TransformGroup) pickCanvas.getNode(pickInfo, PickTool.TYPE_TRANSFORM_GROUP);
- if((tg != null) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))) {
- zoom.setTransformGroup(tg);
- zoom.wakeup();
- currentTG = tg;
- }
- } else if (callback!=null)
- callback.transformChanged( PickingCallback.NO_PICK, null );
-
-
- }
- }
-
- /**
- * Callback method from MouseZoom
- * This is used when the Picking callback is enabled
- */
- @Override
- public void transformChanged( int type, Transform3D transform ) {
- callback.transformChanged( PickingCallback.ZOOM, currentTG );
- }
-
- /**
- * Register the class @param callback to be called each
- * time the picked object moves
- */
- public void setupCallback( PickingCallback callback ) {
- this.callback = callback;
- if (callback==null)
- zoom.setupCallback( null );
- else
- zoom.setupCallback( this );
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickingCallback.java b/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickingCallback.java
deleted file mode 100644
index 98573e9..0000000
--- a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickingCallback.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.pickfast.behaviors;
-
-import javax.media.j3d.TransformGroup;
-
-/**
- * The PickingCallback interface allows a class to be notified when a
- * picked object is moved. The class that is interested in object
- * movement implements this interface, and the object created with
- * that class is registered with the desired subclass of
- * PickMouseBehavior using the Provides picking behaviors for the new core picking methods. Provides picking utility classes for the new core picking methods.
- * The pick tolerance specifies the distance from the
- * pick center to include in the pick shape. A tolerance of 0.0 may speedup
- * picking slightly, but also make it very difficult to pick points and lines.
- *
- * The pick canvas can be used to make a series of picks. For example, to
- * initialize the pick canvas:
- *
- * Then for each mouse event:
- *
- * NOTE: For the pickAllSorted or pickClosest methods, the picks will be sorted
- * by the distance from the ViewPlatform to the intersection point.
- * @see PickTool
- */
-public class PickCanvas extends PickTool {
-
- /* OPEN ISSUES:
- -- Should restrict the pick shape to the front/back clip plane
- */
-
-
- /** The canvas we are picking into */
- Canvas3D canvas;
-
- /* the pick tolerance, default to 2.0 */
- float tolerance = 2.0f;
- int save_xpos;
- int save_ypos;
-
- /** Constructor with Canvas3D for mouse events and BranchGroup to be picked.
- */
- public PickCanvas (Canvas3D c, BranchGroup b) {
- super (b);
- canvas = c;
- }
-
- /** Constructor with Canvas3D for mouse events and Locale to be picked.
- */
- public PickCanvas (Canvas3D c, Locale l) {
- super (l);
- canvas = c;
- }
-
- /** Inquire the canvas to be used for picking operations.
- @return the canvas.
- */
- public Canvas3D getCanvas() {
- return canvas;
- }
-
- /** Set the picking tolerance. Objects within this distance
- * (in pixels)
- * to the mouse x,y location will be picked. The default tolerance is 2.0.
- * @param t The tolerance
- * @exception IllegalArgumentException if the tolerance is less than 0.
- */
- public void setTolerance(float t) {
- if (t < 0.0f) {
- throw new IllegalArgumentException();
- }
- tolerance = t;
-
- if ((pickShape != null) && (!userDefineShape)) {
- // reset pickShape
- pickShape = null;
- setShapeLocation(save_xpos, save_ypos);
- }
- }
-
- /** Get the pick tolerance.
- */
- public float getTolerance() {
- return tolerance;
- }
-
- /** Set the pick location. Defines the location on the canvas where the
- pick is to be performed.
- @param mevent The MouseEvent for the picking point
- */
- public void setShapeLocation(MouseEvent mevent) {
- setShapeLocation(mevent.getX(), mevent.getY());
- }
- /** Set the pick location. Defines the location on the canvas where the
- pick is to be performed (upper left corner of canvas is 0,0).
- @param xpos the X position of the picking point
- @param ypos the Y position of the picking point
- */
- public void setShapeLocation (int xpos, int ypos) {
- Transform3D motion = new Transform3D();
- Point3d eyePosn = new Point3d();
- Point3d mousePosn = new Point3d();
- Vector3d mouseVec = new Vector3d();
- boolean isParallel = false;
- double radius = 0.0;
- double spreadAngle = 0.0;
-
- this.save_xpos = xpos;
- this.save_ypos = ypos;
- canvas.getCenterEyeInImagePlate(eyePosn);
- canvas.getPixelLocationInImagePlate(xpos,ypos,mousePosn);
-
- if ((canvas.getView() != null) &&
- (canvas.getView().getProjectionPolicy() ==
- View.PARALLEL_PROJECTION)) {
- // Correct for the parallel projection: keep the eye's z
- // coordinate, but make x,y be the same as the mouse, this
- // simulates the eye being at "infinity"
- eyePosn.x = mousePosn.x;
- eyePosn.y = mousePosn.y;
- isParallel = true;
- }
-
- // Calculate radius for PickCylinderRay and spread angle for PickConeRay
- Vector3d eyeToCanvas = new Vector3d();
- eyeToCanvas.sub (mousePosn, eyePosn);
- double distanceEyeToCanvas = eyeToCanvas.length();
-
- Point3d deltaImgPlate = new Point3d();
- canvas.getPixelLocationInImagePlate (xpos+1, ypos, deltaImgPlate);
-
- Vector3d ptToDelta = new Vector3d();
- ptToDelta.sub (mousePosn, deltaImgPlate);
- double distancePtToDelta = ptToDelta.length();
- distancePtToDelta *= tolerance;
-
- canvas.getImagePlateToVworld(motion);
-
- /*
- System.out.println("mouse position " + xpos + " " + ypos);
- System.out.println("before, mouse " + mousePosn + " eye " + eyePosn);
- */
-
- motion.transform(eyePosn);
- start = new Point3d (eyePosn); // store the eye position
- motion.transform(mousePosn);
- mouseVec.sub(mousePosn, eyePosn);
- mouseVec.normalize();
-
- /*
- System.out.println(motion + "\n");
- System.out.println("after, mouse " + mousePosn + " eye " + eyePosn +
- " mouseVec " + mouseVec);
- */
-
- if (tolerance == 0.0) {
- if ((pickShape != null) && (pickShape instanceof PickRay)) {
- ((PickRay)pickShape).set (eyePosn, mouseVec);
- } else {
- pickShape = (PickShape) new PickRay (eyePosn, mouseVec);
- }
- // pickShape = (PickShape) new PickConeRay (eyePosn,
- // mouseVec,1.0*Math.PI/180.0);
- } else {
- if (isParallel) {
- // Parallel projection, use a PickCylinderRay
- distancePtToDelta *= motion.getScale();
- if ((pickShape != null) &&
- (pickShape instanceof PickCylinderRay)) {
- ((PickCylinderRay)pickShape).set (eyePosn, mouseVec,
- distancePtToDelta);
- } else {
- pickShape = (PickShape) new PickCylinderRay (eyePosn,
- mouseVec, distancePtToDelta);
- }
- } else {
- // Perspective projection, use a PickConeRay
-
- // Calculate spread angle
- spreadAngle = Math.atan (distancePtToDelta/distanceEyeToCanvas);
-
- if ((pickShape != null) &&
- (pickShape instanceof PickConeRay)) {
- ((PickConeRay)pickShape).set (eyePosn, mouseVec,
- spreadAngle);
- } else {
- pickShape = (PickShape) new PickConeRay (eyePosn, mouseVec,
- spreadAngle);
- }
- }
- }
- }
-} // PickCanvas
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/picking/PickIntersection.java b/src/classes/share/com/sun/j3d/utils/picking/PickIntersection.java
deleted file mode 100644
index df88c89..0000000
--- a/src/classes/share/com/sun/j3d/utils/picking/PickIntersection.java
+++ /dev/null
@@ -1,1581 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.picking;
-
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.IndexedGeometryArray;
-import javax.vecmath.Color3b;
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4b;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3d;
-import javax.vecmath.Point3f;
-import javax.vecmath.TexCoord2f;
-import javax.vecmath.TexCoord3f;
-import javax.vecmath.Vector3d;
-import javax.vecmath.Vector3f;
-
-/**
- * Holds information about an intersection of a PickShape with a Node
- * as part of a PickResult. Information about
- * the intersected geometry, intersected primitive, intersection point, and
- * closest vertex can be inquired.
- *
- * The intersected geometry is indicated by an index into the list of
- * geometry arrays on the PickResult. It can also be inquired from this
- * object.
- *
- * The intersected primitive indicates which primitive out of the GeometryArray
- * was intersected (where the primitive is a point, line, triangle or quad,
- * not a
- *
- * The primitive's VWorld coordinates are saved when then intersection is
- * calculated. The local coordinates, normal, color and texture coordinates
- * for the primitive can also be inquired if they are present and readable.
- *
- * The intersection point is the location on the primitive which intersects the
- * pick shape closest to the center of the pick shape. The intersection point's
- * location in VWorld coordinates is saved when the intersection is calculated.
- * The local coordinates, normal, color and texture coordiantes of at the
- * intersection can be interpolated if they are present and readable.
- *
- * The closest vertex is the vertex of the primitive closest to the intersection
- * point. The vertex index, VWorld coordinates and local coordinates of the
- * closest vertex can be inquired. The normal, color and texture coordinate
- * of the closest vertex can be inquired from the geometry array:
- *
- * The color, normal
- * and texture coordinate information for the intersected primitive and the
- * intersection point
- * can be inquired
- * the geometry includes them and the corresponding READ capibility bits are
- * set.
- *
- *
- * A PickResult can be used to calculate intersections on Node which is not part
- * of a live scene graph using the constructor which takes a local to VWorld
- * transformation for the Node.
- *
- * Pick hits on TriangleStrip primitives will store the triangle points in the
- * PickIntersection with
- * the verticies in counter-clockwise order. For triangles which start with
- * an odd numbered vertex this will be the the opposite of the
- * order of the points in the TriangleStrip.
- * This way the triangle in
- * the PickIntersection will display the same was as the triangle in the
- * strip.
- *
- * If the Shape3D being picked has multiple geometry arrays, the arrays are
- * stored in the PickResult and referred to by a geometry index.
- *
- * If the Shape3D refers to a CompressedGeometry, the geometry is decompressed
- * into an array of Shape3D nodes which can be inquired. The geometry
- * NodeComponents for the Shape3D nodes are stored and used as if the Shape3D
- * had multiple geometries. If there are multiple CompressedGeometries on the
- * Shape3D, the decompressed Shape3Ds and GeometryArrays will be stored
- * sequentially.
- *
- * The intersection point for Morph nodes cannot be calculated using the
- * displayed geometry
- * due to limitations in the current Java3D core API (the current
- * geometry of the the Morph cannot be inquired). Instead
- * the geometry at index 0 in the Morph is used. This limitation may
- * be eliminated in a future release of Java3D.
- */
-public class PickResult {
-
- /* OPEN ISSUES:
- -- getInterpolatedTextureCoordinates uses the depricated API faor
- getTextureCoordinate(), need to update.
- -- Bounds tests don't fill in any picking info.
- -- Can't do any intersections with the PickPoint shape.
- */
-
-
- // Externally used constants
-
- /**
- * Flag to pass to
- *
- * The utility method
- *
- *
- * A PickResult from a lower level of detail pick can be used to
- * inquire more detailed information if the capibility bits are set.
- * This can be used to filter the PickResults
- * before the more computationally intensive intersection processing.
- * For example,
- * the application can do a BOUNDS pick and then selectively inquire
- * intersections on some of the PickResults. This will save the effort of
- * doing intersection computation on the other PickResults.
- * However, inquiring the intersections from a GEOMETRY pick will make
- * the intersection computation happen twice, use GEOMETRY_INTERSECT_INFO
- * if you want to inquire the intersection information on all the PickResults.
- *
- * When using pickAllSorted or pickClosest methods, the picks
- * will be sorted by the distance from the start point of the pick shape to
- * the intersection point.
- *
- * Morph nodes cannot be picked using the displayed geometry in
- * GEOMETRY_INTERSECT_INFO mode due to limitations in the current Java3D core
- * API (the current
- * geometry of the the Morph cannot be inquired). Instead they are picked
- * using
- * the geometry at index 0 in the Morph, this limitation may be eliminated in a
- * future release of Java3D.
- *
- * If the pick shape is a PickBounds, the pick result will contain only the
- * scene graph path, even if the mode is GEOMETRY_INTERSECT_INFO.
- */
-public class PickTool {
-
- /* OPEN ISSUES:
- -- pickClosest() and pickAllSorted() using GEOMETRY and a non-PickRay
- shape => unsorted picking.
- -- Need to implement Morph geometry index 0 picking.
- */
-
- private final boolean debug = true;
- protected boolean userDefineShape = false;
-
- PickShape pickShape;
-
- /** Used to store the BranchGroup used for picking */
- BranchGroup pickRootBG = null;
- /** Used to store the Locale used for picking */
- Locale pickRootL = null;
-
- /** Used to store a reference point used in determining how "close" points
- are.
- */
- Point3d start = null;
-
- /* pick mode, one of BOUNDS, GEOMETRY, etc. */
- int mode = BOUNDS;
-
- /** Use this mode to pick by bounds and get basic information
- on the pick.
- */
- public static final int BOUNDS = 0x200;
-
- /** Use this mode to pick by geometry and get basic
- information on the pick.
- */
- public static final int GEOMETRY = 0x100;
-
- /** Use this mode to pick by geometry and save
- information about the intersections (intersected primitive,
- intersection point and closest vertex).
- */
- public static final int GEOMETRY_INTERSECT_INFO = 0x400;
-
-
- // Flags for the setCapabilities() method
- /**
- * Flag to pass to
- * Note that by default all com.sun.j3d.utils.geometry.Primitive
- * objects with the same parameters share their geometry (e.g.,
- * you can have 50 spheres in your scene, but the geometry is
- * stored only once). Therefore the capabilities of the geometry
- * are also shared, and once a shared node is live, the
- * capabilities cannot be changed. To assign capabilities to
- * Primitives with the same parameters, either set the
- * capabilities before the primitive is set live, or specify the
- * Primitive.GEOMETRY_NOT_SHARED constructor parameter when
- * creating the primitive.
- * @param node The node to modify
- * @param level The capability level, must be one of INTERSECT_TEST,
- * INTERSECT_COORD or INTERSECT_FULL
- * @throws IllegalArgumentException if Node is not a Shape3D or Morph or
- * if the flag value is not valid.
- * @throws javax.media.j3d.RestrictedAccessException if the node is part
- * of a live or compiled scene graph. */
- static public void setCapabilities(Node node, int level) {
- if (node instanceof Morph) {
- Morph morph = (Morph) node;
- switch (level) {
- case INTERSECT_FULL:
- /* intentional fallthrough */
- case INTERSECT_COORD:
- morph.setCapability(Morph.ALLOW_GEOMETRY_ARRAY_READ);
- /* intentional fallthrough */
- case INTERSECT_TEST:
- break;
- default:
- throw new IllegalArgumentException("Improper level");
- }
- double[] weights = morph.getWeights();
- for (int i = 0; i < weights.length; i++) {
- GeometryArray ga = morph.getGeometryArray(i);
- setCapabilities(ga, level);
- }
- } else if (node instanceof Shape3D) {
- Shape3D shape = (Shape3D) node;
- switch (level) {
- case INTERSECT_FULL:
- /* intentional fallthrough */
- case INTERSECT_COORD:
- shape.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
- /* intentional fallthrough */
- case INTERSECT_TEST:
- break;
- default:
- throw new IllegalArgumentException("Improper level");
- }
- for (int i = 0; i < shape.numGeometries(); i++) {
- Geometry geo = shape.getGeometry(i);
- if (geo instanceof GeometryArray) {
- setCapabilities((GeometryArray)geo, level);
- } else if (geo instanceof CompressedGeometry) {
- setCapabilities((CompressedGeometry)geo, level);
- }
- }
- } else {
- throw new IllegalArgumentException("Improper node type");
- }
- }
-
- static private void setCapabilities(GeometryArray ga, int level) {
- switch (level) {
- case INTERSECT_FULL:
- ga.setCapability(GeometryArray.ALLOW_COLOR_READ);
- ga.setCapability(GeometryArray.ALLOW_NORMAL_READ);
- ga.setCapability(GeometryArray.ALLOW_TEXCOORD_READ);
- /* intential fallthrough */
- case INTERSECT_COORD:
- ga.setCapability(GeometryArray.ALLOW_COUNT_READ);
- ga.setCapability(GeometryArray.ALLOW_FORMAT_READ);
- ga.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
- /* intential fallthrough */
- case INTERSECT_TEST:
- ga.setCapability(GeometryArray.ALLOW_INTERSECT);
- break;
- }
- if (ga instanceof IndexedGeometryArray) {
- setCapabilities((IndexedGeometryArray)ga, level);
- }
- }
-
- static private void setCapabilities(IndexedGeometryArray iga, int level) {
- switch (level) {
- case INTERSECT_FULL:
- iga.setCapability(IndexedGeometryArray.ALLOW_COLOR_INDEX_READ);
- iga.setCapability(IndexedGeometryArray.ALLOW_NORMAL_INDEX_READ);
- iga.setCapability(IndexedGeometryArray.ALLOW_TEXCOORD_INDEX_READ);
- /* intential fallthrough */
- case INTERSECT_COORD:
- iga.setCapability(IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ);
- /* intential fallthrough */
- case INTERSECT_TEST:
- break;
- }
- }
-
- static private void setCapabilities(CompressedGeometry cg, int level) {
- switch (level) {
- case INTERSECT_FULL:
- /* intential fallthrough */
- case INTERSECT_COORD:
- cg.setCapability(CompressedGeometry.ALLOW_GEOMETRY_READ);
- /* intential fallthrough */
- case INTERSECT_TEST:
- cg.setCapability(CompressedGeometry.ALLOW_INTERSECT);
- break;
- }
- }
-
- // Methods used to define the pick shape
-
- /** Sets the pick shape to a user-provided PickShape object
- * @param ps The pick shape to pick against.
- * @param startPt The start point to use for distance calculations
- */
- public void setShape (PickShape ps, Point3d startPt) {
- this.pickShape = ps;
- this.start = startPt;
- userDefineShape = (ps != null);
- }
-
- /** Sets the pick shape to use a user-provided Bounds object
- * @param bounds The bounds to pick against.
- * @param startPt The start point to use for distance calculations
- */
- public void setShapeBounds (Bounds bounds, Point3d startPt) {
- this.pickShape = (PickShape) new PickBounds (bounds);
- this.start = startPt;
- userDefineShape = true;
- }
-
- /** Sets the picking detail mode. The default is BOUNDS.
- * @param mode One of BOUNDS, GEOMETRY, GEOMETRY_INTERSECT_INFO, or
- * @exception IllegalArgumentException if mode is not a legal value
- */
- public void setMode (int mode) {
- if ((mode != BOUNDS) && (mode != GEOMETRY) &&
- (mode != GEOMETRY_INTERSECT_INFO)) {
- throw new java.lang.IllegalArgumentException();
- }
- this.mode = mode;
- }
-
- /** Gets the picking detail mode.
- */
- public int getMode () {
- return mode;
- }
-
- /** Sets the pick shape to a PickRay.
- * @param start The start of the ray
- * @param dir The direction of the ray
- */
- public void setShapeRay (Point3d start, Vector3d dir) {
- this.pickShape = (PickShape) new PickRay (start, dir);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Sets the pick shape to a PickSegment.
- @param start The start of the segment
-p @param end The end of the segment
- */
- public void setShapeSegment (Point3d start, Point3d end) {
- this.pickShape = (PickShape) new PickSegment (start, end);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Sets the pick shape to a capped PickCylinder
- * @param start The start of axis of the cylinder
- * @param end The end of the axis of the cylinder
- * @param radius The radius of the cylinder
- */
- public void setShapeCylinderSegment (Point3d start, Point3d end,
- double radius) {
- this.pickShape = (PickShape)
- new PickCylinderSegment (start, end, radius);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Sets the pick shape to an infinite PickCylinder.
- * @param start The start of axis of the cylinder
- * @param dir The direction of the axis of the cylinder
- * @param radius The radius of the cylinder
- */
- public void setShapeCylinderRay (Point3d start, Vector3d dir,
- double radius) {
- this.pickShape = (PickShape) new PickCylinderRay (start, dir, radius);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Sets the pick shape to a capped PickCone
- * @param start The start of axis of the cone
- * @param end The end of the axis of the cone
- * @param angle The angle of the cone
- */
- public void setShapeConeSegment (Point3d start, Point3d end,
- double angle) {
- this.pickShape = (PickShape) new PickConeSegment (start, end, angle);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Sets the pick shape to an infinite PickCone.
- * @param start The start of axis of the cone
- * @param dir The direction of the axis of the cone
- * @param angle The angle of the cone
- */
- public void setShapeConeRay (Point3d start, Vector3d dir,
- double angle) {
- this.pickShape = (PickShape) new PickConeRay (start, dir, angle);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Returns the PickShape for this object. */
- public PickShape getPickShape () {
- return pickShape;
- }
-
- /** Returns the start postion used for distance measurement. */
- public Point3d getStartPosition () {
- return start;
- }
-
- /** Selects all the nodes that intersect the PickShape.
- @return An array of
- @return An array of
- @return A
- * 2. Create this behavior with root and canvas.
- *
- *
- * The above behavior will monitor for any picking events on
- * the scene graph (below root node) and handle mouse drags on pick hits.
- * Note the root node can also be a subgraph node of the scene graph (rather
- * than the topmost).
- */
-
-public class PickRotateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
- MouseRotate drag;
-// int pickMode = PickTool.BOUNDS;
- private PickingCallback callback=null;
- private TransformGroup currentTG;
-
- /**
- * Creates a pick/rotate behavior that waits for user mouse events for
- * the scene graph. This method has its pickMode set to BOUNDS picking.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- **/
-
- public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
- super(canvas, root, bounds);
- drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
- drag.setTransformGroup(currGrp);
- currGrp.addChild(drag);
- drag.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- }
-
- /**
- * Creates a pick/rotate behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- * @param pickMode specifys PickTool.BOUNDS, PickTool.GEOMETRY or
- * PickTool.GEOMETRY_INTERSECT_INFO.
- * @see PickTool#setMode
- **/
-
- public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
- int pickMode){
- super(canvas, root, bounds);
- drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
- drag.setTransformGroup(currGrp);
- currGrp.addChild(drag);
- drag.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- this.setMode(pickMode);
- }
-
-
- /**
- * Update the scene to manipulate any nodes. This is not meant to be
- * called by users. Behavior automatically calls this. You can call
- * this only if you know what you are doing.
- *
- * @param xpos Current mouse X pos.
- * @param ypos Current mouse Y pos.
- **/
- @Override
- public void updateScene(int xpos, int ypos){
- TransformGroup tg = null;
-
- if (!mevent.isMetaDown() && !mevent.isAltDown()){
-
- pickCanvas.setShapeLocation(xpos, ypos);
- PickResult pr = pickCanvas.pickClosest();
- if ((pr != null) &&
- ((tg = (TransformGroup)pr.getNode(PickResult.TRANSFORM_GROUP))
- != null) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
- drag.setTransformGroup(tg);
- drag.wakeup();
- currentTG = tg;
- // free the PickResult
- // Need to clean up Issue 123 --- Chien
- // freePickResult(pr);
- } else if (callback!=null)
- callback.transformChanged( PickingCallback.NO_PICK, null );
- }
- }
-
- /**
- * Callback method from MouseRotate
- * This is used when the Picking callback is enabled
- */
- @Override
- public void transformChanged( int type, Transform3D transform ) {
- callback.transformChanged( PickingCallback.ROTATE, currentTG );
- }
-
- /**
- * Register the class @param callback to be called each
- * time the picked object moves
- */
- public void setupCallback( PickingCallback callback ) {
- this.callback = callback;
- if (callback==null)
- drag.setupCallback( null );
- else
- drag.setupCallback( this );
- }
-
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickTranslateBehavior.java b/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickTranslateBehavior.java
deleted file mode 100644
index 0768579..0000000
--- a/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickTranslateBehavior.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.picking.behaviors;
-
-import javax.media.j3d.Bounds;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-
-import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
-import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
-import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
-import com.sun.j3d.utils.picking.PickResult;
-import com.sun.j3d.utils.picking.PickTool;
-
-/**
- * A mouse behavior that allows user to pick and translate scene graph objects.
- * Common usage: 1. Create your scene graph. 2. Create this behavior with
- * the root and canvas. See PickRotateBehavior for more details.
- */
-
-public class PickTranslateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
- MouseTranslate translate;
- private PickingCallback callback = null;
- private TransformGroup currentTG;
-
- /**
- * Creates a pick/translate behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- **/
-
- public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
- super(canvas, root, bounds);
- translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
- translate.setTransformGroup(currGrp);
- currGrp.addChild(translate);
- translate.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- }
-
- /**
- * Creates a pick/translate behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- * @param pickMode specifys PickTool.BOUNDS, PickTool.GEOMETRY or
- * PickTool.GEOMETRY_INTERSECT_INFO.
- * @see PickTool#setMode
- **/
- public PickTranslateBehavior(BranchGroup root, Canvas3D canvas,
- Bounds bounds, int pickMode) {
- super(canvas, root, bounds);
- translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
- translate.setTransformGroup(currGrp);
- currGrp.addChild(translate);
- translate.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- this.setMode(pickMode);
- }
-
-
- /**
- * Update the scene to manipulate any nodes. This is not meant to be
- * called by users. Behavior automatically calls this. You can call
- * this only if you know what you are doing.
- *
- * @param xpos Current mouse X pos.
- * @param ypos Current mouse Y pos.
- **/
- @Override
- public void updateScene(int xpos, int ypos){
- TransformGroup tg = null;
-
- if (!mevent.isAltDown() && mevent.isMetaDown()){
-
- pickCanvas.setShapeLocation(xpos, ypos);
- PickResult pr = pickCanvas.pickClosest();
- if ((pr != null) &&
- ((tg = (TransformGroup)pr.getNode(PickResult.TRANSFORM_GROUP))
- != null) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
-
- translate.setTransformGroup(tg);
- translate.wakeup();
- currentTG = tg;
- // Need to clean up Issue 123 --- Chien
- // freePickResult(pr);
- } else if (callback!=null)
- callback.transformChanged( PickingCallback.NO_PICK, null );
- }
-
- }
-
- /**
- * Callback method from MouseTranslate
- * This is used when the Picking callback is enabled
- */
- @Override
- public void transformChanged( int type, Transform3D transform ) {
- callback.transformChanged( PickingCallback.TRANSLATE, currentTG );
- }
-
- /**
- * Register the class @param callback to be called each
- * time the picked object moves
- */
- public void setupCallback( PickingCallback callback ) {
- this.callback = callback;
- if (callback==null)
- translate.setupCallback( null );
- else
- translate.setupCallback( this );
- }
-
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickZoomBehavior.java b/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickZoomBehavior.java
deleted file mode 100644
index 9276560..0000000
--- a/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickZoomBehavior.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.picking.behaviors;
-
-import javax.media.j3d.Bounds;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-
-import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
-import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
-import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
-import com.sun.j3d.utils.picking.PickResult;
-import com.sun.j3d.utils.picking.PickTool;
-
-
-/**
- * A mouse behavior that allows user to pick and zoom scene graph objects.
- * Common usage: 1. Create your scene graph. 2. Create this behavior with
- * the root and canvas. See PickRotateBehavior for more details.
- */
-
-public class PickZoomBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
- MouseZoom zoom;
- private PickingCallback callback = null;
- private TransformGroup currentTG;
-
- /**
- * Creates a pick/zoom behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- **/
-
- public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
- super(canvas, root, bounds);
- zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
- zoom.setTransformGroup(currGrp);
- currGrp.addChild(zoom);
- zoom.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- }
-
- /**
- * Creates a pick/zoom behavior that waits for user mouse events for
- * the scene graph.
- * @param root Root of your scene graph.
- * @param canvas Java 3D drawing canvas.
- * @param bounds Bounds of your scene.
- * @param pickMode specifys PickTool.BOUNDS, PickTool.GEOMETRY or
- * PickTool.GEOMETRY_INTERSECT_INFO.
- * @see PickTool#setMode
- */
- public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
- int pickMode) {
- super(canvas, root, bounds);
- zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
- zoom.setTransformGroup(currGrp);
- currGrp.addChild(zoom);
- zoom.setSchedulingBounds(bounds);
- this.setSchedulingBounds(bounds);
- this.setMode(pickMode);
- }
-
- /**
- * Update the scene to manipulate any nodes. This is not meant to be
- * called by users. Behavior automatically calls this. You can call
- * this only if you know what you are doing.
- *
- * @param xpos Current mouse X pos.
- * @param ypos Current mouse Y pos.
- **/
-
- @Override
- public void updateScene(int xpos, int ypos){
- TransformGroup tg = null;
-
- if (mevent.isAltDown() && !mevent.isMetaDown()){
-
- pickCanvas.setShapeLocation(xpos, ypos);
- PickResult pr = pickCanvas.pickClosest();
- if ((pr != null) &&
- ((tg = (TransformGroup)pr.getNode(PickResult.TRANSFORM_GROUP))
- != null) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
- (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
- zoom.setTransformGroup(tg);
- zoom.wakeup();
- currentTG = tg;
- // Need to clean up Issue 123 --- Chien
- // freePickResult(pr);
- } else if (callback!=null)
- callback.transformChanged( PickingCallback.NO_PICK, null );
- }
- }
-
- /**
- * Callback method from MouseZoom
- * This is used when the Picking callback is enabled
- */
- @Override
- public void transformChanged( int type, Transform3D transform ) {
- callback.transformChanged( PickingCallback.ZOOM, currentTG );
- }
-
- /**
- * Register the class @param callback to be called each
- * time the picked object moves
- */
- public void setupCallback( PickingCallback callback ) {
- this.callback = callback;
- if (callback==null)
- zoom.setupCallback( null );
- else
- zoom.setupCallback( this );
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickingCallback.java b/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickingCallback.java
deleted file mode 100644
index 5678bd0..0000000
--- a/src/classes/share/com/sun/j3d/utils/picking/behaviors/PickingCallback.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.picking.behaviors;
-
-import javax.media.j3d.TransformGroup;
-
-/**
- * The PickingCallback interface allows a class to be notified when a
- * picked object is moved. The class that is interested in object
- * movement implements this interface, and the object created with
- * that class is registered with the desired subclass of
- * PickMouseBehavior using the OBSOLETE: provides picking behaviors for the old picking
-methods. OBSOLETE: provides picking utility classes for the old
-picking methods.
- * If the file does not contain universe information, null is returned.
- *
- * @param attachBranchGraphs load and attach all the branchgraphs
- * to the universe.
- * @see ConfiguredUniverse#getConfigURL
- */
- public ConfiguredUniverse readUniverse(boolean attachBranchGraphs ) throws IOException {
- return fileControl.readUniverse( attachBranchGraphs, null );
- }
-
- /**
- * Set the ClassLoader used to load the scene graph objects and
- * deserialize user data
- */
- public void setClassLoader( ClassLoader classLoader ) {
- fileControl.setClassLoader( classLoader );
- }
-
- /**
- * Get the ClassLoader used to load the scene graph objects and
- * deserialize user data
- */
- public ClassLoader getClassLoader() {
- return fileControl.getClassLoader();
- }
-
- /**
- * Create and return a ConfiguredUniverse with the PlatformGeometry, ViewerAvatar,
- * and Locales saved in the file. The MultiTransformGroup between the ViewingPlatform
- * and the View is also restored.
- * If the file does not contain universe information, null is returned.
- *
- * @param attachBranchGraphs load and attach all the branchgraphs
- * to the universe.
- * @param canvas The canvas to be associated with the Universe.
- */
- public ConfiguredUniverse readUniverse(boolean attachBranchGraphs,
- Canvas3D canvas) throws IOException {
- return fileControl.readUniverse( attachBranchGraphs, canvas );
- }
-
- /**
- * Get the UserData in the File header
- */
- public Object readUserData() throws IOException {
- return fileControl.getUserData();
- }
-
- /**
- * Get the Description of this file's contents
- */
- public String readDescription() throws IOException {
- return fileControl.readFileDescription();
- }
-
- /**
- * Return the number of BranchGraphs in the file
- */
- public int getBranchGraphCount() {
- return fileControl.getBranchGraphCount();
- }
-
- /**
- * Read the BranchGraph at index in the file. If the graph
- * contains references to nodes in other BranchGraphs that have not already been
- * loaded, they will also be loaded and returned.
- *
- * The requested graph will always be the first element in the array.
- *
- * The file index of all the Graphs can be discovered using
- *
- * @param index The index of the Graph in the file. First graph is at index 0
- *
- * @see #getBranchGraphPosition( BranchGroup graph )
- *
- */
- public BranchGroup[] readBranchGraph(int index) throws IOException {
- return fileControl.readBranchGraph( index );
- }
-
- /**
- * Read and return all the branchgraphs in the file
- */
- public BranchGroup[] readAllBranchGraphs() throws IOException {
- return fileControl.readAllBranchGraphs();
- }
-
- /**
- * Remove the IO system's reference to this branchgraph and all its nodes.
- *
- * References to all loaded graphs are maintained by the IO system in
- * order to facilitate node and component sharing between the graphs.
- *
- * This call removes the references to graph
- *
- * NOT CURRENTLY IMPLEMENTED
- */
- public void dereferenceBranchGraph( BranchGroup graph ) {
- throw new RuntimeException("Not implemented");
- }
-
- /**
- * Given a BranchGraph that has been loaded return the index of the
- * graph in the file. The the Branchgroup isn't found, -1 is returned.
- */
- public int getBranchGraphPosition( BranchGroup graph ) {
- return fileControl.getBranchGraphPosition( graph );
- }
-
- /**
- * Read the userdata for the branchgraph at 'index' in the file
- *
- * @param index the index of the graph in the file
- */
- public Object readBranchGraphUserData( int index ) throws IOException {
- return fileControl.readBranchGraphUserData( index );
- }
-
- /**
- * Return the names of all the named objects
- */
- public String[] getNames() {
- return fileControl.getNames();
- }
-
- /**
- * Return the named object.
- *
- * @param name The name of the object
- *
- * @exception NamedObjectException is thrown if the name is not known to the system
- * @exception ObjectNotLoadedException is thrown if the named object has not been loaded yet
- */
- public SceneGraphObject getNamedObject( String name ) throws NamedObjectException, ObjectNotLoadedException {
- return fileControl.getNamedObject( name );
- }
-
- /**
- * Close the file and cleanup internal data structures
- */
- public void close() throws IOException {
- fileControl.close();
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileWriter.java b/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileWriter.java
deleted file mode 100644
index 7931429..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileWriter.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.scenegraph.io;
-
-import java.io.File;
-import java.io.IOException;
-
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.SceneGraphObject;
-
-import com.sun.j3d.utils.scenegraph.io.retained.RandomAccessFileControl;
-import com.sun.j3d.utils.universe.SimpleUniverse;
-
-/**
- * Write a (set) of Java3D BranchGraphs and/or Universe to a file. The BranchGraphs
- * are stored in the order in which they are written, they can be read in any order
- * using SceneGraphFileReader.
- *
- * The API handles Nodes and NodeComponents that are shared between seperate
- * graphs. It will handle all Java3D 1.3 core classes and any user
- * subclass of a Node or NodeComponent that implements the SceneGraphIO
- * interface.
- */
-public class SceneGraphFileWriter extends java.lang.Object {
-
- private RandomAccessFileControl fileControl;
- private File file;
-
- /** Creates new SceneGraphFileWriter and opens the file for writing.
- *
- * Writes the
- * Java3D Universe structure to the file. This includes the number and position of
- * the Locales, PlatformGeometry, ViewerAvatar, and the MultitransformGroup between
- * the ViewingPlatform and the View. However this
- * call does not write the content of the branch graphs unless writeUniverseContent is true.
- * close() MUST be called when IO is complete. If close() is not called
- * the file contents will be undefined.
- * Using this class to write to a FileOutputStream is not recommended. Use
- * SceneGraphFileWriter instead to achieve maximum performance and flexibility.
- */
-public class SceneGraphStreamWriter extends java.lang.Object {
-
- private StreamControl control;
- private DataOutputStream out;
-
- /** Creates new SceneGraphStreamWriter that will write to the supplied stream */
- public SceneGraphStreamWriter(java.io.OutputStream outputStream ) throws IOException {
- this.out = new java.io.DataOutputStream( outputStream );
- control = new StreamControl( out );
- control.writeStreamHeader();
- }
-
-
- /**
- * Write
- *
- * If
- *
- * If
- *
- * @param universe The universe to write
- * @param writeContent Flag enabling the BranchGraphs to be written
- *
- * @exception IOException
- * @exception UnsupportedUniverseException Thrown if the universe class is not
- * supported by this implementation
- */
- public void writeUniverse( SimpleUniverse universe, boolean writeContent ) throws IOException, UnsupportedUniverseException {
- control.writeUniverse( out, universe, writeContent );
- }
-
- /**
- * Write the entire graph to the stream.
- *
- * The API will correctly handle NodeComponents that are shared
- * between seperate graphs. However Nodes cannot be referenced
- * in other Graphs.
- *
- * If a reference to a Node in another graph is encountered a
- * DanglingReferenceException will be thrown.
- *
- * The scenegraph.io APIs will handle the IO for all the core Java3D
-SceneGraphObjects. However, if you create a subclass of one of these
-objects and add it to your Scene Graph, the IO system, by default,
-will not store any state information specific to your class. The default behavior when an unrecognized SceneGraphObject class
-is encountered is to traverse up the superclasses of the object until
-a recognized Java3D class is located. The data structures for this
-class are then used for IO. The system does store the class name of
-the original object.
- For example:
- When the Scene Graph is written to a file and this node is
-encountered, the superclass javax.media.j3d.BranchGroup will be used
-to store all the state for the object so any children of
-MyBranchGroup, the capabilities, etc. will be stored, but myData will
-be lost. When the scene graph is loaded, MyBranchGroup will be
-instantiated and will be populated with all the state from
-BranchGroup but myData will have been lost. To overcome this, the scenegraph.io API provides an interface for
-you to implement in your own classes that provides the opportunity
-for you to save the state of your classes during the IO processes.
-This is the SceneGraphIO interface. When the scenegraph is saved, the methods of SceneGraphIO are
-called in this order
- createSceneGraphObjectReferences saveChildren writeSceneGraphObject During the load cycle the method call order is Instantiate Object using default constructor Populate object with state from superclasses readSceneGraphObject restoreSceneGraphObjectReferences Within each method you need to perform the following actions:
- createSceneGraphObjectReferences If your object has
- references to other SceneGraphObjects then you need to obtain an
- object reference (int) for each reference using the
- SceneGraphReferenceControl object passed as a parameter to this
- method. If you don't have references to other SceneGraphObjects then
- no action is required. saveChildren If your object is a subclass of Group and you
- want the scenegraph.io package to save the children then this must
- return true. If it returns false, the object will be saved but not
- its children. writeSceneGraphObject In this method you must write all the
- state information for your class, including the object references
- obtained in createSceneGraphObjectReferences, to the DataOutput
- stream passed into this method. readSceneGraphObject By the time this method is called your
- class has been instantiated and the state information in the Java3D
- superclass will have been loaded. You should load all the state
- information you saved for your class. restoreSceneGraphObjectReferences is called once all the
- SceneGraph objects have been loaded and allows you to restore the
- references to the other SceneGraph objects. Here are some examples. Only the parts of the source pertaining to
-IO are show.... This package provides a Java3D SceneGraph IO capability.
-The API supports IO of a scenegraph to and from a Java Stream and/or
-RandomAccessFile. The features offered for these two io systems are
-somewhat different. The SceneGraphFileReader and SceneGraphFileWriter classes provide
-IO to and from a RandomAccessFile. They allow a universe and/or
-multiple BranchGraphs to be written to the file with Node's and
-NodeComponent's shared between the separate graphs. The graphs can be
-read in any order. SceneGraphStreamReader and SceneGraphStreamWriter classes provide
-IO to and from a Stream. These classes allow a universe and/or
-multiple BranchGraphs to be passed over stream. In contrast to the
-FileReader/Writer sharing of Node's is NOT supported between graphs
-by the API. Sharing of node components is supported. If your
-application requires references to Nodes in other graphs (such as
-SharedGroups) the application must handle the references using the
-namedObjects constructs. Note : If you use SceneGraphStreamWriter class to write to a
-FileOutputStream the resulting file cannot be read using the
-SceneGraphFileReader, the converse is also true, you can not use a
-FileInputStream to load a file written by SceneGraphFileWriter.
-
-The package supports the IO of all the Java3D 1.3 core classes
-and many of the utilities. It also includes interfaces which can be
-implemented to allow user defined subclasses of SceneGraphObjects to
-be stored. Information on the extensibility can be found
-here
-
-The package has a number of properties which can be used to control the IO
-behavior
-
-
-
-j3d.io.ImageCompression this can be set to None, GZIP, JPEG and tells the
-IO system to compress images in the .j3f file using the prescribed technique. In
-the future this will be extended to support all the formats available in
-javax.imageio in JDK 1.4.
- Provides transparency sorting utility classes. Provides shader utility classes. Deprecated: Use java.lang.System.nanoTime() instead.
- *
- * As of Java 3D 1.3.1, this is handled the same as an attribute.
- * The individual setProperty() method implementations of
- * ConfigObject determine whether the method to set the property can
- * be invoked directly or through introspection. If through
- * introspection, then the evaluation of the property must be
- * delayed until the target object is instantiated.
- */
- static final int PROPERTY = 2 ;
-
- /**
- * Specifies that this command creates an alias for a ConfigObject of the
- * same base name.
- */
- static final int ALIAS = 3 ;
-
- /**
- * Specifies that this command is a deferred built-in command that can't
- * be immediately evaluated by the parser. Its evaluation is delayed
- * until all config objects are instantiated and their properties can be
- * evaluated.
- */
- static final int BUILTIN = 4 ;
-
- /**
- * Specifies that this command is an include file directive.
- */
- static final int INCLUDE = 5 ;
-
- /**
- * Specifes that this command is entirely processed by the
- * constructor and should be ignored by subsequent recipients.
- */
- static final int IGNORE = 6 ;
-
- /**
- * The type of this command, either CREATE, PROPERTY, ALIAS,
- * BUILTIN, INCLUDE, or IGNORE.
- */
- int type = -1 ;
-
- /**
- * The number of arguments in this command, including the command
- * name.
- */
- int argc = 0 ;
-
- /**
- * An array containing all of this command's arguments, including
- * the command name.
- */
- Object[] argv = null ;
-
- /**
- * The name of the command being invoked, which is always the first
- * argument of the command.
- */
- String commandName = null ;
-
- /**
- * The base name of this command, from which the name of the ConfigObject
- * subclass that processes it is derived. This is constructed by
- * stripping off the leading "New" prefix or the trailing "Attribute",
- * "Property", or "Alias" suffix of the command name. The name of the
- * ConfigObject subclass which handles the command is derived by adding
- * "Config" as a prefix to the base name.
- */
- String baseName = null ;
-
- /**
- * The instance name of the ConfigObject subclass which processes this
- * command. Together with the base name this provides the handle by which
- * a ConfigObject can be referenced by other commands in the configuration
- * file.
- */
- String instanceName = null ;
-
- /**
- * The file from which this command was read.
- */
- String fileName = null ;
-
- /**
- * The line number from which this command was read.
- */
- int lineNumber = 0 ;
-
- /**
- * Constructs a ConfigCommand from configuration file command arguments.
- *
- * @param elements arguments to this command, including the command name
- * @param fileName name of the file from where the command was read
- * @param lineNumber line number where the command is found in the file
- */
- ConfigCommand(Collection elements, String fileName, int lineNumber) {
- this.fileName = fileName ;
- this.lineNumber = lineNumber ;
-
- argc = elements.size() ;
- argv = elements.toArray(new Object[0]) ;
-
- if (! (argc > 0 && (argv[0] instanceof String)))
- throw new IllegalArgumentException("malformed command") ;
-
- commandName = (String)argv[0] ;
-
- if (commandName.startsWith("New")) {
- type = CREATE ;
- baseName = commandName.substring(3) ;
- instanceName = checkName(argv[1]) ;
- }
- else if (commandName.endsWith("Property")) {
- baseName = commandName.substring(0, commandName.length()-8) ;
- if (baseName.equals("Java")) {
- type = IGNORE ;
- processJavaProperty(argc, argv) ;
- }
- else {
- type = PROPERTY ;
- instanceName = checkName(argv[1]) ;
- }
- }
- else if (commandName.endsWith("Attribute")) {
- // Backward compatibility.
- type = PROPERTY ;
- baseName = commandName.substring(0, commandName.length()-9) ;
- instanceName = checkName(argv[1]) ;
- }
- else if (commandName.endsWith("Alias")) {
- type = ALIAS ;
- baseName = commandName.substring(0, commandName.length()-5) ;
- instanceName = checkName(argv[1]) ;
- }
- else if (commandName.equals("Include")) {
- type = INCLUDE ;
- }
- else {
- type = BUILTIN ;
- }
-
- // We allow "Window" as an equivalent to "Screen".
- if (baseName != null && baseName.equals("Window"))
- baseName = "Screen" ;
- }
-
- /**
- * Sets the Java property specified in the command. If the command
- * has 3 arguments then it's an unconditional assignment. If the
- * 3rd argument is "Default", then the property is set to the value
- * of the 4th argument only if the specified property has no
- * existing value.
- *
- * @param argc the number of arguments in the command
- * @param argv command arguments as an array of Objects; the 1st is
- * the command name (ignored), the 2nd is the name of the Java
- * property, the 3rd is the value to be set or the keyword
- * "Default", and the 4th is thevalue to be set if the Java
- * property doesn't already exist
- */
- private static void processJavaProperty(int argc, Object[] argv) {
- for (int i = 1 ; i < argc ; i++) {
- // Check args.
- if (argv[i] instanceof Boolean) {
- argv[i] = ((Boolean)argv[i]).toString() ;
- }
- else if (! (argv[i] instanceof String)) {
- throw new IllegalArgumentException
- ("JavaProperty arguments must be Strings or Booleans") ;
- }
- }
- if (argc == 3) {
- // Unconditional assignment.
- setJavaProperty((String)argv[1], (String)argv[2]) ;
- }
- else if (argc != 4) {
- // Conditional assignment must have 4 args.
- throw new IllegalArgumentException
- ("JavaProperty must have either 2 or 3 arguments") ;
- }
- else if (! ((String)argv[2]).equals("Default")) {
- // Penultimate arg must be "Default" keyword.
- throw new IllegalArgumentException
- ("JavaProperty 2nd argument must be \"Default\"") ;
- }
- else if (evaluateJavaProperty((String)argv[1]) == null) {
- // Assignment only if no existing value.
- setJavaProperty((String)argv[1], (String)argv[3]) ;
- }
- }
-
- /**
- * Sets the given Java system property if allowed by the security manager.
- *
- * @param key property name
- * @param value property value
- * @return previous property value if any
- */
- static String setJavaProperty(final String key, final String value) {
- return (String)java.security.AccessController.doPrivileged
- (new java.security.PrivilegedAction() {
- @Override
- public Object run() {
- return System.setProperty(key, value) ;
- }
- }) ;
- }
-
- /**
- * Evaluates the specified Java property string if allowed by the security
- * manager.
- *
- * @param key string containing a Java property name
- * @return string containing the Java property valaue
- */
- static String evaluateJavaProperty(final String key) {
- return (String)java.security.AccessController.doPrivileged
- (new java.security.PrivilegedAction() {
- @Override
- public Object run() {
- return System.getProperty(key) ;
- }
- }) ;
- }
-
- /**
- * Checks if the given object is an instance of String.
- *
- * @param o the object to be checked
- * @return the object cast to a String
- * @exception IllegalArgumentException if the object is not a String
- */
- private final String checkName(Object o) {
- if (! (o instanceof String))
- throw new IllegalArgumentException
- ("second argument to \"" + commandName + "\" must be a name") ;
-
- return (String)o ;
- }
-
- /**
- * Calls
- *
- * Clients can construct the view side of a scene graph by retrieving these
- * objects using the accessor methods provided by this class. This could
- * involve as little as just attaching ViewingPlatforms to a Locale, depending
- * upon how completely the viewing configuration is specified in the file.
- * The ConfiguredUniverse class is an example of a ConfigContainer client and
- * how it can be used.
- *
- * ConfigContainer can be useful for clients other than ConfiguredUniverse.
- * InputDevice and ViewPlatformBehavior configuration is fully supported, so a
- * given Java 3D installation can provide configuration files to an
- * application that will allow it to fully utilize whatever site-specific
- * devices and behaviors are available. The configuration mechanism can be
- * extended for any target object through the use of the
- *
- *
- * Normally the flag should be true. However, when instantiated by
- * ConfiguredUniverse, this flag is set false so that ConfiguredUniverse
- * can set a reference to itself in the ViewingPlatform before attaching
- * the behavior. This provides backwards compatibility to behaviors that
- * access the ConfiguredUniverse instance from a call to
- *
- *
- * The preferred methods to retrieve instances of specific objects defined
- * in the configuration file are to either 1) get the ConfiguredUniverse
- * instance when the behavior's
- *
- * (New{baseName} {instanceName} ... [Alias {aliasName}])
- *
- * The first two command elements and the optional trailing Alias syntax
- * are processed here, at which point the subclass implementation of
- * initialize() is called. Subclasses must override initialize() if they
- * need to process more than what is processed by default here.
- *
- * @param cmd configuration command that creates a new ConfigObject
- */
- private ConfigObject createConfigObject(ConfigCommand cmd) {
- Class objectClass = null ;
- ConfigObject configObject = null ;
-
- // Instantatiate the ConfigObject if possible. This is not the target
- // object, but an object that will gather configuration properties,
- // instantiate the target object, and then apply the configuration
- // properties to it.
- try {
- objectClass = Class.forName("com.sun.j3d.utils.universe.Config" +
- cmd.baseName) ;
- }
- catch (ClassNotFoundException e) {
- throw new IllegalArgumentException
- ("\"" + cmd.baseName + "\"" +
- " is not a configurable object; ignoring command") ;
- }
- try {
- configObject = (ConfigObject)(objectClass.newInstance()) ;
- }
- catch (IllegalAccessException e) {
- System.out.println(e) ;
- throw new IllegalArgumentException("Ignoring command") ;
- }
- catch (InstantiationException e) {
- System.out.println(e) ;
- throw new IllegalArgumentException("Ignoring command") ;
- }
-
- // Process an Alias keyword if present. This option is available for
- // all New commands so it is processed here. The Alias keyword must
- // be the penultimate command element, followed by a String.
- for (int i = 2 ; i < cmd.argc ; i++) {
- if (cmd.argv[i] instanceof String &&
- ((String)cmd.argv[i]).equals("Alias")) {
- if (i == (cmd.argc - 2) && cmd.argv[i+1] instanceof String) {
- addConfigObject(new ConfigAlias(cmd.baseName,
- (String)cmd.argv[i+1],
- configObject)) ;
- cmd.argc -= 2 ;
- }
- else {
- throw new IllegalArgumentException
- ("The alias name must be a string and " +
- "must be the last command argument") ;
- }
- }
- }
-
- // Initialize common fields.
- configObject.baseName = cmd.baseName ;
- configObject.instanceName = cmd.instanceName ;
- configObject.creatingCommand = cmd ;
- configObject.configContainer = this ;
-
- // Initialize specific fields and return the ConfigObject.
- configObject.setClassLoader(classLoader);
- configObject.initialize(cmd) ;
- return configObject ;
- }
-
- /**
- * Instantiate and initialize a ConfigObject base class containing alias
- * information. The command is of the form:
- *
- * ({baseName}Alias {aliasName} {originalName})
- *
- * @param cmd configuration command that creates a new alias
- * @return the new ConfigObject with alias information
- */
- private ConfigObject createConfigAlias(ConfigCommand cmd) {
- ConfigObject original ;
-
- if (cmd.argc != 3 || ! (cmd.argv[2] instanceof String))
- throw new IllegalArgumentException
- ("Command \"" + cmd.commandName +
- "\" requires an instance name as second argument") ;
-
- original = findConfigObject(cmd.baseName, (String)cmd.argv[2]) ;
- return new ConfigAlias(cmd.baseName, cmd.instanceName, original) ;
- }
-
- /**
- * A class that does nothing but reference another ConfigObject. Once
- * created, the alias name can be used in all commands that would accept
- * the original name. A lookup of the alias name will always return the
- * original instance.
- */
- private static class ConfigAlias extends ConfigObject {
- ConfigAlias(String baseName, String instanceName, ConfigObject targ) {
- this.baseName = baseName ;
- this.instanceName = instanceName ;
- this.isAlias = true ;
- this.original = targ ;
- targ.aliases.add(instanceName) ;
- }
- }
-
- /**
- * Adds the specified ConfigObject instance into this container using the
- * given ConfigCommand's base name and instance name.
- *
- * @param object the ConfigObject instance to add into the database
- */
- private void addConfigObject(ConfigObject object) {
- ArrayList instances ;
-
- instances = (ArrayList)baseNameMap.get(object.baseName) ;
- if (instances == null) {
- instances = new ArrayList() ;
- baseNameMap.put(object.baseName, instances) ;
- }
-
- // Disallow duplicate instance names.
- for (int i = 0 ; i < instances.size() ; i++) {
- ConfigObject co = (ConfigObject)instances.get(i) ;
- if (co.instanceName.equals(object.instanceName)) {
- // Don't confuse anybody using Window.
- String base = object.baseName ;
- if (base.equals("Screen")) base = "Screen or Window" ;
- throw new IllegalArgumentException
- ("Duplicate " + base + " instance name \"" +
- object.instanceName + "\" ignored") ;
- }
- }
-
- instances.add(object) ;
- }
-
- /**
- * Finds a config object matching the given base name and the instance
- * name. If an alias is found, then its original is returned. If the
- * object is not found, an IllegalArgumentException is thrown.
- *
- * @param basename base name of the config object
- * @param instanceName name associated with this config object instance
- * @return the found ConfigObject
- */
- ConfigObject findConfigObject(String baseName, String instanceName) {
- ArrayList instances ;
- ConfigObject configObject ;
-
- instances = (ArrayList)baseNameMap.get(baseName) ;
- if (instances != null) {
- for (int i = 0 ; i < instances.size() ; i++) {
- configObject = (ConfigObject)instances.get(i) ;
-
- if (configObject.instanceName.equals(instanceName)) {
- if (configObject.isAlias)
- return configObject.original ;
- else
- return configObject ;
- }
- }
- }
-
- // Throw an error, but don't confuse anybody using Window.
- if (baseName.equals("Screen")) baseName = "Screen or Window" ;
- throw new IllegalArgumentException
- (baseName + " \"" + instanceName + "\" not found") ;
- }
-
- /**
- * Find instances of config objects with the given base name.
- * This is the same as
- *
- *
- *
- * PhysicalEnvironment instances are created with the following command:
- *
- *
- *
- * Viewer instances are created with the following command:
- *
- *
- *
- * @return read-only Map from names to Viewer instances, or
- * null if no instances
- */
- public Map getNamedViewers() {
- if (viewerMap != null) return viewerMap ;
- viewerMap = createMap("View") ;
- return viewerMap ;
- }
-
- /**
- * Returns a read-only Set of all configured InputDevice instances in the
- * order they were defined in the configuration file. All InputDevice
- * instances in the set are initialized and registered with any
- * PhysicalEnvironments that reference them.
- *
- * InputDevice instances are created with the following command:
- *
- *
- * The InputDevice is configured through the DeviceProperty command:
- *
- *
- * Sensor instances are named with the following command:
- *
- *
- * The Sensor is configured through the SensorProperty command:
- *
- *
- * With the sole exception of the Sensor assigned to the head tracker,
- * none of the Sensors defined in the configuration file are placed into
- * the Sensor array maintained by a PhysicalEnvironment.
- *
- * @return read-only Map from names to Sensor instances, or
- * null if no instances
- */
- public Map getNamedSensors() {
- if (sensorMap != null) return sensorMap ;
- sensorMap = createMap("Sensor") ;
- return sensorMap ;
- }
-
- /**
- * Returns a read-only Set of all configured ViewingPlatform instances in
- * the order they were defined in the configuration file. The
- * ConfigContainer class itself does not attach the ViewingPlatform
- * instances to any scengraph components or universe Locales; they are not
- * "live" until made so by a separate client such as ConfiguredUniverse.
- *
- * ViewingPlatform instances are created with the following command:
- *
- *
- *
- * The behaviors are attached to any ViewingPlatforms that specified them;
- * that is, the
- *
- * ViewPlatformBehavior instances are created by the following command:
- *
- *
- * The behavior is configured using ViewPlatformBehaviorProperty:
- *
- *
- * Concrete ViewPlatformBehavior instances can also define their own
- * unique properties. In those cases, propertyName must be the
- * name of a behavior method that takes an array of Objects as its only
- * parameter; the array is populated with the values of arg0
- * through argn when the method is invoked to set the property.
- * These additional requirements for configurable behaviors can usually be
- * fulfilled by extending or wrapping available ViewPlatformBehavior
- * subclasses.
- *
- * @return read-only Set of all unique instances, or null
- */
- public Set getViewPlatformBehaviors() {
- if (behaviors != null) return behaviors ;
- behaviors = createSet("ViewPlatformBehavior") ;
- return behaviors ;
- }
-
- /**
- * Returns a read-only Map that maps ViewPlatformBehavior names to
- * instances. Names may be aliases and if so will map to the original
- * instances.
- *
- * The behaviors are attached to any ViewingPlatforms that specified them;
- * that is, the
- *
- * @return read-only Map from names to ViewPlatformBehavior instances, or
- * null if no instances
- * @see #getViewPlatformBehaviors
- */
- public Map getNamedViewPlatformBehaviors() {
- if (behaviorMap != null) return behaviorMap ;
- behaviorMap = createMap("ViewPlatformBehavior") ;
- return behaviorMap ;
- }
-
- /**
- * Returns a read-only Map containing the named Canvas3D instances used by
- * the specified Viewer. Names may be aliases and if so will map to the
- * original instances. The set of unique Canvas3D instances used by a
- * Viewer may be obtained by calling the Viewer's accessor methods
- * directly.
- *
- * A named Canvas3D is created and added to a Viewer whenever any of the
- * following configuration commands are used:
- *
- *
- * Generic object instances are created with the following command:
- *
- *
- * The object is configured through the ObjectProperty command:
- *
- *
- * Generic base implementations are provided for the initialize(),
- * setProperty(), and processProperties() methods. These implementations
- * assume target objects that are unknown and thus instantiated via
- * introspection. Property names are assumed to be method names that take an
- * array of Objects as a parameter; they are invoked through introspection as
- * well.
- *
- * Most ConfigObjects target concrete Java 3D core classes, so these
- * implementations are usually overridden to instantiate those objects and
- * call their methods directly.
- */
-class ConfigObject {
- /**
- * The base name of this object, derived from the configuration command
- * which created it. This is constructed by stripping off the leading
- * "New" prefix or the trailing "Attribute", "Property", or "Alias" suffix
- * of the command name. The name of the ConfigObject subclass which
- * handles the command is derived by adding "Config" as a prefix to the
- * base name.
- */
- String baseName = null ;
-
- /**
- * The instance name of this object, as specified in the configuration
- * file.
- */
- String instanceName = null ;
-
- /**
- * The corresponding target object which this ConfigObject is configuring.
- */
- Object targetObject = null ;
-
- /**
- * The name of the target class this object is configuring.
- */
- String targetClassName = null ;
-
- /**
- * The Class object for the target.
- */
- Class targetClass = null ;
-
- /**
- * Configurable properties gathered by this object, represented by the
- * ConfigCommands that set them.
- */
- List properties = new ArrayList() ;
-
- /**
- * The ConfigContainer in which this ConfigObject is contained.
- */
- ConfigContainer configContainer = null ;
-
- /**
- * The command that created this class.
- */
- ConfigCommand creatingCommand = null ;
-
- /**
- * If true, this object is an alias to another.
- */
- boolean isAlias = false ;
-
- /**
- * If isAlias is true, this references the original object.
- */
- ConfigObject original = null ;
-
- /**
- * List of alias Strings for this object if it's not an alias itself.
- */
- List aliases = new ArrayList() ;
-
- protected ClassLoader classLoader;
-
- /**
- * @param classLoader the ClassLoader to use when loading the implementation
- * class for this object
- */
- void setClassLoader( ClassLoader classLoader ) {
- this.classLoader = classLoader;
- }
-
- /**
- * The base initialize() implementation. This takes a ConfigCommand with
- * three arguments: the command name, the instance name, and the name of
- * the target class this ConfigObject is configuring. The command in the
- * configuration file should have the form:
- *
- * (New{configType} {instanceName} {className})
- *
- * For example, (NewDevice tracker com.sun.j3d.input.LogitechTracker) will
- * first cause ConfigDevice to be instantiated, which will then be
- * initialized with this method. After all the properties are collected,
- * ConfigDevice will instantiate com.sun.j3d.input.LogitechTracker,
- * evaluate its properties, and allow references to it in the
- * configuration file by the name "tracker".
- *
- * It's assumed the target class will be instantiated through
- * introspection and its properties set through introspection as well.
- * Most config objects (ConfigScreen, ConfigView, ConfigViewPlatform,
- * ConfigPhysicalBody, and ConfigPhysicalEnvironment) target a concrete
- * core Java 3D class and will instantiate them directly, so they override
- * this method.
- *
- * @param c the command that created this ConfigObject
- */
- protected void initialize(ConfigCommand c) {
- if (c.argc != 3) {
- syntaxError("Wrong number of arguments to " + c.commandName) ;
- }
-
- if (!isName(c.argv[1])) {
- syntaxError("The first argument to " + c.commandName +
- " must be the instance name") ;
- }
-
- if (!isName(c.argv[2])) {
- syntaxError("The second argument to " + c.commandName +
- " must be the class name") ;
- }
-
- targetClassName = (String)c.argv[2] ;
- }
-
- /**
- * The base setProperty() implementation. This implementation assumes the
- * property needs to be set by introspection on the property name as a
- * method that accepts an array of Objects. That is, the command in the
- * configuration file is of the form:
- *
- * ({type}Property {instance name} {method name} {arg0} ... {argn})
- *
- * For example, (DeviceProperty tracker SerialPort "/dev/ttya") will
- * invoke the method named "SerialPort" in the object referenced by
- * "tracker" with an array of 1 Object containing the String
- * "/dev/ttya".
- *
- * The property is stored as the original ConfigCommand and is evaluated
- * after the configuration file has been parsed. It is overridden by
- * subclasses that instantiate concrete core Java 3D classes with known
- * method names.
- *
- * @param c the command that invoked this method
- */
- protected void setProperty(ConfigCommand c) {
- if (c.argc < 4) {
- syntaxError("Wrong number of arguments to " + c.commandName) ;
- }
-
- if (!isName(c.argv[1])) {
- syntaxError("The first argument to " + c.commandName +
- " must be the instance name") ;
- }
-
- if (!isName(c.argv[2])) {
- syntaxError("The second argument to " + c.commandName +
- " must be the property name") ;
- }
-
- properties.add(c) ;
- }
-
- /**
- * Instantiates the target object.
- */
- protected Object createTargetObject() {
- if (targetClassName == null)
- return null ;
-
- targetClass = getClassForName(creatingCommand, targetClassName) ;
- targetObject = getNewInstance(creatingCommand, targetClass) ;
-
- return targetObject ;
- }
-
- /**
- * Return the class for the specified class name string.
- *
- * @param className the name of the class
- * @return the object representing the class
- */
- protected Class getClassForName(ConfigCommand cmd, String className) {
- try {
- // Use the system class loader. If the Java 3D jar files are
- // installed directly in the JVM's lib/ext directory, then the
- // default class loader won't find user classes outside ext.
- //
- // From 1.3.2 we use the classLoader supplied to this object,
- // normally this will be the system class loader, but for webstart
- // apps the user can supply another class loader.
- return Class.forName(className, true,
- classLoader) ;
- }
- catch (ClassNotFoundException e) {
- throw new IllegalArgumentException
- (errorMessage(cmd, "Class \"" + className + "\" not found")) ;
- }
- }
-
- /**
- * Return an instance of the class specified by the given class object.
- *
- * @param objectClass the object representing the class
- * @return a new instance of the class
- */
- protected Object getNewInstance(ConfigCommand cmd, Class objectClass) {
- try {
- return objectClass.newInstance() ;
- }
- catch (IllegalAccessException e) {
- throw new IllegalArgumentException
- (errorMessage(cmd, "Illegal access to object class")) ;
- }
- catch (InstantiationException e) {
- throw new IllegalArgumentException
- (errorMessage(cmd, "Instantiation error for object class")) ;
- }
- }
-
- /**
- * Evaluate properties for the the given class instance. The property
- * names are used as the names of methods to be invoked by the instance.
- * Each such method takes an array of Objects as its only parameter. The
- * array will contain Objects corresponding to the property values.
- */
- protected void processProperties() {
- evaluateProperties(this.targetClass,
- this.targetObject, this.properties) ;
-
- // Potentially holds a lot of references, and not needed anymore.
- this.properties.clear() ;
- }
-
- /**
- * Evaluate properties for the the given class instance.
- *
- * @param objectClass the class object representing the given class
- * @param objectInstance the class instance whose methods will be invoked
- * @param properties list of property setting commands
- */
- protected void evaluateProperties(Class objectClass,
- Object objectInstance,
- List properties) {
-
- // Holds the single parameter passed to the class instance methods.
- Object[] parameters = new Object[1] ;
-
- // Specifies the class of the single method parameter.
- Class[] parameterTypes = new Class[1] ;
-
- // All property methods use Object[] as their single parameter, which
- // happens to be the same type as the parameters variable above.
- parameterTypes[0] = parameters.getClass() ;
-
- // Loop through all property commands and invoke the appropriate
- // method for each one. Property commands are of the form:
- // ({configClass}Property {instanceName} {methodName} {arg} ...)
- for (int i = 0 ; i < properties.size() ; i++) {
- ConfigCommand cmd = (ConfigCommand)properties.get(i) ;
- String methodName = (String)cmd.argv[2] ;
- Object[] argv = new Object[cmd.argc - 3] ;
-
- for (int a = 0 ; a < argv.length ; a++) {
- argv[a] = cmd.argv[a + 3] ;
- if (argv[a] instanceof ConfigCommand) {
- // Evaluate a delayed built-in command.
- ConfigCommand bcmd = (ConfigCommand)argv[a] ;
- argv[a] = configContainer.evaluateBuiltIn(bcmd) ;
- }
- }
-
- parameters[0] = argv ;
-
- try {
- Method objectMethod =
- objectClass.getMethod(methodName, parameterTypes) ;
-
- objectMethod.invoke(objectInstance, parameters) ;
- }
- catch (NoSuchMethodException e) {
- throw new IllegalArgumentException
- (errorMessage
- (cmd, "Unknown property \"" + methodName + "\"")) ;
- }
- catch (IllegalAccessException e) {
- throw new IllegalArgumentException
- (errorMessage
- (cmd, "Illegal access to \"" + methodName + "\"")) ;
- }
- catch (InvocationTargetException e) {
- throw new IllegalArgumentException
- (errorMessage(cmd, e.getTargetException().getMessage())) ;
- }
- }
- }
-
- /**
- * Throws an IllegalArgumentException with the specified description.
- * This is caught by the parser which prints out error diagnostics and
- * continues parsing if it can.
- *
- * @param s string describing the syntax error
- */
- protected void syntaxError(String s) {
- throw new IllegalArgumentException(s) ;
- }
-
- /**
- * Constructs an error message from the given string and file information
- * from the given command.
- */
- static String errorMessage(ConfigCommand cmd, String s) {
- return
- s + "\nat line " + cmd.lineNumber +
- " in " + cmd.fileName + "\n" + cmd;
- }
-
- /**
- * Check if the argument is a name string.
- *
- * @param o the object to be checked
- * @return true if the object is an instance of String
- */
- protected boolean isName(Object o) {
- return (o instanceof String) ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalBody.java b/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalBody.java
deleted file mode 100644
index cd76a71..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalBody.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe;
-
-import javax.media.j3d.PhysicalBody;
-import javax.media.j3d.Transform3D;
-import javax.vecmath.Matrix4d;
-import javax.vecmath.Point3d;
-
-class ConfigPhysicalBody extends ConfigObject {
-
- Point3d leftEyePosition = new Point3d(-0.033, 0.0, 0.0);
- Point3d rightEyePosition = new Point3d(0.033, 0.0, 0.0);
- double stereoEyeSeparation = Double.MAX_VALUE;
-
- Point3d leftEarPosition = new Point3d(-0.080, -0.030, 0.09);
- Point3d rightEarPosition = new Point3d(0.080, -0.030, 0.09);
-
- double nominalEyeHeightFromGround = 1.68;
- double nominalEyeOffsetFromNominalScreen = 0.4572;
-
- Matrix4d headToHeadTracker = new Matrix4d(
- 1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0);
-
- PhysicalBody j3dPhysicalBody;
-
- // Overridden to do nothing.
- @Override
- protected void initialize(ConfigCommand command) {
- }
-
- @Override
- protected void setProperty(ConfigCommand command) {
- int argc = command.argc;
- Object[] argv = command.argv;
- String prop;
- Object val;
-
- // Check that arg[1] and arg[2] are strings
- if (argc != 4) {
- syntaxError("Incorrect number of arguments to " +
- command.commandName);
- }
-
- if (!isName(argv[1])) {
- syntaxError("The first argument to " + command.commandName +
- " must be a name");
- }
-
- if (!isName(argv[2])) {
- syntaxError("The second argument to " + command.commandName +
- " must be an property/attribute name");
- }
-
- prop = (String) argv[2];
- val = argv[3];
-
- if (prop.equals("StereoEyeSeparation")) {
- if (!(val instanceof Double)) {
- syntaxError("StereoEyeSeparation must be a number");
- }
- stereoEyeSeparation = ((Double) val).doubleValue();
- }
- else if (prop.equals("LeftEyePosition")) {
- if (!(val instanceof Point3d)) {
- syntaxError("LeftEyePosition must be a point");
- }
- leftEyePosition = (Point3d) val;
- }
- else if (prop.equals("RightEyePosition")) {
- if (!(val instanceof Point3d)) {
- syntaxError("RightEyePosition must be a point");
- }
- rightEyePosition = (Point3d) val;
- }
- else if (prop.equals("LeftEarPosition")) {
- if (!(val instanceof Point3d)) {
- syntaxError("LeftEarPosition must be a point");
- }
- leftEarPosition = (Point3d) val;
- }
- else if (prop.equals("RightEarPosition")) {
- if (!(val instanceof Point3d)) {
- syntaxError("RightEarPosition must be a point");
- }
- leftEarPosition = (Point3d) val;
- }
- else if (prop.equals("NominalEyeHeightFromGround")) {
- if (!(val instanceof Double)) {
- syntaxError("NominalEyeHeightFromGround must be a number");
- }
- nominalEyeHeightFromGround = ((Double) val).doubleValue();
- }
- else if (prop.equals("NominalEyeOffsetFromNominalScreen")) {
- if (!(val instanceof Double)) {
- syntaxError("NominalEyeOffsetFromNominalScreen " +
- "must be a number");
- }
- nominalEyeOffsetFromNominalScreen = ((Double) val).doubleValue();
- }
- else if (prop.equals("HeadToHeadTracker")) {
- if (!(val instanceof Matrix4d)) {
- syntaxError("HeadToHeadTracker must be a matrix");
- }
- headToHeadTracker = (Matrix4d) val;
- }
- else {
- syntaxError("Unknown " + command.commandName +
- " \"" + prop + "\"") ;
- }
- }
-
- PhysicalBody createJ3dPhysicalBody() {
- // Transfer all the information from the config version
- if (stereoEyeSeparation < Double.MAX_VALUE) {
- leftEyePosition.set(-stereoEyeSeparation / 2.0, 0.0, 0.0);
- rightEyePosition.set(stereoEyeSeparation / 2.0, 0.0, 0.0);
- }
-
- j3dPhysicalBody = new PhysicalBody(leftEyePosition, rightEyePosition,
- leftEarPosition, rightEarPosition);
-
- j3dPhysicalBody.setHeadToHeadTracker(
- new Transform3D(headToHeadTracker));
-
- j3dPhysicalBody.setNominalEyeHeightFromGround(
- nominalEyeHeightFromGround);
- j3dPhysicalBody.setNominalEyeOffsetFromNominalScreen(
- nominalEyeOffsetFromNominalScreen);
-
- return j3dPhysicalBody ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalEnvironment.java b/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalEnvironment.java
deleted file mode 100644
index b9144ab..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfigPhysicalEnvironment.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe ;
-
-import java.util.ArrayList;
-
-import javax.media.j3d.InputDevice;
-import javax.media.j3d.PhysicalEnvironment;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.View;
-import javax.vecmath.Matrix4d;
-
-class ConfigPhysicalEnvironment extends ConfigObject {
-
- /**
- * The corresponding J3D core PhysicalEnvironment instance.
- */
- PhysicalEnvironment j3dPhysicalEnvironment = null ;
-
- /**
- * The coexistence to tracker base matrix.
- */
- Matrix4d coexistenceToTrackerBase = null ;
-
- // All other configurable attributes.
- private ConfigSensor headTracker = null ;
- private ArrayList inputDevices = new ArrayList() ;
- private int coexistenceCenterInPworldPolicy = View.NOMINAL_SCREEN ;
-
- /**
- * Overrides initialize() to do nothing.
- */
- @Override
- protected void initialize(ConfigCommand command) {
- }
-
- /**
- * Handles the commands
- * (PhysicalEnvironmentAttribute {instance} {attrName} {attrValue}) and
- * (PhysicalEnvironmentProperty {instance} {attrName} {attrValue}).
- *
- * @param command the command that invoked this method
- */
- @Override
- protected void setProperty(ConfigCommand command) {
- Object val ;
- Object[] argv = command.argv ;
- int argc = command.argc ;
- String sval, prop ;
-
- if (argc != 4) {
- syntaxError("Incorrect number of arguments to " +
- command.commandName) ;
- }
-
- if (!isName(argv[1])) {
- syntaxError("The first argument to " + command.commandName +
- " must be a name") ;
- }
-
- if (!isName(argv[2])) {
- syntaxError("The second argument to " + command.commandName +
- " must be a property name") ;
- }
-
- prop = (String)argv[2] ;
- val = argv[3] ;
-
- if (prop.equals("CoexistenceCenterInPworldPolicy")) {
- if (!(val instanceof String))
- syntaxError("CoexistenceCenterInPworldPolicy must be string") ;
-
- sval = (String)val ;
- if (sval.equals("NOMINAL_HEAD"))
- coexistenceCenterInPworldPolicy = View.NOMINAL_HEAD ;
- else if (sval.equals("NOMINAL_SCREEN"))
- coexistenceCenterInPworldPolicy = View.NOMINAL_SCREEN ;
- else if (sval.equals("NOMINAL_FEET"))
- coexistenceCenterInPworldPolicy = View.NOMINAL_FEET ;
- else
- syntaxError("Illegal value " + sval +
- " for CoexistenceCenterInPworldPolicy") ;
- }
- else if (prop.equals("CoexistenceToTrackerBase")) {
- if (val instanceof Matrix4d)
- coexistenceToTrackerBase = (Matrix4d)val ;
- else
- syntaxError("CoexistenceToTrackerBase must be a Matrix4d") ;
- }
- else if (prop.equals("InputDevice")) {
- if (!(val instanceof String))
- syntaxError("InputDevice must be a name") ;
-
- sval = (String)val ;
- inputDevices.add(configContainer.findConfigObject("Device", sval));
- }
- else if (prop.equals("HeadTracker")) {
- if (!(val instanceof String))
- syntaxError("HeadTracker must be a Sensor name") ;
-
- sval = (String)val ;
- headTracker =
- (ConfigSensor)configContainer.findConfigObject("Sensor", sval);
- }
- else {
- syntaxError("Unknown " + command.commandName +
- " \"" + prop + "\"") ;
- }
- }
-
- /**
- * Create a core Java 3D PhysicalEnvironment instance using the attributes
- * gathered by this object.
- */
- PhysicalEnvironment createJ3dPhysicalEnvironment() {
- j3dPhysicalEnvironment = new PhysicalEnvironment() ;
-
- j3dPhysicalEnvironment.setCoexistenceCenterInPworldPolicy
- (coexistenceCenterInPworldPolicy) ;
-
- if (coexistenceToTrackerBase != null)
- j3dPhysicalEnvironment.setCoexistenceToTrackerBase
- (new Transform3D(coexistenceToTrackerBase)) ;
-
- return j3dPhysicalEnvironment ;
- }
-
- /**
- * Process the devices associated with the PhysicalEnvironment.
- */
- void processDevices() {
- for (int j = 0; j < inputDevices.size(); j++) {
- ConfigDevice configDevice = (ConfigDevice)inputDevices.get(j) ;
- InputDevice device = configDevice.j3dInputDevice ;
- j3dPhysicalEnvironment.addInputDevice(device) ;
- }
-
- if (headTracker != null) {
- j3dPhysicalEnvironment.setHeadIndex(0) ;
- j3dPhysicalEnvironment.setSensor(0, headTracker.j3dSensor) ;
- }
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfigScreen.java b/src/classes/share/com/sun/j3d/utils/universe/ConfigScreen.java
deleted file mode 100644
index 4748675..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfigScreen.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe ;
-
-import java.awt.Window;
-
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.View;
-import javax.swing.JFrame;
-import javax.swing.JPanel;
-import javax.vecmath.Matrix4d;
-import javax.vecmath.Point2d;
-
-class ConfigScreen extends ConfigObject {
-
- /**
- * The index of this screen in the GraphicsDevice array returned by
- * GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices().
- */
- int frameBufferNumber ;
-
- /**
- * The physical width in meters of the screen area of the GraphicsDevice
- * associated with this ConfigScreen. The default is based on a screen
- * resolution of 90 pixels/inch.
- */
- double physicalScreenWidth = 0.0 ;
-
- /**
- * The physical height in meters of the screen area of the GraphicsDevice
- * associated with this ConfigScreen. The default is based on a screen
- * resolution of 90 pixels/inch.
- */
- double physicalScreenHeight = 0.0 ;
-
- /**
- * The trackerBaseToImagePlate transform of this ConfigScreen.
- * The default is the identity transform.
- */
- Matrix4d trackerBaseToImagePlate = null ;
-
- /**
- * The headTrackerToLeftImagePlate transform of this ConfigScreen if HMD
- * mode is in effect. The default is the identity transform.
- */
- Matrix4d headTrackerToLeftImagePlate = null ;
-
- /**
- * The headTrackerToRightImagePlate transform of this ConfigScreen if HMD
- * mode is in effect. The default is the identity transform.
- */
- Matrix4d headTrackerToRightImagePlate = null ;
-
- /**
- * The monoscopicViewPolicy for this ConfigScreen. The default is
- * View.CYCLOPEAN_EYE_VIEW.
- */
- int monoscopicViewPolicy = View.CYCLOPEAN_EYE_VIEW ;
-
- /**
- * Boolean indicating whether a full-screen window should be created for
- * this ConfigScreen. The default is false.
- */
- boolean fullScreen = false ;
-
- /**
- * Boolean indicating whether a full-screen window with no borders should
- * be created for this ConfigScreen. The default is false.
- */
- boolean noBorderFullScreen = false ;
-
- /**
- * The width in pixels for the window to be created for this ConfigScreen
- * if a full screen window is not specified. The default is 512.
- */
- int windowWidthInPixels = 512 ;
-
- /**
- * The height in pixels for the window to be created for this ConfigScreen
- * if a full screen window is not specified. The default is 512.
- */
- int windowHeightInPixels = 512 ;
-
- /**
- * The X pixel position of the top-left corner of the window, relative to
- * the physical screen. The default is 0.
- */
- int windowX = 0 ;
-
- /**
- * The Y pixel position of the top-left corner of the window, relative to
- * the physical screen. The default is 0.
- */
- int windowY = 0 ;
-
- /**
- * The JFrame created for this ConfigScreen. When running under JDK 1.4
- * or newer, the JFrame always contains a JPanel which contains the
- * Canvas3D. When running under JDK 1.3.1 and using a borderless full
- * screen the JFrame will instead contain a JWindow which will contain the
- * JPanel and Canvas3D.
- */
- JFrame j3dJFrame ;
-
- /**
- * The Window created for this ConfigScreen. Under JDK 1.4 or higher this
- * is the same reference as j3dJFrame. If a borderless full screen is
- * specified while running under JDK 1.3.1 then this is a JWindow with the
- * j3dJFrame as its parent.
- */
- Window j3dWindow ;
-
- /**
- * The JPanel created for this ConfigScreen to hold the Canvas3D.
- */
- JPanel j3dJPanel ;
-
- /**
- * The Canvas3D created for this ConfigScreen.
- */
- Canvas3D j3dCanvas ;
-
- /**
- * Processes attributes for this object. Handles commands of the form:
- * (ScreenAttribute {instanceName} {attrName} {attrValue})
- * (ScreenProperty {instanceName} {attrName} {attrValue})
- * (DisplayAttribute {instanceName} {attrName} {attrValue})
- * (DisplayProperty {instanceName} {attrName} {attrValue})
- *
- * @param command the command that invoked this method
- */
- @Override
- protected void setProperty(ConfigCommand command) {
-
- String attr = null ;
- Object val = null ;
- String sval = null ;
-
- if (command.argc != 4) {
- syntaxError("Incorrect number of arguments to " +
- command.commandName) ;
- }
-
- if (!isName(command.argv[2])) {
- syntaxError("The second argument to " + command.commandName +
- " must be a property name") ;
- }
-
- attr = (String)command.argv[2] ;
- val = command.argv[3] ;
-
- if (attr.equals("PhysicalScreenWidth")) {
- if (!(val instanceof Double)) {
- syntaxError("Value for PhysicalScreenWidth " +
- "must be a number") ;
- }
- physicalScreenWidth = ((Double)val).doubleValue() ;
- }
- else if (attr.equals("PhysicalScreenHeight")) {
- if (!(val instanceof Double)) {
- syntaxError("Value for PhysicalScreenHeight " +
- "must be a number") ;
- }
- physicalScreenHeight = ((Double)val).doubleValue() ;
- }
- else if (attr.equals("TrackerBaseToImagePlate")) {
- if (!(val instanceof Matrix4d)) {
- syntaxError("Value for TrackerBaseToImagePlate " +
- "must be a 4x3 or 4x4 matrix") ;
- }
- trackerBaseToImagePlate = (Matrix4d)val ;
- }
- else if (attr.equals("HeadTrackerToLeftImagePlate")) {
- if (!(val instanceof Matrix4d)) {
- syntaxError("Value for HeadTrackerToLeftImagePlate "
- + "must be a 4x3 or 4x4 matrix") ;
- }
- headTrackerToLeftImagePlate = (Matrix4d)val ;
- }
- else if (attr.equals("HeadTrackerToRightImagePlate")) {
- if (!(val instanceof Matrix4d)) {
- syntaxError("Value for HeadTrackerToRightImagePlate "
- + "must be a 4x3 or 4x4 matrix") ;
- }
- headTrackerToRightImagePlate = (Matrix4d)val ;
- }
- else if (attr.equals("MonoscopicViewPolicy")) {
- if (!(val instanceof String)) {
- syntaxError("Value for MonoscopicViewPolicy " +
- "must be a name") ;
- }
- sval = (String)val ;
- if (sval.equals("LEFT_EYE_VIEW"))
- monoscopicViewPolicy = View.LEFT_EYE_VIEW ;
- else if (sval.equals("RIGHT_EYE_VIEW"))
- monoscopicViewPolicy = View.RIGHT_EYE_VIEW ;
- else if (sval.equals("CYCLOPEAN_EYE_VIEW"))
- monoscopicViewPolicy = View.CYCLOPEAN_EYE_VIEW ;
- else
- syntaxError("Invalid value for MonoscopicViewPolicy "
- + "\"" + sval + "\"") ;
- }
- else if (attr.equals("WindowPosition")) {
- if (! (val instanceof Point2d)) {
- syntaxError("WindowPosition must be a Point2d") ;
- }
- Point2d p2d = (Point2d)val ;
- windowX = (int)p2d.x ;
- windowY = (int)p2d.y ;
- }
- else if (attr.equals("WindowSize")) {
- if (val instanceof Point2d) {
- fullScreen = false ;
- noBorderFullScreen = false ;
-
- Point2d p2d = (Point2d)val ;
- windowWidthInPixels = (int)p2d.x ;
- windowHeightInPixels = (int)p2d.y ;
- }
- else if (val instanceof String) {
- String s = (String)val ;
-
- if (s.equals("FullScreen")) {
- fullScreen = true ;
- noBorderFullScreen = false ;
- } else if (s.equals("NoBorderFullScreen")) {
- fullScreen = false ;
- noBorderFullScreen = true ;
- } else {
- syntaxError("Value for WindowSize " +
- "must be one of\n" + "\"FullScreen\" " +
- "\"NoBorderFullScreen\" or Point2d") ;
- }
- }
- else {
- syntaxError("Invalid WindowSize value: " + val +
- "\nValue for WindowSize " +
- "must be one of\n" + "\"FullScreen\" " +
- "\"NoBorderFullScreen\" or Point2d") ;
- }
- }
- else {
- syntaxError("Unknown " + command.commandName +
- " \"" + attr + "\"") ;
- }
- }
-
- /**
- * Initializes this object. Handles commands of the form:
- * (NewScreen {instanceName} {FrameBufferNumber}).
- *
- * @param command the command that invoked this method
- */
- @Override
- protected void initialize(ConfigCommand command) {
- if (command.argc != 3) {
- syntaxError("Incorrect number of arguments to " +
- command.commandName) ;
- }
-
- if (!(command.argv[2] instanceof Double)) {
- syntaxError("The second argument to " + command.commandName +
- " must be a GraphicsDevice index") ;
- }
-
- frameBufferNumber = ((Double)command.argv[2]).intValue() ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfigSensor.java b/src/classes/share/com/sun/j3d/utils/universe/ConfigSensor.java
deleted file mode 100644
index ba3a407..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfigSensor.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe ;
-
-import javax.media.j3d.Sensor;
-import javax.vecmath.Point3d;
-
-class ConfigSensor extends ConfigObject {
-
- // The index of this sensor in the associated InputDevice.
- private int sensorIndex ;
-
- // The ConfigDevice which creates the associated InputDevice.
- private ConfigDevice configDevice ;
-
- // All configurable attributes.
- private Point3d hotspot = null ;
- private int predictor = -1 ;
- private int predictionPolicy = -1 ;
- private int sensorReadCount = -1 ;
-
- /**
- * The corresponding Java 3D core Sensor instance. This is created by the
- * associated InputDevice.
- */
- Sensor j3dSensor ;
-
- /**
- * Handles the command
- * (NewSensor {instanceName} {inputDeviceName} {indexInInputDevice})
- *
- * @param command the command that invoked this method
- */
- @Override
- protected void initialize(ConfigCommand command) {
-
- int argc = command.argc ;
- Object[] argv = command.argv ;
-
- // Check that arg[1] and arg[2] are strings, arg[3] a number
- if (argc != 4) {
- syntaxError("Incorrect number of arguments to " +
- command.commandName) ;
- }
-
- if (!isName(argv[2])) {
- syntaxError("The second argument to " + command.commandName +
- " must be the device name") ;
- }
-
- if (!(argv[3] instanceof Double)) {
- syntaxError("The third argument to " + command.commandName +
- " must be a sensor index") ;
- }
-
- sensorIndex = ((Double)argv[3]).intValue() ;
- configDevice = (ConfigDevice)configContainer.findConfigObject
- ("Device", (String)argv[2]) ;
- }
-
- /**
- * Handles the commands
- * (SensorAttribute {instanceName} {attributeName} {attributeValue}) and
- * (SensorProperty {instanceName} {attributeName} {attributeValue}).
- *
- * @param command the command that invoked this method
- */
- @Override
- protected void setProperty(ConfigCommand command) {
-
- int argc = command.argc ;
- Object[] argv = command.argv ;
- String attribute ;
-
- // Check that arg[1] and arg[2] are strings
- if (argc != 4) {
- syntaxError("Incorrect number of arguments to " +
- command.commandName) ;
- }
-
- if (! isName(argv[1])) {
- syntaxError("The first argument to " + command.commandName +
- " must be the instance name") ;
- }
-
- if (! isName(argv[2])) {
- syntaxError("The second argument to " + command.commandName +
- " must be a property name") ;
- }
-
- attribute = (String)argv[2] ;
- if (attribute.equals("Hotspot")) {
- if (! (argv[3] instanceof Point3d)) {
- syntaxError("Hotspot must be a 3D point") ;
- }
- hotspot = (Point3d)argv[3] ;
- }
- /*
- * Questionable attributes. Commented out for now.
- else if (attribute.equals("Predictor")) {
- if (! isName(argv[3])) {
- syntaxError("Predictor must be a name") ;
- }
-
- String predictorName = (String)argv[3] ;
- if (predictorName.equals("PREDICT_NONE")) {
- predictor = Sensor.PREDICT_NONE ;
- }
- else if (predictorName.equals("PREDICT_NEXT_FRAME_TIME")) {
- predictor = Sensor.PREDICT_NEXT_FRAME_TIME ;
- }
- else {
- syntaxError("Predictor must be either PREDICT_NONE " +
- "or PREDICT_NEXT_FRAME_TIME") ;
- }
- }
- else if (attribute.equals("PredictionPolicy")) {
- if (! isName(argv[3])) {
- syntaxError("PredictionPolicy must be a name") ;
- }
-
- String predictionPolicyName = (String)argv[3] ;
- if (predictionPolicyName.equals("NO_PREDICTOR")) {
- predictionPolicy = Sensor.NO_PREDICTOR ;
- }
- else if (predictionPolicyName.equals("HEAD_PREDICTOR")) {
- predictionPolicy = Sensor.HEAD_PREDICTOR ;
- }
- else if (predictionPolicyName.equals("HAND_PREDICTOR")) {
- predictionPolicy = Sensor.HAND_PREDICTOR ;
- }
- else {
- syntaxError("PredictionPolicy must be either NO_PREDICTOR, " +
- "HEAD_PREDICTOR, or HAND_PREDICTOR") ;
- }
- }
- else if (attribute.equals("SensorReadCount")) {
- if (! (argv[3] instanceof Double)) {
- syntaxError("SensorReadCount must be a number") ;
- }
- sensorReadCount = ((Double)argv[3]).intValue() ;
- }
- */
- else {
- syntaxError("Unknown " + command.commandName +
- " \"" + attribute + "\"") ;
- }
- }
-
- /**
- * This method is called after all InputDevice implementations have been
- * instantiated and initialized. All the specified attributes for this
- * sensor are set in the corresponding Java3D core Sensor instantiated by
- * the associated InputDevice.
- */
- void configureSensor() {
- j3dSensor = configDevice.j3dInputDevice.getSensor(sensorIndex) ;
-
- if (hotspot != null)
- j3dSensor.setHotspot(hotspot) ;
-
- if (predictor != -1)
- j3dSensor.setPredictor(predictor) ;
-
- if (predictionPolicy != -1)
- j3dSensor.setPredictionPolicy(predictionPolicy) ;
-
- if (sensorReadCount != -1)
- j3dSensor.setSensorReadCount(sensorReadCount) ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfigSexpression.java b/src/classes/share/com/sun/j3d/utils/universe/ConfigSexpression.java
deleted file mode 100644
index 7673343..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfigSexpression.java
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe ;
-
-import java.io.IOException;
-import java.io.StreamTokenizer;
-import java.util.ArrayList;
-
-import javax.media.j3d.BoundingSphere;
-import javax.media.j3d.Transform3D;
-import javax.vecmath.Matrix3d;
-import javax.vecmath.Matrix4d;
-import javax.vecmath.Point2d;
-import javax.vecmath.Point3d;
-import javax.vecmath.Point4d;
-import javax.vecmath.Vector3d;
-
-class ConfigSexpression {
-
- private ArrayList elements = new ArrayList() ;
-
- private void syntaxError(StreamTokenizer st, String file, String s) {
- System.out.println(s + ":\nat line " + st.lineno() + " in " + file) ;
- print() ; System.out.print("\n\n") ;
- }
-
- private int myNextToken(StreamTokenizer st, String file) {
- int tok = 0 ;
- try {
- tok = st.nextToken() ;
- }
- catch (IOException e) {
- throw new RuntimeException(e + "\nwhile reading " + file) ;
- }
- return tok ;
- }
-
-
- Object parseAndEval(ConfigContainer configContainer,
- StreamTokenizer st, int level) {
- int tok ;
- String s ;
- String file = configContainer.currentFileName ;
-
- //
- // First tokenize the character stream and add the tokens to the
- // elements array.
- //
- elements.clear() ;
-
- // Look for an open paren to start this sexp.
- while (true) {
- tok = myNextToken(st, file) ;
-
- if (tok == StreamTokenizer.TT_EOF)
- return Boolean.FALSE ;
-
- if (tok == ')')
- syntaxError(st, file, "Premature closing parenthesis") ;
-
- if (tok == '(')
- break ;
- }
-
- // Add elements until a close paren for this sexp is found.
- for (int i = 0 ; true ; i++) {
- tok = myNextToken(st, file) ;
-
- if (tok == StreamTokenizer.TT_EOF) {
- syntaxError(st, file, "Missing closing parenthesis") ;
- break ;
- }
-
- // An open paren starts a new embedded sexp. Put the paren back,
- // evaluate the sexp, and add the result to the elements list.
- if (tok == '(') {
- st.pushBack() ;
- ConfigSexpression cs = new ConfigSexpression() ;
- elements.add(cs.parseAndEval(configContainer, st, level+1)) ;
- continue ;
- }
-
- // A close paren finishes the scan.
- if (tok == ')')
- break ;
-
- // Check for too many arguments.
- if (i >= 20)
- syntaxError(st, file, "Too many arguments") ;
-
- // Check for numeric argument.
- if (tok == StreamTokenizer.TT_NUMBER) {
- elements.add(new Double(st.nval)) ;
- continue ;
- }
-
- // Anything other than a word or a quoted string is an error.
- if (tok != StreamTokenizer.TT_WORD && tok != '"' && tok != '\'') {
- String badToken = String.valueOf((char)tok) ;
- elements.add(badToken) ; // so bad token prints out
- syntaxError(st, file, "Invalid token \"" + badToken +
- "\" must be enclosed in quotes") ;
- continue ;
- }
-
- // Scan the token for Java property substitution syntax ${...}.
- s = scanJavaProperties(st, file, st.sval) ;
- if (s == null) continue ;
-
- if (s.equalsIgnoreCase("true"))
- // Replace "true" or "True" with the Boolean equivalent.
- elements.add(new Boolean(true)) ;
-
- else if (s.equalsIgnoreCase("false"))
- // Replace "false" or "False" with the Boolean equivalent.
- elements.add(new Boolean(false)) ;
-
- else
- // Add the token as a string element.
- elements.add(s) ;
- }
-
-
- //
- // Now evaluate elements.
- //
- if (elements.size() == 0)
- syntaxError(st, file, "Null command") ;
-
- // If the first argument is a string, then this sexp must be
- // a top-level command or a built-in, and needs to be evaluated.
- if (elements.get(0) instanceof String) {
- try {
- if (level == 0) {
- configContainer.evaluateCommand(elements, st.lineno()) ;
-
- // Continue parsing top-level commands.
- return Boolean.TRUE ;
- }
- else {
- // Evaluate built-in and return result to next level up.
- return evaluateBuiltIn
- (configContainer, elements, st.lineno()) ;
- }
- }
- catch (IllegalArgumentException e) {
- syntaxError(st, file, e.getMessage()) ;
- if (level == 0)
- // Command ignored: continue parsing.
- return Boolean.TRUE ;
- else
- // Function ignored: return sexp to next level up so error
- // processing can print it out in context of command.
- return this ;
- }
- }
-
- // If the first argument isn't a string, and we are at level 0,
- // this is a syntax error.
- if (level == 0)
- syntaxError(st, file, "Malformed top-level command name") ;
-
- // If the first argument is a number, then we must have
- // either a 2D, 3D, or 4D numeric vector.
- if (elements.get(0) instanceof Double) {
- if (elements.size() == 1)
- syntaxError(st, file, "Can't have single-element vector") ;
-
- // Point2D
- if (elements.size() == 2) {
- if (!(elements.get(1) instanceof Double))
- syntaxError(st, file, "Both elements must be numbers") ;
-
- return new Point2d(((Double)elements.get(0)).doubleValue(),
- ((Double)elements.get(1)).doubleValue()) ;
- }
-
- // Point3d
- if (elements.size() == 3) {
- if (!(elements.get(1) instanceof Double) ||
- !(elements.get(2) instanceof Double))
- syntaxError(st, file, "All elements must be numbers") ;
-
- return new Point3d(((Double)elements.get(0)).doubleValue(),
- ((Double)elements.get(1)).doubleValue(),
- ((Double)elements.get(2)).doubleValue()) ;
- }
-
- // Point4D
- if (elements.size() == 4) {
- if (!(elements.get(1) instanceof Double) ||
- !(elements.get(2) instanceof Double) ||
- !(elements.get(3) instanceof Double))
- syntaxError(st, file, "All elements must be numbers") ;
-
- return new Point4d(((Double)elements.get(0)).doubleValue(),
- ((Double)elements.get(1)).doubleValue(),
- ((Double)elements.get(2)).doubleValue(),
- ((Double)elements.get(3)).doubleValue()) ;
- }
-
- // Anything else is an error.
- syntaxError(st, file, "Too many vector elements") ;
- }
-
- // If the first argument is a Point3d, then we should be a Matrix3d.
- if (elements.get(0) instanceof Point3d) {
- if (elements.size() != 3)
- syntaxError(st, file, "Matrix must have three rows") ;
-
- if (!(elements.get(1) instanceof Point3d) ||
- !(elements.get(2) instanceof Point3d))
- syntaxError(st, file, "All rows must have three elements") ;
-
- return new Matrix3d(((Point3d)elements.get(0)).x,
- ((Point3d)elements.get(0)).y,
- ((Point3d)elements.get(0)).z,
- ((Point3d)elements.get(1)).x,
- ((Point3d)elements.get(1)).y,
- ((Point3d)elements.get(1)).z,
- ((Point3d)elements.get(2)).x,
- ((Point3d)elements.get(2)).y,
- ((Point3d)elements.get(2)).z) ;
- }
-
- // If the first argument is a Point4d, then we should be a Matrix4d.
- if (elements.get(0) instanceof Point4d) {
- if (elements.size() == 3) {
- if (!(elements.get(1) instanceof Point4d) ||
- !(elements.get(2) instanceof Point4d))
- syntaxError(st, file, "All rows must have four elements") ;
-
- return new Matrix4d(((Point4d)elements.get(0)).x,
- ((Point4d)elements.get(0)).y,
- ((Point4d)elements.get(0)).z,
- ((Point4d)elements.get(0)).w,
- ((Point4d)elements.get(1)).x,
- ((Point4d)elements.get(1)).y,
- ((Point4d)elements.get(1)).z,
- ((Point4d)elements.get(1)).w,
- ((Point4d)elements.get(2)).x,
- ((Point4d)elements.get(2)).y,
- ((Point4d)elements.get(2)).z,
- ((Point4d)elements.get(2)).w,
- 0.0, 0.0, 0.0, 1.0) ;
- }
- else if (elements.size() != 4)
- syntaxError(st, file, "Matrix must have three or four rows") ;
-
- if (!(elements.get(1) instanceof Point4d) ||
- !(elements.get(2) instanceof Point4d) ||
- !(elements.get(3) instanceof Point4d))
- syntaxError(st, file, "All rows must have four elements") ;
-
- return new Matrix4d(((Point4d)elements.get(0)).x,
- ((Point4d)elements.get(0)).y,
- ((Point4d)elements.get(0)).z,
- ((Point4d)elements.get(0)).w,
- ((Point4d)elements.get(1)).x,
- ((Point4d)elements.get(1)).y,
- ((Point4d)elements.get(1)).z,
- ((Point4d)elements.get(1)).w,
- ((Point4d)elements.get(2)).x,
- ((Point4d)elements.get(2)).y,
- ((Point4d)elements.get(2)).z,
- ((Point4d)elements.get(2)).w,
- ((Point4d)elements.get(3)).x,
- ((Point4d)elements.get(3)).y,
- ((Point4d)elements.get(3)).z,
- ((Point4d)elements.get(3)).w) ;
- }
-
- // Anything else is an error.
- syntaxError(st, file, "Syntax error") ;
- return null ;
- }
-
- /**
- * Scan for Java properties in the specified string. Nested properties are
- * not supported.
- *
- * @param st stream tokenizer in use
- * @param f current file name
- * @param s string containing non-nested Java properties possibly
- * interspersed with arbitrary text.
- * @return scanned string with Java properties replaced with values
- */
- private String scanJavaProperties(StreamTokenizer st, String f, String s) {
- int open = s.indexOf("${") ;
- if (open == -1) return s ;
-
- int close = 0 ;
- StringBuffer buf = new StringBuffer() ;
- while (open != -1) {
- buf.append(s.substring(close, open)) ;
- close = s.indexOf('}', open) ;
- if (close == -1) {
- elements.add(s) ; // so that the bad element prints out
- syntaxError(st, f, "Java property substitution syntax error") ;
- return null ;
- }
-
- String property = s.substring(open + 2, close) ;
- String value = ConfigCommand.evaluateJavaProperty(property) ;
- if (value == null) {
- elements.add(s) ; // so that the bad element prints out
- syntaxError(st, f, "Java property \"" + property +
- "\" has a null value") ;
- return null ;
- }
-
- buf.append(value) ;
- open = s.indexOf("${", close) ;
- close++ ;
- }
-
- buf.append(s.substring(close)) ;
- return buf.toString() ;
- }
-
- /**
- * This method gets called from the s-expression parser to evaluate a
- * built-in command.
- *
- * @param elements tokenized list of sexp elements
- * @return object representing result of evaluation
- */
- private Object evaluateBuiltIn(ConfigContainer configContainer,
- ArrayList elements, int lineNumber) {
- int argc ;
- String functionName ;
-
- argc = elements.size() ;
- functionName = (String)elements.get(0) ;
-
- if (functionName.equals("Rotate")) {
- return makeRotate(elements) ;
- }
- else if (functionName.equals("Translate")) {
- return makeTranslate(elements) ;
- }
- else if (functionName.equals("RotateTranslate") ||
- functionName.equals("TranslateRotate") ||
- functionName.equals("Concatenate")) {
-
- return concatenate(elements) ;
- }
- else if (functionName.equals("BoundingSphere")) {
- return makeBoundingSphere(elements) ;
- }
- else {
- // This built-in can't be evaluated immediately or contains an
- // unknown command. Create a ConfigCommand for later evaluation.
- return new ConfigCommand
- (elements, configContainer.currentFileName, lineNumber) ;
- }
- }
-
- /**
- * Processes the built-in command (Translate x y z).
- *
- * @param elements ArrayList containing Doubles wrapping x, y, and z
- * translation components at indices 1, 2, and 3 respectively
- *
- * @return matrix that translates by the given x, y, and z components
- */
- private Matrix4d makeTranslate(ArrayList elements) {
- if (elements.size() != 4) {
- throw new IllegalArgumentException
- ("Incorrect number of arguments to Translate") ;
- }
-
- if (!(elements.get(1) instanceof Double) ||
- !(elements.get(2) instanceof Double) ||
- !(elements.get(3) instanceof Double)) {
- throw new IllegalArgumentException
- ("All arguments to Translate must be numbers") ;
- }
-
- Matrix4d m4d = new Matrix4d() ;
- m4d.set(new Vector3d(((Double)elements.get(1)).doubleValue(),
- ((Double)elements.get(2)).doubleValue(),
- ((Double)elements.get(3)).doubleValue())) ;
-
- return m4d ;
- }
-
- /**
- * Processes the (Rotate x y z) built-in command.
- *
- * @param elements ArrayList containing Doubles wrapping x, y, and z Euler
- * angles at indices 1, 2, and 3 respectively
- *
- * @return matrix that rotates by the given Euler angles around static X,
- * Y, and Z basis vectors: first about X, then Y, and then Z
- *
- * @see Transform3D#setEuler()
- */
- private Matrix4d makeRotate(ArrayList elements) {
- if (elements.size() != 4) {
- throw new IllegalArgumentException
- ("Incorrect number of arguments to Rotate") ;
- }
-
- if (!(elements.get(1) instanceof Double) ||
- !(elements.get(2) instanceof Double) ||
- !(elements.get(3) instanceof Double)) {
- throw new IllegalArgumentException
- ("All arguments to Rotate must be numbers") ;
- }
-
- double x = Math.toRadians(((Double)elements.get(1)).doubleValue()) ;
- double y = Math.toRadians(((Double)elements.get(2)).doubleValue()) ;
- double z = Math.toRadians(((Double)elements.get(3)).doubleValue()) ;
-
- Transform3D t3d = new Transform3D() ;
- t3d.setEuler(new Vector3d(x, y, z)) ;
-
- Matrix4d m4d = new Matrix4d() ;
- t3d.get(m4d) ;
-
- return m4d ;
- }
-
- /**
- * Processes the (RotateTranslate m1 m2), (TranslateRotate m1 m2), and
- * (Concatenate m1 m2) built-in commands. Although these do exactly the
- * same thing, using the appropriate command is recommended in order to
- * explicitly describe the sequence of transforms and their intent.
- *
- * @param elements ArrayList containing Matrix4d objects m1 and m2 at
- * indices 1 and 2 respectively
- *
- * @return matrix that concatenates m1 and m2 in that order: if a point is
- * transformed by the resulting matrix, then in effect the points are
- * first transformed by m1 and then m2
- */
- private Matrix4d concatenate(ArrayList elements) {
- String functionName = (String)elements.get(0) ;
-
- if (elements.size() != 3) {
- throw new IllegalArgumentException
- ("Incorrect number of arguments to " + functionName) ;
- }
-
- if (!(elements.get(1) instanceof Matrix4d) ||
- !(elements.get(2) instanceof Matrix4d)) {
- throw new IllegalArgumentException
- ("Both arguments to " + functionName + " must be Matrix4d") ;
- }
-
- // Multiply the matrices in the order such that the result, when
- // transforming a 3D point, will apply the transform represented by
- // the 1st matrix and then apply the transform represented by the 2nd
- // matrix.
- Matrix4d m4d = new Matrix4d((Matrix4d)elements.get(2)) ;
- m4d.mul((Matrix4d)elements.get(1)) ;
-
- return m4d ;
- }
-
- /**
- * Processes the built-in command (BoundingSphere center radius).
- * This is used when configuring behaviors.
- *
- * @param elements ArrayList containing Point3d at index 1 for the sphere
- * center and Double at index 2 wrapping the sphere radius, or the String
- * "infinite" at index 2.
- *
- * @return BoundingSphere with the given center and radius
- */
- private BoundingSphere makeBoundingSphere(ArrayList elements) {
- if (elements.size() != 3) {
- throw new IllegalArgumentException
- ("Incorrect number of arguments to BoundingSphere") ;
- }
-
- if (! (elements.get(1) instanceof Point3d) ||
- ! (elements.get(2) instanceof Double ||
- elements.get(2) instanceof String))
- throw new IllegalArgumentException
- ("BoundingSphere needs a Point3d center " +
- "followed by a Double radius or the String \"infinite\"") ;
-
- double r ;
- if (elements.get(2) instanceof Double)
- r = ((Double)elements.get(2)).doubleValue() ;
- else
- r = Double.POSITIVE_INFINITY ;
-
- return new BoundingSphere((Point3d)elements.get(1), r) ;
- }
-
- void print() {
- System.out.print("(") ;
- int argc = elements.size() ;
- for (int i = 0 ; i < argc ; i++) {
- if (elements.get(i) instanceof Matrix3d) {
- String[] rows = ConfigCommand.formatMatrixRows
- ((Matrix3d)elements.get(i)) ;
- System.out.println("\n ((" + rows[0] + ")") ;
- System.out.println(" (" + rows[1] + ")") ;
- System.out.print(" (" + rows[2] + "))") ;
- if (i != (argc - 1)) System.out.println() ;
- }
- else if (elements.get(i) instanceof Matrix4d) {
- String[] rows = ConfigCommand.formatMatrixRows
- ((Matrix4d)elements.get(i)) ;
- System.out.println("\n ((" + rows[0] + ")") ;
- System.out.println(" (" + rows[1] + ")") ;
- System.out.println(" (" + rows[2] + ")") ;
- System.out.print(" (" + rows[3] + "))") ;
- if (i != (argc - 1)) System.out.println() ;
- }
- else if (elements.get(i) instanceof ConfigSexpression) {
- if (i > 0) System.out.print(" ") ;
- ((ConfigSexpression)elements.get(i)).print() ;
- if (i != (argc - 1)) System.out.println() ;
- }
- else if (elements.get(i) instanceof ConfigCommand) {
- if (i > 0) System.out.print(" ") ;
- System.out.print(elements.get(i).toString()) ;
- if (i != (argc - 1)) System.out.println() ;
- }
- else {
- if (i > 0) System.out.print(" ") ;
- System.out.print(elements.get(i).toString()) ;
- }
- }
- System.out.print(")") ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfigView.java b/src/classes/share/com/sun/j3d/utils/universe/ConfigView.java
deleted file mode 100644
index 00a3c0b..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfigView.java
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe ;
-
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import javax.media.j3d.PhysicalBody;
-import javax.media.j3d.PhysicalEnvironment;
-import javax.media.j3d.View;
-import javax.vecmath.Point3d;
-
-class ConfigView extends ConfigObject {
- /**
- * The corresponding View and Viewer instances. These are set when
- * createJ3dView() is called after parsing the configuration file.
- */
- View j3dView = null ;
- Viewer j3dViewer = null ;
-
- /**
- * Set of ConfigScreen instances added to this view.
- */
- Set screens = new HashSet() ;
-
- /**
- * Indicates whether or not stereo viewing should be enabled for this
- * ConfigView. This is set during parsing of the configuration file.
- */
- boolean stereoEnable = false ;
-
- /**
- * Indicates whether or not antialiasing is enabled for this ConfigView.
- * This is set during parsing of the configuration file.
- */
- boolean antialiasingEnable = false;
-
- /**
- * Reference to the PhysicalBody associated with this ConfigView. This is
- * set when createJ3dView() is called after parsing the configuration
- * file.
- */
- PhysicalBody physicalBody = null ;
-
- /**
- * Reference to the PhysicalEnvironment associated with this ConfigView.
- * This is set when createJ3dView() is called after parsing the
- * configuration file.
- */
- PhysicalEnvironment physicalEnvironment = null ;
-
- // All other configurable attributes.
- private double fieldOfView = Math.PI/4.0 ;
- private int backClipPolicy = View.PHYSICAL_EYE ;
- private int frontClipPolicy = View.PHYSICAL_EYE ;
- private double backClipDistance = 10.0 ;
- private double frontClipDistance = 0.1 ;
- private int screenScalePolicy = View.SCALE_SCREEN_SIZE ;
- private double screenScale = 1.0 ;
- private boolean trackingEnable = false ;
- private int viewPolicy = View.SCREEN_VIEW ;
- private int windowEyepointPolicy = -1 ;
- private int windowMovementPolicy = -1 ;
- private int windowResizePolicy = -1 ;
- private boolean coeCenteringEnableSet = false ;
- private boolean coeCenteringEnable = false ;
- private Point3d centerEyeInCoexistence = null ;
-
- private ConfigPhysicalBody configBody = null ;
- private ConfigPhysicalEnvironment configEnv = null ;
- private ConfigViewPlatform configViewPlatform = null ;
-
- /**
- * Overrides initialize() to do nothing.
- */
- @Override
- protected void initialize(ConfigCommand command) {
- }
-
- /**
- * Processes properties for this object. Handles commands of the form:
- * (ViewAttribute {instanceName} {attrName} {attrValue})
- *
- * @param command the command that invoked this method
- */
- @Override
- protected void setProperty(ConfigCommand command) {
-
- int argc = command.argc ;
- Object[] argv = command.argv ;
- String attr = null ;
- Object val = null ;
- String sval = null ;
- ConfigScreen cs = null ;
-
- // Check that arg[1] and arg[2] are strings
- if (argc != 4) {
- syntaxError("Incorrect number of arguments to " +
- command.commandName) ;
- }
-
- if (!isName(argv[1])) {
- syntaxError("The first argument to " + command.commandName +
- " must be the instance name") ;
- }
-
- if (!isName(argv[2])) {
- syntaxError("The second argument to " + command.commandName +
- " must be a property name") ;
- }
-
- attr = (String) argv[2] ;
- val = argv[3] ;
-
- if (attr.equals("Screen") || attr.equals("Window")) {
- if (!(val instanceof String)) {
- syntaxError("Value for " + attr + " must be a name") ;
- }
- cs = (ConfigScreen)
- configContainer.findConfigObject("Screen", (String)val) ;
-
- if (!screens.add(cs)) {
- syntaxError(attr + " \"" + ((String)val) +
- "\" has already been added to " + instanceName) ;
- }
- }
- else if (attr.equals("ViewPlatform")) {
- if (!(val instanceof String)) {
- syntaxError("value for ViewPlatform " +
- " must be an instance name") ;
- }
- configViewPlatform =
- (ConfigViewPlatform)configContainer.findConfigObject
- ("ViewPlatform", (String)val) ;
-
- configViewPlatform.addConfigView(this) ;
- }
- else if (attr.equals("PhysicalEnvironment")) {
- if (!(val instanceof String)) {
- syntaxError("value for PhysicalEnvironment " +
- "must be an instance name") ;
- }
- configEnv =
- (ConfigPhysicalEnvironment)configContainer.findConfigObject
- ("PhysicalEnvironment", (String)val) ;
- }
- else if (attr.equals("PhysicalBody")) {
- if (!(val instanceof String)) {
- syntaxError("value for PhysicalBody " +
- "must be an instance name") ;
- }
- configBody = (ConfigPhysicalBody)
- configContainer.findConfigObject("PhysicalBody", (String)val) ;
- }
- else if (attr.equals("BackClipPolicy")) {
- if (!(val instanceof String)) {
- syntaxError("value for BackClipPolicy must be a string") ;
- }
- sval = (String) val ;
- if (sval.equals("PHYSICAL_EYE"))
- backClipPolicy = View.PHYSICAL_EYE ;
- else if (sval.equals("PHYSICAL_SCREEN"))
- backClipPolicy = View.PHYSICAL_SCREEN ;
- else if (sval.equals("VIRTUAL_EYE"))
- backClipPolicy = View.VIRTUAL_EYE ;
- else if (sval.equals("VIRTUAL_SCREEN"))
- backClipPolicy = View.VIRTUAL_SCREEN ;
- else
- syntaxError("Invalid value for BackClipPolicy " + sval) ;
- }
- else if (attr.equals("FrontClipPolicy")) {
- if (!(val instanceof String)) {
- syntaxError("value for FrontClipPolicy must be a string") ;
- }
- sval = (String) val ;
- if (sval.equals("PHYSICAL_EYE"))
- frontClipPolicy = View.PHYSICAL_EYE ;
- else if (sval.equals("PHYSICAL_SCREEN"))
- frontClipPolicy = View.PHYSICAL_SCREEN ;
- else if (sval.equals("VIRTUAL_EYE"))
- frontClipPolicy = View.VIRTUAL_EYE ;
- else if (sval.equals("VIRTUAL_SCREEN"))
- frontClipPolicy = View.VIRTUAL_SCREEN ;
- else
- syntaxError("Invalid value for FrontClipPolicy " + sval) ;
- }
- else if (attr.equals("ScreenScalePolicy")) {
- if (!(val instanceof String)) {
- syntaxError("value for ScreenScalePolicy must be a string") ;
- }
- sval = (String) val ;
- if (sval.equals("SCALE_SCREEN_SIZE"))
- screenScalePolicy = View.SCALE_SCREEN_SIZE ;
- else if (sval.equals("SCALE_EXPLICIT"))
- screenScalePolicy = View.SCALE_EXPLICIT ;
- else
- syntaxError("Invalid value for ScreenScalePolicy " + sval) ;
- }
- else if (attr.equals("FieldOfView")) {
- if (!(val instanceof Double)) {
- syntaxError("value for FieldOfView must be a number") ;
- }
- fieldOfView = ((Double)val).doubleValue() ;
- }
- else if (attr.equals("BackClipDistance")) {
- if (!(val instanceof Double)) {
- syntaxError("value for BackClipDistance must be a number") ;
- }
- backClipDistance = ((Double)val).doubleValue() ;
- }
- else if (attr.equals("FrontClipDistance")) {
- if (!(val instanceof Double)) {
- syntaxError("value for FrontClipDistance must be a number") ;
- }
- frontClipDistance = ((Double)val).doubleValue() ;
- }
- else if (attr.equals("ScreenScale")) {
- if (!(val instanceof Double)) {
- syntaxError("value for ScreenScale must be a number") ;
- }
- screenScale = ((Double)val).doubleValue() ;
- }
- else if (attr.equals("TrackingEnable")) {
- if (!(val instanceof Boolean)) {
- syntaxError("value for TrackingEnable must be a boolean") ;
- }
- trackingEnable = ((Boolean)val).booleanValue() ;
- }
- else if (attr.equals("CoexistenceCenteringEnable")) {
- if (!(val instanceof Boolean)) {
- syntaxError("value for CoexistenceCenteringEnable " +
- "must be a boolean") ;
- }
- coeCenteringEnable = ((Boolean)val).booleanValue() ;
- coeCenteringEnableSet = true ;
- }
- else if (attr.equals("ViewPolicy")) {
- if (!(val instanceof String)) {
- syntaxError("value for ViewPolicy must be a string") ;
- }
- sval = (String) val ;
- if (sval.equals("SCREEN_VIEW"))
- viewPolicy = View.SCREEN_VIEW ;
- else if (sval.equals("HMD_VIEW"))
- viewPolicy = View.HMD_VIEW ;
- else
- syntaxError("Invalid value for ViewPolicy " + sval) ;
- }
- else if (attr.equals("WindowEyepointPolicy")) {
- if (!(val instanceof String)) {
- syntaxError("value for WindowEyepointPolicy " +
- "must be a string") ;
- }
- sval = (String) val ;
- if (sval.equals("RELATIVE_TO_SCREEN"))
- windowEyepointPolicy = View.RELATIVE_TO_SCREEN ;
- else if (sval.equals("RELATIVE_TO_COEXISTENCE"))
- windowEyepointPolicy = View.RELATIVE_TO_COEXISTENCE ;
- else if (sval.equals("RELATIVE_TO_WINDOW"))
- windowEyepointPolicy = View.RELATIVE_TO_WINDOW ;
- else if (sval.equals("RELATIVE_TO_FIELD_OF_VIEW"))
- windowEyepointPolicy = View.RELATIVE_TO_FIELD_OF_VIEW ;
- else
- syntaxError("Invalid value for WindowEyepointPolicy " + sval) ;
- }
- else if (attr.equals("WindowMovementPolicy")) {
- if (!(val instanceof String)) {
- syntaxError("value for WindowEyeMovementPolicy " +
- "must be a string") ;
- }
- sval = (String) val ;
- if (sval.equals("VIRTUAL_WORLD"))
- windowMovementPolicy = View.VIRTUAL_WORLD ;
- else if (sval.equals("PHYSICAL_WORLD"))
- windowMovementPolicy = View.PHYSICAL_WORLD ;
- else
- syntaxError("Invalid value for WindowMovementPolicy " + sval) ;
- }
- else if (attr.equals("WindowResizePolicy")) {
- if (!(val instanceof String)) {
- syntaxError("value for WindowResizePolicy " +
- "must be a string") ;
- }
- sval = (String) val ;
- if (sval.equals("VIRTUAL_WORLD"))
- windowResizePolicy = View.VIRTUAL_WORLD ;
- else if (sval.equals("PHYSICAL_WORLD"))
- windowResizePolicy = View.PHYSICAL_WORLD ;
- else
- syntaxError("Invalid value for WindowResizePolicy " + sval) ;
- }
- else if (attr.equals("CenterEyeInCoexistence")) {
- if (val instanceof Point3d)
- centerEyeInCoexistence = (Point3d)val ;
- else
- syntaxError("value for CenterEyeInCoexistence " +
- "must be a Point3d") ;
- }
- else if (attr.equals("StereoEnable")) {
- if (!(val instanceof Boolean)) {
- syntaxError("value for StereoEnable must be a boolean") ;
- }
- stereoEnable = ((Boolean)val).booleanValue() ;
- }
- else if (attr.equals("AntialiasingEnable")) {
- if (!(val instanceof Boolean)) {
- syntaxError("value for AntialiasingEnable must be a boolean") ;
- }
- antialiasingEnable = ((Boolean)val).booleanValue() ;
- }
- else {
- syntaxError("Unknown " + command.commandName +
- " \"" + attr + "\"") ;
- }
- }
-
- /**
- * Create a core Java 3D View instance and a utility Viewer instance using
- * the attributes gathered by this object.
- */
- protected Viewer createViewer(boolean setVisible) {
- Point3d leftEyeCoe, rightEyeCoe ;
-
- j3dView = new View() ;
- j3dView.setViewPolicy(viewPolicy) ;
-
- if (configBody == null)
- physicalBody = new PhysicalBody() ;
- else
- physicalBody = configBody.j3dPhysicalBody ;
-
- if (configEnv == null)
- physicalEnvironment = new PhysicalEnvironment() ;
- else
- physicalEnvironment = configEnv.j3dPhysicalEnvironment ;
-
- j3dView.setPhysicalBody(physicalBody) ;
- j3dView.setPhysicalEnvironment(physicalEnvironment) ;
-
- boolean standardDefaults = true ;
- if (coeCenteringEnableSet && !coeCenteringEnable) {
- standardDefaults = false ;
- }
- if (configEnv != null && configEnv.coexistenceToTrackerBase != null) {
- standardDefaults = false ;
- }
- else {
- Iterator i = screens.iterator() ;
- while (i.hasNext()) {
- ConfigScreen s = (ConfigScreen)i.next() ;
- if (s.trackerBaseToImagePlate != null) {
- standardDefaults = false ;
- break ;
- }
- }
- }
-
- if (standardDefaults) {
- // Coexistence centering has not been explicitly set false, and
- // the tracker base to image plate and coexistence to tracker base
- // transforms are unset, so use the standard Java 3D defaults.
- if (windowEyepointPolicy == -1)
- windowEyepointPolicy = View.RELATIVE_TO_FIELD_OF_VIEW ;
- if (windowMovementPolicy == -1)
- windowMovementPolicy = View.PHYSICAL_WORLD ;
- if (windowResizePolicy == -1)
- windowResizePolicy = View.PHYSICAL_WORLD ;
- if (!coeCenteringEnableSet)
- coeCenteringEnable = true ;
- }
- else {
- // Use multi-screen or calibrated coexistence defaults.
- if (windowEyepointPolicy == -1)
- windowEyepointPolicy = View.RELATIVE_TO_COEXISTENCE ;
- if (windowMovementPolicy == -1)
- windowMovementPolicy = View.VIRTUAL_WORLD ;
- if (windowResizePolicy == -1)
- windowResizePolicy = View.VIRTUAL_WORLD ;
- if (!coeCenteringEnableSet)
- coeCenteringEnable = false ;
- }
-
- j3dView.setWindowEyepointPolicy(windowEyepointPolicy) ;
- j3dView.setWindowMovementPolicy(windowMovementPolicy) ;
- j3dView.setWindowResizePolicy(windowResizePolicy) ;
- j3dView.setCoexistenceCenteringEnable(coeCenteringEnable) ;
-
- if (centerEyeInCoexistence == null) {
- centerEyeInCoexistence = new Point3d(0.0, 0.0, 0.4572) ;
- }
-
- leftEyeCoe = new Point3d(centerEyeInCoexistence) ;
- rightEyeCoe = new Point3d(centerEyeInCoexistence) ;
-
- if (stereoEnable) {
- Point3d leftEyeBody = new Point3d() ;
- Point3d rightEyeBody = new Point3d() ;
-
- physicalBody.getLeftEyePosition(leftEyeBody) ;
- physicalBody.getRightEyePosition(rightEyeBody) ;
-
- leftEyeCoe.add(leftEyeBody) ;
- rightEyeCoe.add(rightEyeBody) ;
- }
-
- j3dView.setLeftManualEyeInCoexistence(leftEyeCoe) ;
- j3dView.setRightManualEyeInCoexistence(rightEyeCoe) ;
-
- j3dView.setBackClipPolicy(backClipPolicy) ;
- j3dView.setFrontClipPolicy(frontClipPolicy) ;
- j3dView.setBackClipDistance(backClipDistance) ;
- j3dView.setFrontClipDistance(frontClipDistance) ;
-
- j3dView.setScreenScalePolicy(screenScalePolicy) ;
- j3dView.setScreenScale(screenScale) ;
-
- j3dView.setFieldOfView(fieldOfView) ;
- j3dView.setTrackingEnable(trackingEnable) ;
- j3dView.setSceneAntialiasingEnable(antialiasingEnable) ;
-
- if (screens.size() == 0) {
- throw new IllegalStateException
- (errorMessage(creatingCommand, "View \"" + instanceName +
- "\" has no canvases or screens")) ;
- }
-
- ConfigScreen[] cs = new ConfigScreen[screens.size()] ;
- screens.toArray(cs) ;
-
- j3dViewer = new Viewer(cs, this, setVisible) ;
- return j3dViewer ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatform.java b/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatform.java
deleted file mode 100644
index 69320fb..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatform.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe ;
-
-import java.util.ArrayList;
-
-import javax.media.j3d.Node;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-import javax.media.j3d.View;
-import javax.media.j3d.ViewPlatform;
-import javax.vecmath.Matrix4d;
-
-class ConfigViewPlatform extends ConfigObject {
-
- private boolean allowPolicyRead = false ;
- private boolean allowLocalToVworldRead = false ;
- private boolean nominalViewingTransform = false ;
- private Transform3D initialViewingTransform = null ;
- private ArrayList configViews = new ArrayList() ;
- private Viewer[] viewers = null ;
-
- /**
- * The corresponding ViewingPlatform instance.
- */
- ViewingPlatform viewingPlatform = null ;
-
- /**
- * Indicates the view attach policy specified in the configuration file.
- * If none is set, it remains -1 even though a default may be in effect.
- */
- int viewAttachPolicy = -1 ;
-
- /**
- * The associated ConfigViewPlatformBehavior, if any.
- */
- ConfigViewPlatformBehavior configBehavior = null ;
-
- /**
- * Overrides initialize() to do nothing.
- */
- @Override
- protected void initialize(ConfigCommand command) {
- }
-
- /**
- * Processes attributes for this object. Handles commands of the form:
- * (ViewPlatformAttribute {instanceName} {attrName} {attrValue})
- * (ViewPlatformBehaviorProperty {instanceName} {attrName} {arg} ...)
- *
- * @param command the command that invoked this method
- */
- @Override
- protected void setProperty(ConfigCommand cmd) {
-
- int argc = cmd.argc ;
- Object[] argv = cmd.argv ;
-
- if (argc < 4) {
- syntaxError("Wrong number of arguments to " + cmd.commandName) ;
- }
-
- if (! isName(argv[2])) {
- syntaxError("The second argument to " + cmd.commandName +
- " must be a property name");
- }
-
- String attribute = (String)argv[2] ;
- if (attribute.equals("HomeTransform")) {
- if (! (argv[3] instanceof Matrix4d)) {
- syntaxError("HomeTransform must be a Matrix4d") ;
- }
- homeTransform = new Transform3D((Matrix4d)argv[3]) ;
- }
- else if (attribute.equals("SchedulingBounds")) {
- if (! (argv[3] instanceof Bounds)) {
- syntaxError("SchedulingBounds must be an instance of Bounds") ;
- }
- schedulingBounds = (Bounds)argv[3] ;
- }
- else if (attribute.equals("SchedulingInterval")) {
- if (! (argv[3] instanceof Double)) {
- syntaxError("SchedulingInterval must be a priority (number)") ;
- }
- schedulingInterval = ((Double)argv[3]).intValue() ;
- }
- else {
- // It's not any of the pre-defined attributes. Add it to the
- // properties list for the behavior instance itself to evaluate.
- properties.add(cmd) ;
- }
- }
-
- /**
- * Instantiate a ViewPlatformBehavior of the given class name.
- *
- * NOTE: All ConfigView and ConfigSensor objects must be processed before
- * calling this method.
- *
- * @return the configured ViewPlatformBehavior, or null if error
- */
- ViewPlatformBehavior createViewPlatformBehavior() {
-
- viewPlatformBehavior = (ViewPlatformBehavior)createTargetObject() ;
-
- // Set known attributes.
- if (homeTransform != null)
- viewPlatformBehavior.setHomeTransform(homeTransform) ;
-
- if (schedulingBounds != null)
- viewPlatformBehavior.setSchedulingBounds(schedulingBounds) ;
-
- if (schedulingInterval != -1)
- viewPlatformBehavior.setSchedulingInterval(schedulingInterval) ;
-
- // Unknown properties in the concrete instance are evaluated later.
- return viewPlatformBehavior ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfiguredUniverse.java b/src/classes/share/com/sun/j3d/utils/universe/ConfiguredUniverse.java
deleted file mode 100644
index 7b84b25..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfiguredUniverse.java
+++ /dev/null
@@ -1,789 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe;
-
-import java.net.URL;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
-
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.HiResCoord;
-import javax.media.j3d.Locale;
-import javax.media.j3d.View;
-
-/**
- * This utility class creates all the necessary objects on the view side of
- * the scene graph. Specifically, it creates a Locale, one or more
- * ViewingPlatforms, and at least one Viewer object.
- *
- * ConfiguredUniverse can set up a viewing environment based upon the contents
- * of a configuration file. This allows an application to run without change
- * across a broad range of viewing configurations, such as windows on
- * conventional desktops, stereo-enabled views, full screen immersive displays
- * on single or multiple screens, or virtual reality installations including
- * cave and head-mounted displays incorporating 6 degree of freedom sensor
- * devices.
- *
- * A configuration file may create InputDevice, Sensor, and
- * ViewPlatformBehavior instances as well as Viewers and ViewingPlatforms. At
- * least one Viewer must be provided by the configuration. If a
- * ViewingPlatform is not provided, a default one will be created and the
- * Viewer will be attached to it.
- *
- * A configuration file may be specified directly by passing a URL to a
- * ConfiguredUniverse constructor. Alternatively, a ConfigContainer may be
- * created from a configuration file first, and then passed to an appropriate
- * ConfiguredUniverse constructor. The latter technique allows Java system
- * properties that affect Java 3D to be specified in the configuration file,
- * as long as no references to a VirtualUniverse are made before creating the
- * container.
- *
- * If a configuration file or container is not provided, then
- * ConfiguredUniverse creates a default viewing environment in the same way as
- * SimpleUniverse. If one or more Canvas3D objects are provided, it will use
- * them instead of creating new ones. All of the constructors provided by
- * SimpleUniverse are also available here.
- *
- * The syntax and description of the configuration file may be found
- * here. Example config files can
- * be found here.
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see ConfigContainer
- * @see
- * The Java 3D Configuration File
- * @see
- * Example Configuration Files
- *
- * @since Java 3D 1.3
- */
-public class ConfiguredUniverse extends SimpleUniverse {
-
- /**
- * The configuration instance for this universe.
- */
- private ConfigContainer configContainer = null;
-
- /**
- * Equivalent to
- *
- * This constructor and
- *
- *
- *
- *
- *
- * @param visible boolean to be passed to the
- *
- * With the sole exception of the Sensor assigned to the head tracker,
- * none of the Sensors defined in the configuration file are placed into
- * the Sensor array maintained by PhysicalEnvironment. The head tracker
- * Sensor is the only one read by the Java 3D core and must generate reads
- * with a full 6 degrees of freedom (3D position and 3D orientation).
- *
- * Other Sensors need not generate reads with a full 6 degrees of freedom,
- * although their reads must be expressed using Transform3D. Some
- * joysticks may provide only 2D relative X and Y axis movement; dials,
- * levers, and sliders are 1D devices, and some devices may combine dials
- * and levers to generate 3D positional data.
- *
- * The index names to identify left / right / dominant / non-dominant hand
- * Sensors in the PhysicalEnvironement Sensor array are not adequate to
- * distinguish these differences, so this method allows applications to
- * look up Sensors based on the names bound to them in the configuration
- * file. There are no set rules on naming. Applications that use Sensors
- * may set up conventions for generic devices such as "mouse6D" or
- * "joystick2D" or specific product names.
- *
- * @return read-only Map which maps Sensor names to the associated Sensors,
- * or null if no Sensors have been named
- */
- public Map getNamedSensors() {
- if (configContainer == null)
- return null;
- else
- return configContainer.getNamedSensors();
- }
-
- /**
- * Returns all named ViewPlatformBehaviors defined by the configuration
- * file used to create the ConfiguredUniverse, if any. Equivalent
- * to
- *
- * @return read-only Map which maps behavior names to the associated
- * ViewPlatformBehavior instances, or null if none have been named.
- * @since Java 3D 1.3.1
- */
- public Map getNamedBehaviors() {
- if (configContainer == null)
- return null;
- else
- return configContainer.getNamedViewPlatformBehaviors();
- }
-
- /**
- * Returns a container holding all the objects defined by the
- * configuration file used to create the ConfiguredUniverse.
- *
- * @return the container
- * @since Java 3D 1.3.1
- */
- public ConfigContainer getConfigContainer() {
- return configContainer;
- }
-
- /**
- * Cleanup memory references used by ConfiguredUniverse.
- * @since Java 3D 1.3.1
- */
- @Override
- public void cleanup() {
- if (viewer != null) {
- for (int i = 0 ; i < viewer.length ; i++) {
- viewer[i].getView().removeAllCanvas3Ds();
- viewer[i].setViewingPlatform(null);
- viewer[i] = null;
- }
- }
-
- locale = null;
- removeAllLocales();
-
- configContainer.clear();
- configContainer = null;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/LocaleFactory.java b/src/classes/share/com/sun/j3d/utils/universe/LocaleFactory.java
deleted file mode 100644
index c00c030..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/LocaleFactory.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe;
-
-import javax.media.j3d.HiResCoord;
-import javax.media.j3d.Locale;
-import javax.media.j3d.VirtualUniverse;
-
-/**
- * This interface defines a factory for creating Locale objects in a
- * SimpleUniverse. Implementations of the createLocale methods in
- * this interface should construct a new Locale object from the
- * specified parameters. This class is used by the SimpleUniverse
- * class to construct the default Locale used to hold the view and
- * content branch graphs.
- *
- * @see Locale
- * @see ConfiguredUniverse
- * @see SimpleUniverse
- *
- * @since Java 3D 1.3
- */
-public interface LocaleFactory {
- /**
- * Creates a new Locale object at the specified high resolution
- * coordinate in the specified universe.
- *
- * @param universe the VirtualUniverse in which to create the Locale
- * @param hiRes the high resolution coordinate that defines the origin
- * of the Locale
- */
- public Locale createLocale(VirtualUniverse universe, HiResCoord hiRes);
-
- /**
- * Creates a new Locale object at (0, 0, 0) in the specified universe.
- *
- * @param universe the VirtualUniverse in which to create the Locale
- */
- public Locale createLocale(VirtualUniverse universe);
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/MultiTransformGroup.java b/src/classes/share/com/sun/j3d/utils/universe/MultiTransformGroup.java
deleted file mode 100644
index 173ebe3..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/MultiTransformGroup.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe;
-
-import javax.media.j3d.TransformGroup;
-
-/**
- * A convenience class that effectively creates a series of TransformGroup
- * nodes connected one to another hierarchically. For most applications,
- * creating a MultiTransformGroup containing one transform will suffice.
- * More sophisticated applications that use a complex portal/head tracking
- * viewing system may find that more transforms are needed.
- *
- * When more than one transform is needed, transform[0] is considered the
- * "top most" transform with repsect to the scene graph, (attached to the
- * ViewingPlatform node) and transform[numTransforms - 1] is the "bottom
- * most" transform (the ViewPlatorm object is attached to this transform).
- */
-public class MultiTransformGroup {
-
- // For now just have an array of TransformGroup nodes.
- TransformGroup[] transforms;
-
- /**
- * Creates a MultiTransformGroup node that contains a single transform.
- * This is effectively equivalent to creating a single TransformGroup
- * node.
- */
- public MultiTransformGroup() {
- this(1);
- }
-
- /**
- * Creates a MultiTransformGroup node that contains the specified
- * number of transforms.
- *
- * When more than one transform is needed, transform[0] is considered the
- * "top most" transform with repsect to the scene graph, (attached to the
- * ViewingPlatform node) and transform[numTransforms - 1] is the "bottom
- * most" transform (the ViewPlatorm object is attached to this transform).
- *
- * @param numTransforms The number of transforms for this node to
- * contain. If this number is less than one, one is assumed.
- */
- public MultiTransformGroup(int numTransforms) {
- if (numTransforms < 1)
- numTransforms = 1;
-
- transforms = new TransformGroup[numTransforms];
-
- // there is always at least one TransformGroup
- transforms[0] = new TransformGroup();
- transforms[0].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- transforms[0].setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
- transforms[0].setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
- transforms[0].setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
-
- for (int i = 1; i < numTransforms; i++) {
- transforms[i] = new TransformGroup();
- transforms[i].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- transforms[i].setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
- transforms[i].setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
- transforms[i].setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
- transforms[i-1].addChild(transforms[i]);
- }
- }
-
- /**
- * Returns the selected TransformGroup node.
- *
- * @param transform The index of the transform to return. The indices
- * are in the range [0..(n - 1)] - where n was the number of transforms
- * created. transform[0] is considered the
- * "top most" transform with repsect to the scene graph, (attached to the
- * ViewingPlatform node) and transform[numTransforms - 1] is the "bottom
- * most" transform (the ViewPlatorm object is attached to this transform).
- *
- * @return The TransformGroup node at the designated index. If an out of
- * range index is given, null is returned.
- */
- public TransformGroup getTransformGroup(int transform) {
- if (transform >= transforms.length || transform < 0)
- return null;
-
- return transforms[transform];
- }
-
- /**
- * Returns the number of transforms in this MultiTransformGroup object.
- *
- * @return The number of transforms in this object.
- */
- public int getNumTransforms() {
- return transforms.length;
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/PlatformGeometry.java b/src/classes/share/com/sun/j3d/utils/universe/PlatformGeometry.java
deleted file mode 100644
index 8f0c037..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/PlatformGeometry.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe;
-
-import javax.media.j3d.BranchGroup;
-
-/**
- * This class holds any geometry that should be associated with the
- * ViewingPlatform object. To create a scene with a dashboard, for
- * instance, a programmer would place the dashboard geometry under
- * the PlatformGeometry node.
- *
- * @see ViewingPlatform
- */
-public class PlatformGeometry extends BranchGroup {
-
- /**
- * Constructs an instance of the PlatformGeometry node.
- */
- public PlatformGeometry() {
- setCapability(ALLOW_DETACH);
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/SimpleUniverse.java b/src/classes/share/com/sun/j3d/utils/universe/SimpleUniverse.java
deleted file mode 100644
index 761ac2e..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/SimpleUniverse.java
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe;
-
-import java.awt.GraphicsConfiguration;
-import java.awt.GraphicsEnvironment;
-import java.net.URL;
-
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.GraphicsConfigTemplate3D;
-import javax.media.j3d.HiResCoord;
-import javax.media.j3d.Locale;
-import javax.media.j3d.View;
-import javax.media.j3d.VirtualUniverse;
-
-import com.sun.j3d.utils.geometry.Primitive;
-
-
-/**
- * This class sets up a minimal user environment to quickly and easily
- * get a Java 3D program up and running. This utility class creates
- * all the necessary objects on the "view" side of the scene graph.
- * Specifically, this class creates a locale, a single ViewingPlatform,
- * and a Viewer object (both with their default values).
- * Many basic Java 3D applications
- * will find that SimpleUniverse provides all necessary functionality
- * needed by their applications. More sophisticated applications
- * may find that they need more control in order to get extra functionality
- * and will not be able to use this class.
- *
- * @see Viewer
- * @see ViewingPlatform
- */
-public class SimpleUniverse extends VirtualUniverse {
-
- /**
- * Locale reference needed to create the "view" portion
- * of the scene graph.
- */
- protected Locale locale;
-
- /**
- * Viewer reference needed to create the "view" portion
- * of the scene graph.
- */
- protected Viewer[] viewer = null;
-
- /**
- * Creates a locale, a single ViewingPlatform, and
- * and a Viewer object (both with their default values).
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- */
- public SimpleUniverse() {
- // call main constructor with default values.
- this(null, 1, null, null);
- }
-
- /**
- * Creates a locale, a single ViewingPlatform, and a Viewer object
- * (with default values). The ViewingPlatform is created with the
- * specified number of TransformGroups.
- *
- * @param numTransforms The number of transforms to be in the
- * MultiTransformGroup object.
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- *
- * @since Java 3D 1.2.1
- */
- public SimpleUniverse(int numTransforms) {
- // call main constructor with default values except numTransforms
- this(null, numTransforms, null, null);
- }
-
- /**
- * Creates a locale, a single ViewingPlatform (with default values), and
- * and a Viewer object. The Viewer object uses default values for
- * everything but the canvas.
- *
- * @param canvas The canvas to associate with the Viewer object. Passing
- * in null will cause this parameter to be ignored and a canvas to be
- * created by the utility.
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- */
- public SimpleUniverse(Canvas3D canvas) {
- // call main constructor with default values for everything but
- // the canvas parameter.
- this(null, 1, canvas, null);
- }
-
- /**
- * Creates a locale, a single ViewingPlatform, and a Viewer object
- * The Viewer object uses default values for everything but the canvas.
- * The ViewingPlatform is created with the specified number of
- * TransformGroups.
- *
- * @param canvas The canvas to associate with the Viewer object. Passing
- * in null will cause this parameter to be ignored and a canvas to be
- * created by the utility.
- * @param numTransforms The number of transforms to be in the
- * MultiTransformGroup object.
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- *
- * @since Java 3D 1.2.1
- */
- public SimpleUniverse(Canvas3D canvas, int numTransforms) {
- // call main constructor with default values except canvas
- // and numTransforms
- this(null, numTransforms, canvas, null);
- }
-
- /**
- * Creates a locale, a single ViewingPlatform, and a Viewer object
- * The Viewer object uses default values for everything but the canvas.
- * The ViewingPlatform is created with the specified number of
- * TransformGroups.
- *
- * @param canvas The canvas to associate with the Viewer object. Passing
- * in null will cause this parameter to be ignored and a canvas to be
- * created by the utility.
- * @param numTransforms The number of transforms to be in the
- * MultiTransformGroup object.
- * @param localeFactory Factory for creating the locale
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- *
- * @since Java 3D 1.5.1
- */
- public SimpleUniverse(Canvas3D canvas, int numTransforms, LocaleFactory localeFactory) {
- // call main constructor with default values except canvas,
- // numTransforms and localeFactory
- this(null, numTransforms, canvas, null, localeFactory);
- }
-
- /**
- * Creates the "view" side of the scene graph. The passed in parameters
- * override the default values where appropriate.
- *
- * @param origin The origin used to set the origin of the Locale object.
- * If this object is null, then 0.0 is used.
- * @param numTransforms The number of transforms to be in the
- * MultiTransformGroup object.
- * @param canvas The canvas to draw into. If this is null, it is
- * ignored and a canvas will be created by the utility.
- * @param userConfig The URL to the user's configuration file, used
- * by the Viewer object. This is never examined and default values are
- * always taken.
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- * @deprecated use ConfiguredUniverse constructors to read a
- * configuration file
- */
- public SimpleUniverse(HiResCoord origin, int numTransforms,
- Canvas3D canvas, URL userConfig) {
- this( origin, numTransforms, canvas, userConfig, null );
- }
-
- /**
- * Creates the "view" side of the scene graph. The passed in parameters
- * override the default values where appropriate.
- *
- * @param origin The origin used to set the origin of the Locale object.
- * If this object is null, then 0.0 is used.
- * @param numTransforms The number of transforms to be in the
- * MultiTransformGroup object.
- * @param canvas The canvas to draw into. If this is null, it is
- * ignored and a canvas will be created by the utility.
- * @param userConfig The URL to the user's configuration file, used
- * by the Viewer object. This is never examined and default values are
- * always taken.
- * @param localeFactory The Locale Factory which will instantiate the
- * locale(s) for this universe.
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- * @deprecated use ConfiguredUniverse constructors to read a
- * configuration file
- */
- public SimpleUniverse(HiResCoord origin, int numTransforms,
- Canvas3D canvas, URL userConfig, LocaleFactory localeFactory ) {
- ViewingPlatform vwp;
-
- createLocale( origin, localeFactory );
-
- // Create the ViewingPlatform and Viewer objects, passing
- // down the appropriate parameters.
- vwp = new ViewingPlatform(numTransforms);
- vwp.setUniverse( this );
- viewer = new Viewer[1];
- // viewer[0] = new Viewer(canvas, userConfig);
- viewer[0] = new Viewer(canvas);
- viewer[0].setViewingPlatform(vwp);
-
- // Add the ViewingPlatform to the locale - the scene
- // graph is now "live".
- locale.addBranchGraph(vwp);
- }
-
-
- /**
- * Creates the "view" side of the scene graph. The passed in parameters
- * override the default values where appropriate.
- *
- * @param viewingPlatform The viewingPlatform to use to create
- * the "view" side of the scene graph.
- * @param viewer The viewer object to use to create
- * the "view" side of the scene graph.
- */
- public SimpleUniverse(ViewingPlatform viewingPlatform, Viewer viewer) {
- this( viewingPlatform, viewer, null );
- }
-
- /**
- * Creates the "view" side of the scene graph. The passed in parameters
- * override the default values where appropriate.
- *
- * @param viewingPlatform The viewingPlatform to use to create
- * the "view" side of the scene graph.
- * @param viewer The viewer object to use to create
- * the "view" side of the scene graph.
- * @param localeFactory The factory used to create the Locale Object
- */
- public SimpleUniverse(ViewingPlatform viewingPlatform, Viewer viewer,
- LocaleFactory localeFactory ) {
- createLocale( null, localeFactory );
- viewingPlatform.setUniverse( this );
-
- // Assign object references.
- this.viewer = new Viewer[1];
- this.viewer[0] = viewer;
-
- // Add the ViewingPlatform to the Viewer object.
- this.viewer[0].setViewingPlatform(viewingPlatform);
-
- // Add the ViewingPlatform to the locale - the scene
- // graph is now "live".
- locale.addBranchGraph(viewingPlatform);
- }
-
- /**
- * Constructor for use by Configured Universe
- */
- SimpleUniverse( HiResCoord origin, LocaleFactory localeFactory ) {
- createLocale( origin, localeFactory );
- }
-
- /**
- * Create the Locale using the LocaleFactory and HiRes origin,
- * if specified.
- */
- private void createLocale( HiResCoord origin,
- LocaleFactory localeFactory ) {
-
- if (localeFactory != null) {
- if (origin != null)
- locale = localeFactory.createLocale(this, origin);
- else
- locale = localeFactory.createLocale(this);
- }
- else {
- if (origin != null)
- locale = new Locale(this, origin);
- else
- locale = new Locale(this);
- }
- }
-
- /**
- * Returns the Locale object associated with this scene graph.
- *
- * @return The Locale object used in the construction of this scene
- * graph.
- */
- public Locale getLocale() {
- return locale;
- }
-
- /**
- * Returns the Viewer object associated with this scene graph.
- * SimpleUniverse creates a single Viewer object for use in the
- * scene graph.
- *
- * @return The Viewer object associated with this scene graph.
- */
- public Viewer getViewer() {
- return viewer[0];
- }
-
- /**
- * Returns the ViewingPlatform object associated with this scene graph.
- *
- * @return The ViewingPlatform object of this scene graph.
- */
- public ViewingPlatform getViewingPlatform() {
- return viewer[0].getViewingPlatform();
- }
-
- /**
- * Returns the Canvas3D object associated with this Java 3D Universe.
- *
- * @return A reference to the Canvas3D object associated with the
- * Viewer object. This method is equivalent to calling getCanvas(0).
- *
- * @see Viewer
- */
- public Canvas3D getCanvas() {
- return getCanvas(0);
- }
-
- /**
- * Returns the Canvas3D object at the specified index associated with
- * this Java 3D Universe.
- *
- * @param canvasNum The index of the Canvas3D object to retrieve.
- * If there is no Canvas3D object for the given index, null is returned.
- *
- * @return A reference to the Canvas3D object associated with the
- * Viewer object.
- */
- public Canvas3D getCanvas(int canvasNum) {
- return viewer[0].getCanvas3D(canvasNum);
- }
-
- /**
- * Used to add Nodes to the geometry side (as opposed to the view side)
- * of the scene graph. This is a short cut to getting the Locale object
- * and calling that object's addBranchGraph() method.
- *
- * @param bg The BranchGroup to attach to this Universe's Locale.
- */
- public void addBranchGraph(BranchGroup bg) {
- locale.addBranchGraph(bg);
- }
-
- /**
- * Finds the preferred
- *
- * The architecture of the Java 3D 1.3 sample implementation introduces a
- * frame latency between updates to the application scene graph structure and
- * their effects on internal Java 3D state.
- *
- * The methods in this class work around this problem at the expense of
- * querying the application state of the scene graph to get the current
- * transform from view platform to virtual world coordinates. This can
- * involve a potential performance degradation, however, since the application
- * scene graph state is not designed for high performance queries. The view
- * platform must also have
- *
- * On the other hand, application behaviors that create the view platform
- * transformation directly will have access to it without the need to query it
- * from the scene graph; in that case, the transforms from physical
- * coordinates to view platform coordinates provided by this class are all
- * that are needed. The
- *
- * Other Synchronization Issues
- *
- * Scene graph updates are guaranteed to take effect in the same frame only
- * if run from the processStimulus() method of a Behavior. Updates from
- * multiple behaviors are only guaranteed to take effect in the same frame if
- * they're responding to a WakeupOnElapsedFrames(0) condition. Use a single
- * behavior to perform view dependent updates if possible; otherwise, use
- * WakeupOnElapsedFrames(0) and set behavior scheduling intervals to ensure
- * that behaviors that need the current view platform transform are run after
- * it's set. Updating scene graph elements from anything other than the
- * Behavior thread, such as an external input thread or a renderer callback
- * in Canvas3D, will not necessarily be synchronized with rendering.
- *
- * Direct updates to geometry data have a different frame latency than
- * updates to scene graph transforms and structure. In the Java 3D 1.3
- * architecture, updates to by-reference geometry arrays and texture data have
- * a 1-frame latency, while updates to transforms and scene graph structure
- * have a 2-frame latency. Because of bug 4799494, which is outstanding
- * in Java 3D 1.3.1, updates to by-copy geometry arrays also have a 1-frame
- * latency. It is therefore recommended that view dependent scene graph
- * updates be limited to transforms and scene graph structure only.
- *
- * If it is not possible to avoid updating geometry directly, then these
- * updates must be delayed by one frame in order to remain synchronized with
- * the view platform. This can be accomplished by creating an additional
- * behavior to actually update the geometry, separate from the behavior that
- * computes the changes that need to be made based on current view state. If
- * the update behavior is awakened by a behavior post from the computing
- * behavior then the update will be delayed by a single frame.
- *
- * Implementation Notes
- *
- * This utility is essentially a rewrite of a few private Java 3D core
- * classes, but designed for public use and source code availability. The
- * source code may be helpful in understanding some of the more complex
- * aspects of the view model, especially with regards to various interactions
- * between attributes which are not adequately documented. None of the actual
- * core Java 3D source code is used, but the code is designed to comply with
- * the view model as defined by the Java 3D Specification, so it can be
- * considered an alternative implementation. This class will produce the
- * same results as the Java 3D core implementation except for:
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- * The last item deserves some mention. Java 3D provides no way to directly
- * query the tracked head position being used by the renderer. The View's
- *
- *
- * Thread Safety
- *
- * All transforms are lazily evaluated. The
- *
- * Screens and view platforms can be shared between separate views in the Java
- * 3D view model. To remain accurate, ViewInfo also allows this sharing.
- * Since it is likely that a multi-view application has separate threads
- * managing each view, potential concurrent modification of data associated
- * with a screen or a view platform is internally synchronized in this class.
- * It is safe for each thread to use its own instance of a ViewInfo
- * corresponding to the view it is managing.
- *
- * Otherwise, none of the other methods in this class are internally
- * synchronized. Except for the update methods mentioned above, a single
- * instance of ViewInfo should not be used by more than one concurrent thread
- * without external synchronization.
- *
- * @since Java 3D 1.3.1
- */
-public class ViewInfo {
- private final static boolean verbose = false ;
-
- /**
- * Indicates that updates to a Screen3D associated with the View should
- * be automatically checked with each call to a public method in this
- * class.
- */
- public final static int SCREEN_AUTO_UPDATE = 1 ;
-
- /**
- * Indicates that updates to a Canvas3D associated with the View should
- * be automatically checked with each call to a public method in this
- * class.
- */
- public final static int CANVAS_AUTO_UPDATE = 2 ;
-
- /**
- * Indicates that updates to the View should be automatically checked
- * with each call to a public method in this class.
- */
- public final static int VIEW_AUTO_UPDATE = 4 ;
-
- /**
- * Indicates that updates to the tracked head position should be
- * automatically checked with each call to a public method in this class.
- */
- public final static int HEAD_AUTO_UPDATE = 8 ;
-
- /**
- * Indicates that updates to the ViewPlatform
- *
- * Applications are responsible for informing this class of changes to the
- * View, its Canvas3D and Screen3D components, the tracked head position,
- * and the ViewPlatform's
- *
- * The View must be attached to a ViewPlatform. If the ViewPlatform is
- * attached to a live scene graph, then
- * @param autoUpdateFlags a logical
- *
- * ViewInfo caches Screen3D and ViewPlatform data, but Screen3D and
- * ViewPlatform instances are shared across multiple Views in the Java 3D
- * view model. Since ViewInfo is per-View, all ViewInfo constructors
- * except for this one use static references to manage the shared Screen3D
- * and ViewPlatform objects. In this constructor, however, the caller
- * supplies two Map instances to hold these references for all ViewInfo
- * instances, so static references can be avoided; it can be used to wrap
- * this class into a multi-view context that provides the required
- * maps.
- *
- * Alternatively, the other constructors can be used by calling
- *
- *
- * @param view the View to use
- * @param autoUpdateFlags a logical
- * @param screenMap a writeable Map to hold Screen3D information
- * @param viewPlatformMap a writeable Map to hold ViewPlatform information
- */
- public ViewInfo(View view, int autoUpdateFlags,
- Map screenMap, Map viewPlatformMap) {
-
- if (verbose)
- System.err.println("ViewInfo: init " + hashCode()) ;
- if (view == null)
- throw new IllegalArgumentException("View is null") ;
- if (screenMap == null)
- throw new IllegalArgumentException("screenMap is null") ;
- if (viewPlatformMap == null)
- throw new IllegalArgumentException("viewPlatformMap is null") ;
-
- this.view = view ;
- this.screenMap = screenMap ;
- this.viewPlatformMap = viewPlatformMap ;
-
- if (autoUpdateFlags == 0) {
- this.autoUpdate = false ;
- }
- else {
- this.autoUpdate = true ;
- this.autoUpdateFlags = autoUpdateFlags ;
- }
-
- getViewInfo() ;
- }
-
- /**
- * Gets the current transforms from image plate coordinates to view
- * platform coordinates and copies them into the given Transform3Ds.
- *
- * With a monoscopic canvas the image plate transform is copied to the
- * first argument and the second argument is not used. For a stereo
- * canvas the first argument receives the left image plate transform, and
- * if the second argument is non-null it receives the right image plate
- * transform. These transforms are always the same unless a head mounted
- * display driven by a single stereo canvas is in use.
- *
- * @param c3d the Canvas3D associated with the image plate
- * @param ip2vpl the Transform3D to receive the left transform
- * @param ip2vpr the Transform3D to receive the right transform, or null
- */
- public void getImagePlateToViewPlatform(Canvas3D c3d,
- Transform3D ip2vpl,
- Transform3D ip2vpr) {
-
- CanvasInfo ci = updateCache
- (c3d, "getImagePlateToViewPlatform", false) ;
-
- getImagePlateToViewPlatform(ci) ;
- ip2vpl.set(ci.plateToViewPlatform) ;
- if (ci.useStereo && ip2vpr != null)
- ip2vpr.set(ci.rightPlateToViewPlatform) ;
- }
-
- private void getImagePlateToViewPlatform(CanvasInfo ci) {
- if (ci.updatePlateToViewPlatform) {
- if (verbose) System.err.println("updating PlateToViewPlatform") ;
- if (ci.plateToViewPlatform == null)
- ci.plateToViewPlatform = new Transform3D() ;
-
- getCoexistenceToImagePlate(ci) ;
- getViewPlatformToCoexistence(ci) ;
-
- ci.plateToViewPlatform.mul(ci.coeToPlate, ci.viewPlatformToCoe) ;
- ci.plateToViewPlatform.invert() ;
-
- if (ci.useStereo) {
- if (ci.rightPlateToViewPlatform == null)
- ci.rightPlateToViewPlatform = new Transform3D() ;
-
- ci.rightPlateToViewPlatform.mul(ci.coeToRightPlate,
- ci.viewPlatformToCoe) ;
- ci.rightPlateToViewPlatform.invert() ;
- }
- ci.updatePlateToViewPlatform = false ;
- if (verbose) t3dPrint(ci.plateToViewPlatform, "plateToVp") ;
- }
- }
-
- /**
- * Gets the current transforms from image plate coordinates to virtual
- * world coordinates and copies them into the given Transform3Ds.
- *
- * With a monoscopic canvas the image plate transform is copied to the
- * first argument and the second argument is not used. For a stereo
- * canvas the first argument receives the left image plate transform, and
- * if the second argument is non-null it receives the right image plate
- * transform. These transforms are always the same unless a head mounted
- * display driven by a single stereo canvas is in use.
- *
- * The View must be attached to a ViewPlatform which is part of a live
- * scene graph, and the ViewPlatform node must have its
- *
- *
- * If coexistence centering is turned off, then canvases and screens can
- * have arbitrary positions with respect to coexistence, set through the
- * the Screen3D
- *
- * With a monoscopic canvas the image plate transform is copied to the
- * first argument and the second argument is not used. For a stereo
- * canvas the first argument receives the left image plate transform, and
- * if the second argument is non-null it receives the right image plate
- * transform. These transforms are always the same unless a head mounted
- * display driven by a single stereo canvas is in use.
- *
- * @param c3d the Canvas3D associated with the image plate
- * @param coe2ipl the Transform3D to receive the left transform
- * @param coe2ipr the Transform3D to receive the right transform, or null
- */
- public void getCoexistenceToImagePlate(Canvas3D c3d,
- Transform3D coe2ipl,
- Transform3D coe2ipr) {
-
- CanvasInfo ci = updateCache(c3d, "getCoexistenceToImagePlate", false) ;
- getCoexistenceToImagePlate(ci) ;
- coe2ipl.set(ci.coeToPlate) ;
- if (ci.useStereo && coe2ipr != null)
- coe2ipr.set(ci.coeToRightPlate) ;
- }
-
- private void getCoexistenceToImagePlate(CanvasInfo ci) {
- //
- // This method will always set coeToRightPlate even if stereo is not
- // in use. This is necessary so that getEyeToImagePlate() can handle
- // a monoscopic view policy of CYCLOPEAN_EYE_VIEW (which averages the
- // left and right eye positions) when the eyepoints are expressed in
- // coexistence coordinates or are derived from the tracked head.
- //
- if (ci.updateCoeToPlate) {
- if (verbose) System.err.println("updating CoeToPlate") ;
- if (ci.coeToPlate == null) {
- ci.coeToPlate = new Transform3D() ;
- ci.coeToRightPlate = new Transform3D() ;
- }
- if (viewPolicy == View.HMD_VIEW) {
- // Head mounted displays have their image plates fixed with
- // respect to the head, so get the head position in
- // coexistence.
- ci.coeToPlate.mul(ci.si.headTrackerToLeftPlate,
- coeToHeadTracker) ;
- if (ci.useStereo)
- // This is the only case in the view model in which the
- // right plate transform could be different from the left.
- ci.coeToRightPlate.mul(ci.si.headTrackerToRightPlate,
- coeToHeadTracker) ;
- else
- ci.coeToRightPlate.set(ci.coeToPlate) ;
- }
- else if (coeCentering) {
- // The default, for fixed single screen displays with no
- // motion tracking. The transform is just a translation.
- if (movementPolicy == View.PHYSICAL_WORLD)
- // The default. Coexistence is centered in the window.
- v3d.set(ci.canvasX + (ci.canvasWidth / 2.0),
- ci.canvasY + (ci.canvasHeight / 2.0), 0.0) ;
- else
- // Coexistence is centered in the screen.
- v3d.set(ci.si.screenWidth / 2.0,
- ci.si.screenHeight / 2.0, 0.0) ;
-
- ci.coeToPlate.set(v3d) ;
- ci.coeToRightPlate.set(v3d) ;
- }
- else {
- // Coexistence centering should be false for multiple fixed
- // screens and/or motion tracking. trackerBaseToImagePlate
- // and coexistenceToTrackerBase are used explicitly.
- ci.coeToPlate.mul(ci.si.trackerBaseToPlate, coeToTrackerBase) ;
- ci.coeToRightPlate.set(ci.coeToPlate) ;
- }
- ci.updateCoeToPlate = false ;
- if (verbose) t3dPrint(ci.coeToPlate, "coeToPlate") ;
- }
- }
-
- /**
- * Gets the current transform from view platform coordinates to
- * coexistence coordinates and copies it into the given transform. View
- * platform coordinates are always aligned with coexistence coordinates
- * but may differ in scale and in Y and Z offset. The scale is derived
- * from the window resize and screen scale policies, while the offset is
- * derived from the view attach policy.
- *
- * Java 3D constructs a view from the physical position of the eyes
- * relative to the physical positions of the image plates; it then uses a
- * view platform to position that physical configuration into the virtual
- * world and from there computes the correct projections of the virtual
- * world onto the physical image plates. Coexistence coordinates are used
- * to place the physical positions of the view platform, eyes, head, image
- * plate, sensors, and tracker base in relation to each other. The view
- * platform is positioned with respect to the virtual world through the
- * scene graph, so the view platform to coexistence transform defines the
- * space in which the virtual world and physical world coexist.
- *
- * This method requires a Canvas3D. A different transform may be returned
- * for each canvas in the view if any of the following apply:
- *
- *
- *
- *
- *
- * This method requires a Canvas3D. The returned transform may differ
- * across canvases for the same reasons as discussed in the description of
- *
- *
- * @param c3d the Canvas3D to use
- * @param coe2vp the Transform3D to receive the transform
- * @see #getViewPlatformToCoexistence
- * getViewPlatformToCoexistence(Canvas3D, Transform3D)
- */
- public void getCoexistenceToViewPlatform(Canvas3D c3d,
- Transform3D coe2vp) {
-
- CanvasInfo ci = updateCache
- (c3d, "getCoexistenceToViewPlatform", false) ;
-
- getCoexistenceToViewPlatform(ci) ;
- coe2vp.set(ci.coeToViewPlatform) ;
- }
-
- private void getCoexistenceToViewPlatform(CanvasInfo ci) {
- if (ci.updateCoeToViewPlatform) {
- if (verbose) System.err.println("updating CoeToViewPlatform") ;
- if (ci.coeToViewPlatform == null)
- ci.coeToViewPlatform = new Transform3D() ;
-
- getViewPlatformToCoexistence(ci) ;
- ci.coeToViewPlatform.invert(ci.viewPlatformToCoe) ;
-
- ci.updateCoeToViewPlatform = false ;
- if (verbose) t3dPrint(ci.coeToViewPlatform, "coeToVp") ;
- }
- }
-
- /**
- * Gets the current transform from coexistence coordinates to virtual
- * world coordinates and copies it into the given transform.
- *
- * The View must be attached to a ViewPlatform which is part of a live
- * scene graph, and the ViewPlatform node must have its
- *
- *
- * This method requires a Canvas3D. The returned transform may differ
- * across canvases for the same reasons as discussed in the description of
- *
- *
- * @param c3d the Canvas3D to use
- * @param coe2vw the Transform3D to receive the transform
- * @see #getViewPlatformToCoexistence
- * getViewPlatformToCoexistence(Canvas3D, Transform3D)
- */
- public void getCoexistenceToVworld(Canvas3D c3d,
- Transform3D coe2vw) {
-
- CanvasInfo ci = updateCache(c3d, "getCoexistenceToVworld", true) ;
- getCoexistenceToVworld(ci) ;
- coe2vw.set(ci.coeToVworld) ;
- }
-
- private void getCoexistenceToVworld(CanvasInfo ci) {
- if (ci.updateCoeToVworld) {
- if (verbose) System.err.println("updating CoexistenceToVworld") ;
- if (ci.coeToVworld == null) ci.coeToVworld = new Transform3D() ;
-
- getCoexistenceToViewPlatform(ci) ;
- ci.coeToVworld.mul(vpi.viewPlatformToVworld,
- ci.coeToViewPlatform) ;
-
- ci.updateCoeToVworld = false ;
- }
- }
-
- /**
- * Gets the transforms from eye coordinates to image plate coordinates and
- * copies them into the Transform3Ds specified.
- *
- * When head tracking is used the eye positions are taken from the head
- * position and set in relation to the image plates with each Screen3D's
- *
- *
- * Eye coordinates are always aligned with image plate coordinates, so
- * these transforms are always just translations. With a monoscopic
- * canvas the eye transform is copied to the first argument and the second
- * argument is not used. For a stereo canvas the first argument receives
- * the left eye transform, and if the second argument is non-null it
- * receives the right eye transform.
- *
- * @param c3d the Canvas3D associated with the image plate
- * @param e2ipl the Transform3D to receive left transform
- * @param e2ipr the Transform3D to receive right transform, or null
- */
- public void getEyeToImagePlate(Canvas3D c3d,
- Transform3D e2ipl, Transform3D e2ipr) {
-
- CanvasInfo ci = updateCache(c3d, "getEyeToImagePlate", false) ;
- getEyeToImagePlate(ci) ;
- e2ipl.set(ci.eyeToPlate) ;
- if (ci.useStereo && e2ipr != null)
- e2ipr.set(ci.rightEyeToPlate) ;
- }
-
- private void getEyeToImagePlate(CanvasInfo ci) {
- if (ci.updateEyeInPlate) {
- if (verbose) System.err.println("updating EyeInPlate") ;
- if (ci.eyeToPlate == null)
- ci.eyeToPlate = new Transform3D() ;
-
- if (viewPolicy == View.HMD_VIEW) {
- getEyesHMD(ci) ;
- }
- else if (useTracking) {
- getEyesTracked(ci) ;
- }
- else {
- getEyesFixedScreen(ci) ;
- }
- ci.updateEyeInPlate = false ;
- if (verbose) System.err.println("eyeInPlate: " + ci.eyeInPlate) ;
- }
- }
-
- //
- // Get physical eye positions for head mounted displays. These are
- // determined solely by the headTrackerToImagePlate and headToHeadTracker
- // calibration constants defined by Screen3D and the PhysicalBody.
- //
- // Note that headTrackerLeftToImagePlate and headTrackerToRightImagePlate
- // should be set according to the *apparent* position and orientation of
- // the image plates, relative to the head and head tracker, as viewed
- // through the HMD optics. This is also true of the "physical" screen
- // width and height specified by the Screen3D -- they should be the
- // *apparent* width and height as viewed through the HMD optics. They
- // must be set directly through the Screen3D methods; the default pixel
- // metrics of 90 pixels/inch used by Java 3D aren't appropriate for HMD
- // optics.
- //
- // Most HMDs have 100% overlap between the left and right displays; in
- // that case, headTrackerToLeftImagePlate and headTrackerToRightImagePlate
- // should be identical. The HMD manufacturer's specifications of the
- // optics in terms of field of view, image overlap, and distance to the
- // focal plane should be used to derive these parameters.
- //
- private void getEyesHMD(CanvasInfo ci) {
- if (ci.useStereo) {
- // This case is for head mounted displays driven by a single
- // stereo canvas on a single screen. These use a field sequential
- // stereo signal to split the left and right images.
- leftEye.set(leftEyeInHead) ;
- headToHeadTracker.transform(leftEye) ;
- ci.si.headTrackerToLeftPlate.transform(leftEye,
- ci.eyeInPlate) ;
- rightEye.set(rightEyeInHead) ;
- headToHeadTracker.transform(rightEye) ;
- ci.si.headTrackerToRightPlate.transform(rightEye,
- ci.rightEyeInPlate) ;
- if (ci.rightEyeToPlate == null)
- ci.rightEyeToPlate = new Transform3D() ;
-
- v3d.set(ci.rightEyeInPlate) ;
- ci.rightEyeToPlate.set(v3d) ;
- }
- else {
- // This case is for 2-channel head mounted displays driven by two
- // monoscopic screens, one for each eye.
- switch (ci.monoscopicPolicy) {
- case View.LEFT_EYE_VIEW:
- leftEye.set(leftEyeInHead) ;
- headToHeadTracker.transform(leftEye) ;
- ci.si.headTrackerToLeftPlate.transform(leftEye,
- ci.eyeInPlate) ;
- break ;
- case View.RIGHT_EYE_VIEW:
- rightEye.set(rightEyeInHead) ;
- headToHeadTracker.transform(rightEye) ;
- ci.si.headTrackerToRightPlate.transform(rightEye,
- ci.eyeInPlate) ;
- break ;
- case View.CYCLOPEAN_EYE_VIEW:
- default:
- throw new IllegalStateException
- ("Illegal monoscopic view policy for 2-channel HMD") ;
- }
- }
- v3d.set(ci.eyeInPlate) ;
- ci.eyeToPlate.set(v3d) ;
- }
-
- private void getEyesTracked(CanvasInfo ci) {
- leftEye.set(leftEyeInHead) ;
- rightEye.set(rightEyeInHead) ;
- headToTrackerBase.transform(leftEye) ;
- headToTrackerBase.transform(rightEye) ;
- if (coeCentering) {
- // Coexistence and tracker base coordinates are the same.
- // Centering is normally turned off for tracking.
- getCoexistenceToImagePlate(ci) ;
- ci.coeToPlate.transform(leftEye) ;
- ci.coeToRightPlate.transform(rightEye) ;
- }
- else {
- // The normal policy for head tracking.
- ci.si.trackerBaseToPlate.transform(leftEye) ;
- ci.si.trackerBaseToPlate.transform(rightEye) ;
- }
- setEyeScreenRelative(ci, leftEye, rightEye) ;
- }
-
- private void getEyesFixedScreen(CanvasInfo ci) {
- switch (eyePolicy) {
- case View.RELATIVE_TO_FIELD_OF_VIEW:
- double z = ci.getFieldOfViewOffset() ;
- setEyeWindowRelative(ci, z, z) ;
- break ;
- case View.RELATIVE_TO_WINDOW:
- setEyeWindowRelative(ci,
- ci.leftManualEyeInPlate.z,
- ci.rightManualEyeInPlate.z) ;
- break ;
- case View.RELATIVE_TO_SCREEN:
- setEyeScreenRelative(ci,
- ci.leftManualEyeInPlate,
- ci.rightManualEyeInPlate) ;
- break ;
- case View.RELATIVE_TO_COEXISTENCE:
- view.getLeftManualEyeInCoexistence(leftEye) ;
- view.getRightManualEyeInCoexistence(rightEye) ;
-
- getCoexistenceToImagePlate(ci) ;
- ci.coeToPlate.transform(leftEye) ;
- ci.coeToRightPlate.transform(rightEye) ;
- setEyeScreenRelative(ci, leftEye, rightEye) ;
- break ;
- }
- }
-
- private void setEyeWindowRelative(CanvasInfo ci,
- double leftZ, double rightZ) {
-
- // Eye position X is offset from the window center.
- double centerX = (ci.canvasX + (ci.canvasWidth / 2.0)) ;
- leftEye.x = centerX + leftEyeInHead.x ;
- rightEye.x = centerX + rightEyeInHead.x ;
-
- // Eye position Y is always the canvas center.
- leftEye.y = rightEye.y = ci.canvasY + (ci.canvasHeight / 2.0) ;
-
- // Eye positions Z are as given.
- leftEye.z = leftZ ;
- rightEye.z = rightZ ;
-
- setEyeScreenRelative(ci, leftEye, rightEye) ;
- }
-
- private void setEyeScreenRelative(CanvasInfo ci,
- Point3d leftEye, Point3d rightEye) {
- if (ci.useStereo) {
- ci.eyeInPlate.set(leftEye) ;
- ci.rightEyeInPlate.set(rightEye) ;
-
- if (ci.rightEyeToPlate == null)
- ci.rightEyeToPlate = new Transform3D() ;
-
- v3d.set(ci.rightEyeInPlate) ;
- ci.rightEyeToPlate.set(v3d) ;
- }
- else {
- switch (ci.monoscopicPolicy) {
- case View.CYCLOPEAN_EYE_VIEW:
- ci.eyeInPlate.set((leftEye.x + rightEye.x) / 2.0,
- (leftEye.y + rightEye.y) / 2.0,
- (leftEye.z + rightEye.z) / 2.0) ;
- break ;
- case View.LEFT_EYE_VIEW:
- ci.eyeInPlate.set(leftEye) ;
- break ;
- case View.RIGHT_EYE_VIEW:
- ci.eyeInPlate.set(rightEye) ;
- break ;
- }
- }
- v3d.set(ci.eyeInPlate) ;
- ci.eyeToPlate.set(v3d) ;
- }
-
- /**
- * Gets the current transforms from eye coordinates to view platform
- * coordinates and copies them into the given Transform3Ds.
- *
- * With a monoscopic canvas the eye transform is copied to the first
- * argument and the second argument is not used. For a stereo canvas the
- * first argument receives the left eye transform, and if the second
- * argument is non-null it receives the right eye transform.
- *
- * This method requires a Canvas3D. When using a head mounted display,
- * head tracking with fixed screens, or a window eyepoint policy of
- *
- *
- * With window eyepoint policies of
- *
- *
- *
- *
- *
- *
- *
- * With a monoscopic canvas the eye transform is copied to the first
- * argument and the second argument is not used. For a stereo canvas the
- * first argument receives the left eye transform, and if the second
- * argument is non-null it receives the right eye transform.
- *
- * This method requires a Canvas3D. The transforms returned may differ
- * across canvases for all the same reasons discussed in the description
- * of
- *
- * With a monoscopic canvas the eye transform is copied to the first
- * argument and the second argument is not used. For a stereo canvas the
- * first argument receives the left eye transform, and if the second
- * argument is non-null it receives the right eye transform.
- *
- * The View must be attached to a ViewPlatform which is part of a live
- * scene graph, and the ViewPlatform node must have its
- *
- *
- * This method requires a Canvas3D. The transforms returned may differ
- * across canvases for all the same reasons discussed in the description
- * of
- *
- * With a monoscopic canvas the projection transform is copied to the
- * first argument and the second argument is not used. For a stereo
- * canvas the first argument receives the left projection transform,
- * and if the second argument is non-null it receives the right
- * projection transform.
- *
- * If either of the clip policies
- *
- * With a monoscopic canvas the projection transform is copied to the
- * first argument and the second argument is not used. For a stereo
- * canvas the first argument receives the left projection transform, and
- * if the second argument is non-null it receives the right projection
- * transform.
- *
- * If either of the clip policies
- *
- * With a monoscopic canvas the projection transform is copied to the
- * first argument and the second argument is not used. For a stereo
- * canvas the first argument receives the left projection transform, and
- * if the second argument is non-null it receives the right projection
- * transform.
- *
- * If either of the clip policies
- *
- * With a monoscopic canvas the projection transform is copied to the
- * first argument and the second argument is not used. For a stereo
- * canvas the first argument receives the left projection transform, and
- * if the second argument is non-null it receives the right projection
- * transform.
- *
- * The View must be attached to a ViewPlatform which is part of a live
- * scene graph, and the ViewPlatform node must have its
- *
- *
- * Note that this is not necessarily the clip distance as set by
- *
- *
- * If either of the clip policies
- *
- * Note that this is not necessarily the clip distance as set by
- *
- *
- * If either of the clip policies
- *
- * This method requires a Canvas3D. A different scale may be returned
- * for each canvas in the view if any of the following apply:
- *
- *
- *
- * This method requires a Canvas3D. A different scale may be returned
- * across canvases for the same reasons as discussed in the description of
- *
- *
- * The View must be attached to a ViewPlatform which is part of a live
- * scene graph, and the ViewPlatform node must have its
- *
- *
- * This method requires a Canvas3D. The returned transform may differ
- * across canvases for the same reasons as discussed in the description of
- *
- *
- * This method requires a Canvas3D. The returned transform may differ
- * across canvases for the same reasons as discussed in the description of
- *
- *
- * This method requires a Canvas3D. The returned transform may differ
- * across canvases for the same reasons as discussed in the description of
- *
- *
- * It is safe to continue using existing ViewInfo instances after calling
- * this method; the data in the released maps will be re-derived as
- * needed.
- */
- public static synchronized void clear() {
- Iterator i = staticVpMap.values().iterator() ;
- while (i.hasNext()) ((ViewPlatformInfo)i.next()).clear() ;
- staticVpMap.clear() ;
-
- i = staticSiMap.values().iterator() ;
- while (i.hasNext()) ((ScreenInfo)i.next()).clear() ;
- staticSiMap.clear() ;
- }
-
- /**
- * Arrange for an update of cached screen parameters. If automatic update
- * has not been enabled, then this method should be called if any of the
- * attributes of the Screen3D have changed. This method should also be
- * called if the screen changes pixel resolution.
- *
- * @param s3d the Screen3D to update
- */
- public void updateScreen(Screen3D s3d) {
- if (verbose) System.err.println("updateScreen") ;
- ScreenInfo si = (ScreenInfo)screenMap.get(s3d) ;
- if (si != null) si.updateScreen = true ;
- }
-
- /**
- * Arrange for an update of cached canvas parameters. If automatic update
- * has not been enabled, then this method should be called if any of the
- * attributes of the Canvas3D have changed. These attributes include the
- * canvas position and size, but do not include the attributes of
- * the associated Screen3D, which are cached separately.
- *
- * @param c3d the Canvas3D to update
- */
- public void updateCanvas(Canvas3D c3d) {
- if (verbose) System.err.println("updateCanvas") ;
- CanvasInfo ci = (CanvasInfo)canvasMap.get(c3d) ;
- if (ci != null) ci.updateCanvas = true ;
- }
-
- /**
- * Arrange for an update of cached view parameters. If automatic update
- * has not been enabled for the View, then this method should be called if
- * any of the attributes of the View associated with this object have
- * changed.
- *
- * These do not include the attributes of the existing Canvas3D or
- * Screen3D components of the View, but do include the attributes of all
- * other components such as the PhysicalEnvironment and PhysicalBody, and
- * all attributes of the attached ViewPlatform except for its
- *
- *
- * This method should also be called if the ViewPlatform is replaced with
- * another using the View's
- *
- * Calling this method causes most transforms to be re-derived. It should
- * be used only when necessary.
- */
- public void updateView() {
- if (verbose) System.err.println("updateView") ;
- this.updateView = true ;
- }
-
- /**
- * Arrange for an update of the cached head position if head tracking is
- * enabled. If automatic update has not enabled for the head position,
- * then this method should be called anytime a new head position is to be
- * read.
- */
- public void updateHead() {
- if (verbose) System.err.println("updateHead") ;
- this.updateHead = true ;
- }
-
- /**
- * Arrange for an update of the cached
- *
- * The View must be attached to a ViewPlatform which is part of a live
- * scene graph, and the ViewPlatform node must have its
- *
- *
- * The default implementation uses the head tracking sensor specified by
- * the View's PhysicalEnvironment, and reads it by calling the sensor's
- *
- *
- * The default implementation returns
- * @see Canvas3D
- * @see PhysicalEnvironment
- * @see PhysicalBody
- * @see View
- * @see ViewerAvatar
- */
-public class Viewer {
- private static final boolean debug = false;
- private static PhysicalBody physicalBody = null;
- private static PhysicalEnvironment physicalEnvironment = null;
- private View view = null;
- private ViewerAvatar avatar = null;
- private Canvas3D[] canvases = null;
- private JFrame[] j3dJFrames = null;
- private JPanel[] j3dJPanels = null;
- private Window[] j3dWindows = null;
- private ViewingPlatform viewingPlatform = null;
-
- /**
- * Creates a default viewer object. The default values are used to create
- * the PhysicalBody and PhysicalEnvironment. A single RGB, double buffered
- * and depth buffered Canvas3D object is created. The View is created
- * with a front clip distance of 0.1f and a back clip distance of 10.0f.
- */
- public Viewer() {
- // Call main constructor with default values.
- this(null, null, null, true);
- }
-
- /**
- * Creates a default viewer object. The default values are used to create
- * the PhysicalBody and PhysicalEnvironment. The View is created
- * with a front clip distance of 0.1f and a back clip distance of 10.0f.
- *
- * @param userCanvas the Canvas3D object to be used for rendering;
- * if this is null then a single RGB, double buffered and depth buffered
- * Canvas3D object is created
- * @since Java3D 1.1
- */
- public Viewer(Canvas3D userCanvas) {
- // Call main constructor.
- this(userCanvas == null ? null : new Canvas3D[] {userCanvas},
- null, null, true);
- }
-
-
- /**
- * Creates a default viewer object. The default values are used to create
- * the PhysicalBody and PhysicalEnvironment. The View is created
- * with a front clip distance of 0.1f and a back clip distance of 10.0f.
- *
- * @param userCanvases the Canvas3D objects to be used for rendering;
- * if this is null then a single RGB, double buffered and depth buffered
- * Canvas3D object is created
- * @since Java3D 1.3
- */
- public Viewer(Canvas3D[] userCanvases) {
- this(userCanvases, null, null, true);
- }
-
- /**
- * Creates a viewer object. The Canvas3D objects, PhysicalEnvironment, and
- * PhysicalBody are taken from the arguments.
- *
- * @param userCanvases the Canvas3D objects to be used for rendering;
- * if this is null then a single RGB, double buffered and depth buffered
- * Canvas3D object is created
- * @param userBody the PhysicalBody to use for this Viewer; if it is
- * null, a default PhysicalBody object is created
- * @param userEnvironment the PhysicalEnvironment to use for this Viewer;
- * if it is null, a default PhysicalEnvironment object is created
- * @param setVisible determines if the Frames should be set to visible once created
- * @since Java3D 1.3
- */
- public Viewer(Canvas3D[] userCanvases, PhysicalBody userBody,
- PhysicalEnvironment userEnvironment, boolean setVisible ) {
-
- if (userBody == null) {
- physicalBody = new PhysicalBody();
- } else {
- physicalBody = userBody;
- }
-
- if (userEnvironment == null) {
- physicalEnvironment = new PhysicalEnvironment();
- } else {
- physicalEnvironment = userEnvironment;
- }
-
- // Create Canvas3D object if none was passed in.
- if (userCanvases == null) {
- GraphicsConfiguration config =
- ConfiguredUniverse.getPreferredConfiguration();
-
- canvases = new Canvas3D[1];
- canvases[0] = new Canvas3D(config);
- canvases[0].setFocusable(true);
- createFramesAndPanels(setVisible);
- }
- else {
- canvases = new Canvas3D[userCanvases.length];
- for (int i=0; i
- * NOTE: When running under JDK 1.4 or newer, the JFrame always directly
- * contains the JPanel which contains the Canvas3D. When running under
- * JDK 1.3.1 and creating a borderless full screen through a configuration
- * file, the JFrame will instead contain a JWindow which will contain the
- * JPanel and Canvas3D.
- *
- * @param frameNum the index of the JFrame object to retrieve;
- * if there is no JFrame object for the given index, null is returned
- * @return a reference to JFrame object created by this Viewer object
- * @since Java3D 1.3
- */
- public JFrame getJFrame(int frameNum) {
- if (j3dJFrames == null || frameNum > j3dJFrames.length) {
- return(null);
- }
- return j3dJFrames[frameNum];
- }
-
- /**
- * Returns all the JFrames created by this Viewer object. If a Viewer is
- * constructed without any Canvas3D objects then the Viewer object will
- * create a Canva3D object, a JPanel containing the Canvas3D object, and a
- * JFrame to place the JPanel in.
- *
- * NOTE: When running under JDK 1.4 or newer, the JFrame always directly
- * contains the JPanel which contains the Canvas3D. When running under
- * JDK 1.3.1 and creating a borderless full screen through a configuration
- * file, the JFrame will instead contain a JWindow which will contain the
- * JPanel and Canvas3D.
- *
- * @return an array of references to the JFrame objects created by
- * this Viewer object, or null if no JFrame objects were created
- * @since Java3D 1.3
- */
- public JFrame[] getJFrames() {
- if (j3dJFrames == null)
- return null;
-
- JFrame[] ret = new JFrame[j3dJFrames.length];
- for (int i = 0; i < j3dJFrames.length; i++) {
- ret[i] = j3dJFrames[i];
- }
- return ret;
- }
-
- /**
- * This method is no longer supported since Java 3D 1.3.
- * @exception UnsupportedOperationException if called.
- * @deprecated AWT Panel components are no longer created by the
- * Viewer class.
- */
- public Panel getPanel() {
- throw new UnsupportedOperationException(
- "AWT Panel components are not created by the Viewer class");
- }
-
- /**
- * Returns the JPanel object created by this Viewer object at the
- * specified index. If a Viewer is constructed without any Canvas3D
- * objects then the Viewer object will create a Canva3D object and a
- * JPanel into which to place the Canvas3D object.
- *
- * @param panelNum the index of the JPanel object to retrieve;
- * if there is no JPanel object for the given index, null is returned
- * @return a reference to a JPanel object created by this Viewer object
- * @since Java3D 1.3
- */
- public JPanel getJPanel(int panelNum) {
- if (j3dJPanels == null || panelNum > j3dJPanels.length) {
- return(null);
- }
- return j3dJPanels[panelNum];
- }
-
- /**
- * Returns all the JPanel objects created by this Viewer object. If a
- * Viewer is constructed without any Canvas3D objects then the Viewer
- * object will create a Canva3D object and a JPanel into which to place
- * the Canvas3D object.
- *
- * @return an array of references to the JPanel objects created by
- * this Viewer object, or null or no JPanel objects were created
- * @since Java3D 1.3
- */
- public JPanel[] getJPanels() {
- if (j3dJPanels == null)
- return null;
-
- JPanel[] ret = new JPanel[j3dJPanels.length];
- for (int i = 0; i < j3dJPanels.length; i++) {
- ret[i] = j3dJPanels[i];
- }
- return ret;
- }
-
- /**
- * Used to create and initialize a default AudioDevice3D used for sound
- * rendering.
- *
- * @return reference to created AudioDevice, or null if error occurs.
- */
- public AudioDevice createAudioDevice() {
- if (physicalEnvironment == null) {
- System.err.println("Java 3D: createAudioDevice: physicalEnvironment is null");
- return null;
- }
-
- try {
- String audioDeviceClassName =
- (String) java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- @Override
- public Object run() {
- return System.getProperty("j3d.audiodevice");
- }
- });
-
- if (audioDeviceClassName == null) {
- throw new UnsupportedOperationException("No AudioDevice specified");
- }
-
- // Issue 341: try the current class loader first before trying the
- // system class loader
- Class audioDeviceClass = null;
- try {
- audioDeviceClass = Class.forName(audioDeviceClassName);
- } catch (ClassNotFoundException ex) {
- // Ignore excpetion and try system class loader
- }
-
- if (audioDeviceClass == null) {
- ClassLoader audioDeviceClassLoader =
- (ClassLoader) java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- @Override
- public Object run() {
- return ClassLoader.getSystemClassLoader();
- }
- });
-
- if (audioDeviceClassLoader == null) {
- throw new IllegalStateException("System ClassLoader is null");
- }
-
- audioDeviceClass = Class.forName(audioDeviceClassName, true, audioDeviceClassLoader);
- }
-
- Class physEnvClass = PhysicalEnvironment.class;
- Constructor audioDeviceConstructor =
- audioDeviceClass.getConstructor(new Class[] {physEnvClass});
- PhysicalEnvironment[] args = new PhysicalEnvironment[] { physicalEnvironment };
- AudioEngine3DL2 mixer =
- (AudioEngine3DL2) audioDeviceConstructor.newInstance((Object[])args);
- mixer.initialize();
- return mixer;
- }
- catch (Throwable e) {
- e.printStackTrace();
- physicalEnvironment.setAudioDevice(null);
- System.err.println("Java 3D: audio is disabled");
- return null;
- }
- }
-
- /**
- * Returns the Universe to which this Viewer is attached
- *
- * @return the Universe to which this Viewer is attached
- * @since Java 3D 1.3
- */
- public SimpleUniverse getUniverse() {
- return getViewingPlatform().getUniverse();
- }
-
-
- /*
- * Exit if run as an application
- */
- void addWindowCloseListener(Window win) {
- SecurityManager sm = System.getSecurityManager();
- boolean doExit = true;
-
- if (sm != null) {
- try {
- sm.checkExit(0);
- } catch (SecurityException e) {
- doExit = false;
- }
- }
- final boolean _doExit = doExit;
-
- win.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosing(WindowEvent winEvent) {
- Window w = winEvent.getWindow();
- w.setVisible(false);
- try {
- w.dispose();
- } catch (IllegalStateException e) {}
- if (_doExit) {
- System.exit(0);
- }
- }
- });
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ViewerAvatar.java b/src/classes/share/com/sun/j3d/utils/universe/ViewerAvatar.java
deleted file mode 100644
index 17367b3..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ViewerAvatar.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe;
-
-import javax.media.j3d.BranchGroup;
-
-/**
- * This class holds geomtry that should be associated with the View's
- * avatar. An avatar is how the user's "virtual self" appears in the
- * virtual world.
- *
- * @see Viewer
- */
-public class ViewerAvatar extends BranchGroup {
-
- /**
- * Constructs an instance of the ViewerAvatar node.
- */
- public ViewerAvatar() {
- setCapability(ALLOW_DETACH);
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ViewingPlatform.java b/src/classes/share/com/sun/j3d/utils/universe/ViewingPlatform.java
deleted file mode 100644
index e740106..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ViewingPlatform.java
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe;
-
-import java.util.Enumeration;
-import java.util.Hashtable;
-
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Group;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-import javax.media.j3d.View;
-import javax.media.j3d.ViewPlatform;
-import javax.vecmath.Vector3d;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-import com.sun.j3d.utils.behaviors.vp.ViewPlatformBehavior;
-
-/**
- * This class is used to set up the "view" side of a Java 3D scene graph.
- * The ViewingPlatform object contains a MultiTransformGroup node to allow
- * for a series of transforms to be linked together. To this structure
- * the ViewPlatform is added as well as any geometry to associate with this
- * view platform.
- *
- * @see ViewPlatform
- */
-public class ViewingPlatform extends BranchGroup {
-
- /**
- * Cached ViewPlatform associated with this ViewingPlatform object.
- */
- protected ViewPlatform viewPlatform;
-
- /**
- * MultiTransformGroup that holds all TransformGroups between
- * the BranchGroup and the View object.
- */
- protected MultiTransformGroup mtg;
-
- /**
- * Used to keep track of added geometry. When geometry
- * is added to the view platform, an addChild to this BranchGroup
- * is performed.
- */
- protected BranchGroup platformGeometryRoot;
-
- /**
- * Used to keep track of added geometry. When geometry
- * is added for an avatar, an addChild to this BranchGroup
- * is performed.
- */
- protected BranchGroup avatarRoot;
-
- /**
- * Cached PlatformGeometry object.
- */
- protected PlatformGeometry platformGeometry = null;
-
- /**
- * Table of the Viewer objects.
- */
- protected Hashtable viewerList;
-
- /**
- * Used to keep track of behaviors.
- *
- * @since Java 3D 1.2.1
- */
- protected BranchGroup behaviors;
-
- /**
- * The universe to which this viewing platform is attached
- *
- * @since Java 3D 1.3
- */
- protected SimpleUniverse universe;
-
- /**
- * Creates a default ViewingPlatform object. This consists of a
- * MultiTransfromGroup node with one transform and a ViewPlatform
- * object. The ViewPlatform is positioned at (0.0, 0.0, 0.0).
- */
- public ViewingPlatform() {
- // Call main constructor with default values.
- this(1);
- }
-
- /**
- * Creates the ViewingPlatform object. This consists of a
- * MultiTransfromGroup node with the specified number of transforms
- * (all initialized to the identity transform).
- * and a ViewPlatform object.
- *
- * @param numTransforms The number of transforms the MultiTransformGroup
- * node should contain. If this number is less than 1, 1 is assumed.
- */
- public ViewingPlatform(int numTransforms) {
- viewerList = new Hashtable();
-
- // Set default capabilities for this node.
- setCapability(Group.ALLOW_CHILDREN_WRITE);
- setCapability(Group.ALLOW_CHILDREN_EXTEND);
- setCapability(BranchGroup.ALLOW_DETACH);
-
- // Create MultiTransformGroup node.
- if (numTransforms < 1)
- numTransforms = 1;
- mtg = new MultiTransformGroup(numTransforms);
-
- // Get first transform and add it to the scene graph.
- TransformGroup tg = mtg.getTransformGroup(0);
- addChild(tg);
-
- // Create ViewPlatform and add it to the last transform in the
- // MultiTransformGroup node.
- tg = mtg.getTransformGroup(numTransforms - 1);
- viewPlatform = new ViewPlatform();
- viewPlatform.setCapability(ViewPlatform.ALLOW_POLICY_READ);
- viewPlatform.setCapability(ViewPlatform.ALLOW_POLICY_WRITE);
- tg.addChild(viewPlatform);
-
- // Set capabilities to allow for changes when live.
- tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
- tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
-
- // Initialize the avatarRoot BranchGroup node and add it to the
- // last transform in the MultiTransformGroup node.
- avatarRoot = new BranchGroup();
- avatarRoot.setCapability(Group.ALLOW_CHILDREN_READ);
- avatarRoot.setCapability(Group.ALLOW_CHILDREN_WRITE);
- avatarRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND);
- tg.addChild(avatarRoot);
-
- // Initialize the platformGeometry BranchGroup node and add it to the
- // last transform in the MultiTransformGroup node.
- platformGeometryRoot = new BranchGroup();
- platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_READ);
- platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_WRITE);
- platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND);
- tg.addChild(platformGeometryRoot);
- }
-
- /**
- * Sets the ViewPlatform node for this ViewingPlatform object.
- *
- * @param vp The ViewPlatform node to associate with this ViewingPlatform
- * object.
- */
- public void setViewPlatform(ViewPlatform vp) {
- TransformGroup tg = getViewPlatformTransform();
- tg.removeChild(viewPlatform);
- tg.addChild(vp);
- viewPlatform = vp;
- // Assign this to all Viewers.
- Enumeration e = viewerList.keys();
-
- while (e.hasMoreElements())
- ((Viewer)e.nextElement()).setViewingPlatform(this);
- }
-
- /**
- * Returns the ViewPlatform node for this ViewingPlatform object.
- *
- * @return The ViewPlatform node associated with this ViewingPlatform
- * object.
- */
- public ViewPlatform getViewPlatform() {
- return viewPlatform;
- }
-
- /**
- * Assigns the geometry to associate with the ViewingPlatform.
- * PlatformGeometry is used to hold any geometry to be associated
- * with the ViewingPlatform. If the ViewingPlatform is to be the
- * inside of a car, for instance, than the PlatformGeometry could be
- * the dashboard of the car.
- *
- * @param pg The geometry to be associated with this ViewingPlatform.
- * Passing in null has the effect of deleting any geometry associated
- * with this ViewingPlatform.
- */
- public void setPlatformGeometry(PlatformGeometry pg) {
- // Just return if trying to set the same PlatformGeometry object.
- if (platformGeometry == pg)
- return;
-
- // If the PlatformGeometry is null, will be removing any geometry
- // already present.
- if (pg == null) {
- if (platformGeometryRoot.numChildren() != 0)
- platformGeometryRoot.removeChild(0);
- }
- else {
-
- // See if there is an old PlatformGeometry to replace.
- if (platformGeometryRoot.numChildren() != 0)
- platformGeometryRoot.setChild(pg, 0);
- else {
- platformGeometryRoot.addChild(pg);
- }
- }
- platformGeometry = pg;
- }
-
- /**
- * Returns the PlatformGeometry associated with this ViewingPlatform
- *
- * @return The PlatformGeometry associated with this ViewingPlatform
- */
- public PlatformGeometry getPlatformGeometry() {
- return platformGeometry;
- }
-
- /**
- * Returns the MultitransformGroup object for this
- * ViewingPlatform object.
- *
- * @return The MultitransformGroup object.
- */
- public MultiTransformGroup getMultiTransformGroup() {
- return mtg;
- }
-
- /**
- * Returns a reference to the "bottom most" transform in the
- * MultiTransformGroup that is above the ViewPlatform node.
- *
- * @return The TransformGroup that is immediately above the
- * ViewPlatform object.
- */
- public TransformGroup getViewPlatformTransform() {
- return mtg.getTransformGroup(mtg.getNumTransforms() - 1);
- }
-
- /**
- * Sets the nominal viewing distance in the ViewPlatform transform based
- * on the current field of view. If the ViewAttachPolicy is not the
- * default of View.NOMINAL_HEAD, then this method has no effect.
- *
- * The ViewPlatform is moved back along Z so that objects at the origin
- * spanning the normalized X range of -1.0 to +1.0 can be fully viewed
- * across the width of the window. This is done by setting a translation
- * of 1/(tan(fieldOfView/2)) in the ViewPlatform transform.
- *
- * If there is no Viewer object associated with this ViewingPlatform
- * object the default field of view of PI/4.0 is used.
- *
- * NOTE: Support for multiple Viewer objects is not available. If
- * multiple viewers are attached to this ViewingPlatform than a
- * RuntimeException will be thrown.
- */
- public void setNominalViewingTransform() {
- if (viewPlatform.getViewAttachPolicy() == View.NOMINAL_HEAD) {
- double fieldOfView;
-
- if (viewerList.size() == 0) {
- // No Viewer associated with this ViewingPlatform, so use the
- // default field of view value to move the ViewingPlatform.
- fieldOfView = Math.PI/4.0;
- }
- else {
- if (viewerList.size() > 1) {
- throw new RuntimeException
- (J3dUtilsI18N.getString("ViewingPlatform0"));
- }
-
- Viewer viewer = (Viewer)viewerList.keys().nextElement();
- View view = viewer.getView();
- fieldOfView = view.getFieldOfView();
- }
-
- Transform3D t3d = new Transform3D();
- double viewDistance = 1.0/Math.tan(fieldOfView/2.0);
- t3d.set(new Vector3d(0.0, 0.0, viewDistance));
- getViewPlatformTransform().setTransform(t3d);
- }
- }
-
- /**
- * Returns the avatarRoot child number of the ViewerAvatar object.
- * All the children of the avatarRoot are compared with the passed
- * in ViewerAvatar. If a match is found, the index is returned.
- *
- * @param avatar The ViewerAvatar object to look for in the avatarRoot's
- * child nodes.
- * @return The index of the child that corresponds to the ViewerAvatar.
- * If the avatarRoot does not contain the ViewerAvatar -1 is returned.
- */
- private int findAvatarChild(ViewerAvatar avatar) {
- // Search the avatarRoot for the ViewerAvatar associated with
- // with the Viewer object
- for (int i = 0; i < avatarRoot.numChildren(); i++) {
- if (((ViewerAvatar)avatarRoot.getChild(i)) == avatar)
- return i;
- }
-
- // Should never get here.
- System.err.println("ViewingPlatform.findAvatarChild:Child not found.");
- return -1;
- }
-
- /**
- * Adds the ViewerAvatar to the scene graph. An avatar (geometry)
- * can be associated with a Viewer object and displayed by Java 3D.
- *
- * @param viewer The viewer object to associate with this avatar.
- * @param avatar The avatar to add to the scene graph. Passing in
- * null removes any currently assigned avatar.
- */
- void setAvatar(Viewer viewer, ViewerAvatar avatar) {
- Object oldAvatar = viewerList.get(viewer);
-
- // A position of -1 means the avatar is not a child of the avatarRoot.
- int avatarPosition = -1;
-
- // Because "null" cannot be used in a put the avatarRoot object
- // is used to signify that there is no ViewerAvatar associated
- // with this Viewer.
- if (oldAvatar != avatarRoot)
- avatarPosition = findAvatarChild((ViewerAvatar)oldAvatar);
-
- // If the avatar is null, will be removing any geometry already present.
- if (avatar == null) {
- if (avatarPosition != -1) {
- avatarRoot.removeChild(avatarPosition);
-
- // Reset hashtable entry - avatarRoot == null.
- viewerList.put(viewer, avatarRoot);
- }
- }
- else {
- // see if there is an old ViewerAvater to replace
- if (avatarPosition != -1)
- avatarRoot.setChild(avatar, avatarPosition);
- else
- avatarRoot.addChild(avatar);
-
- // Update hashtable with new avatar.
- viewerList.put(viewer, avatar);
- }
- }
-
- /**
- * When a ViewingPlatform is set by a Viewer, the ViewingPlatform
- * needs to be informed, via a call to this method. This will add
- * the Viewer to the ViewingPlatform's viewerList for use when
- * things such as the PlatformGeometry are changed and all Viewer
- * scene graphs need to be modified.
- */
- void addViewer(Viewer viewer) {
- // Because the viewerList is also used to associate ViewerAvatars
- // with Viewer objects a hashtable is used. This routine does not
- // check for the presence of a ViewerAvatar but the Viewer still
- // needs to be added to the hashtable. Because "null" cannot be
- // used in a put the avatarRoot object is used to signify that there
- // is no ViewerAvatar associated with this Viewer.
- viewerList.put(viewer, avatarRoot);
- }
-
- /*
- * Cleanup when Viewer set another ViewingPlatform
- */
- void removeViewer(Viewer viewer) {
- viewerList.remove(viewer);
- }
-
- /**
- * Adds a new ViewPlatformBehavior to the ViewingPlatform
- */
- void addViewPlatformBehavior(ViewPlatformBehavior behavior) {
- behavior.setViewingPlatform(this);
- if (behaviors == null) {
- behaviors = new BranchGroup();
- behaviors.setCapability(BranchGroup.ALLOW_DETACH);
- behaviors.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
- }
- // otherwise detach the BranchGroup so we can add to it
- else {
- behaviors.detach();
- }
- behaviors.addChild(behavior);
- this.addChild(behaviors);
- }
-
- /**
- * Sets the ViewPlatformBehavior which will operate on the ViewPlatform
- * transform (the TransformGroup returned by
- * ViewingPlatform.getViewPlatformTransform()). The ViewPlatformBehavior
- * may be set after the ViewingPlatform is setLive().
- * If a behavior is already present, it will be detached and it's
- * setViewingPlatform method will be called with a parameter of null.
- * @param behavior The ViewPlatformBehavior to add to the ViewingPlatform.
- * null will remove the ViewingPlatform behavior.
- * @since Java 3D 1.2.1
- */
- public void setViewPlatformBehavior(ViewPlatformBehavior behavior) {
- if (behaviors != null) {
- removeViewPlatformBehavior((ViewPlatformBehavior)behaviors.getChild(0));
- }
- if (behavior != null) {
- addViewPlatformBehavior(behavior);
- }
- }
-
- /**
- * Removes the specified ViewPlatformBehavior
- */
- void removeViewPlatformBehavior(ViewPlatformBehavior behavior) {
- // remove from the behaviors branch group
- if (behaviors != null) {
- behaviors.detach();
- for (int i = 0; i < behaviors.numChildren(); i++) {
- if (behaviors.getChild(i) == behavior) {
- behavior.setViewingPlatform( null );
- behaviors.removeChild(i);
- break;
- }
- }
- if (behaviors.numChildren() == 0) behaviors = null;
- else this.addChild(behaviors);
- }
- }
-
- /**
- * Returns the number of ViewPlatformBehaviors on the ViewingPlatform
- */
- int getViewPlatformBehaviorCount() {
- return behaviors.numChildren();
- }
-
- /**
- * Returns the ViewPlatformBehavior at the specified index
- */
- ViewPlatformBehavior getViewPlatformBehavior(int index) {
- return (ViewPlatformBehavior)behaviors.getChild(index);
- }
-
- /**
- * Returns the ViewPlatformBehavior
- * @return the ViewPlatformBehavior for the ViewingPlatform.
- * Returns null if there is no ViewPlatformBehavior set.
- * @since Java 3D 1.2.1
- */
- public ViewPlatformBehavior getViewPlatformBehavior() {
- if (behaviors == null) {
- return null;
- }
- return getViewPlatformBehavior(0);
- }
-
- /**
- * Returns the Viewers attached to this ViewingPlatform
- *
- * @return the Viewers attached to this viewing platform
- * @since Java 3D 1.3
- */
- public Viewer[] getViewers() {
- if (viewerList.size() == 0) return null;
- return (Viewer[])viewerList.keySet().toArray( new Viewer[0] );
- }
-
- /**
- * Returns the Universe to which this ViewingPlatform is attached
- *
- * @return the Universe to which this ViewingPlatform is attached
- * @since Java 3D 1.3
- */
- public SimpleUniverse getUniverse() {
- return universe;
- }
-
- /**
- * Sets the Universe to which this ViewingPlatform is attached
- *
- * @param universe the Universe to which this ViewingPlatform is attached
- * @since Java 3D 1.3
- */
- public void setUniverse( SimpleUniverse universe ) {
- this.universe = universe;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-examples.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-examples.html
deleted file mode 100644
index bab913b..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-examples.html
+++ /dev/null
@@ -1,85 +0,0 @@
-
-
-
-
-
- j3d1x1-behavior A single
-fullscreen desktop configuration with a configurable view platform behavior.
- j3d1x1-stereo A single
-fullscreen desktop configuration with stereo viewing.
- j3d1x1-vr A single fullscreen
-desktop configuration with head tracker, stereo viewing, and 6 degree of
-freedom mouse.
- j3d1x1-window A single screen
-desktop configuration with a conventional window.
- j3d1x2-flat A dual-screen planar
-desktop configuration.
- j3d1x2-rot30 A dual-screen
-desktop configuration with each screen rotated toward the other by 30 degrees.
- j3d1x3-cave A three-projector cave
-configuration.
- j3d1x3-cave-vr A
-three-projector cave configuration with head tracking and stereo viewing.
- j3d1x3-rot45 A three-screen
-desktop configuration with left and right screens rotated 45 degrees from the
-center screen.
- j3d2x2-flat A four-projector
-configuration arranged in a 2x2 array.
-
-This document is an informal description of the syntax of the Java 3D
-configuration file and a tutorial of the semantics of its various commands.
-Such a file is written by a user or site administrator to describe the physical
-configuration of a local interactive viewing environment. Configuration
-properties that can be described in the file include the sizes, positions, and
-orientations of displays in either fixed screen environments or head mounted
-displays (HMD devices), as well as the input devices and sensors
-available for user interaction apart from the keyboard and mouse abstractions
-provided by the AWT.
-A configuration file is used by passing its URL to either a ConfigContainer or
-a ConfiguredUniverse constructor. The method by which a user specifies the
-file is up to the application, but the universe utilities do provide a few
-means to easily enable an application to perform this task. These depend upon
-a Java 3D property, j3d.configURL, that the user can set on the java
-command line with the -D option. Its value should be a URL string
-indicating the location of the desired file. The application can then either
-call the static ConfigContainer methods
-getConfigURL
-to retrieve the value of the property, or
-
-getConfigURL(String) to specify a default file to be used in case the
-property is not set. Applications are encouraged to devise their own
-user-friendly mechanisms to retrieve the configuration file, although the
-setting of the j3d.configURL property should be honored if at all
-possible.
-If the attempt to open the resource indicated by the URL is successful, then a
-parser will be invoked to read and evaluate the commands it contains and
-deposit the results in the ConfigContainer. The parser will detect syntax
-errors, invalid commands, and bad references, printing descriptive messages to
-System.out, including the line number and text of the offending command. In
-general the parser attempts to continue processing as much of the file as it
-can when encountering an error. Some errors can only be detected after the
-entire file has been evaluated; in those cases an exception will be thrown.
-An application may choose to override the settings of the configuration file by
-accessing view-side scenegraph components directly from the ConfigContainer
-once the file is evaluated. Applications should avoid this in general, as most
-settings are physical calibration constants specific to the local interactive
-viewing environment. Nonetheless, application overrides are still sometimes
-appropriate; for example, the application may have knowledge of the contents of
-the scenegraph that enables it to make a better judgement of where the view's
-clipping planes should be.
-The configuration file syntax is very simple; scanning any of the
-sample configuration files should provide
-the general idea. At the broadest level there are two main types of
-constructs: comments and commands.
-Comments can be either C or C++ style. In a C-style
-comment all text between successive occurances of /* and */ is ignored.
-A C++ comment begins with // and continues to the end of the line.
-A command begins with an opening parenthesis and ends with a closing
-parenthesis. The elements between the parentheses can be of four types:
-alphanumeric strings, numbers, quoted strings, or other commands. During the
-evaluation of a command, any nested command encountered is itself evaluated,
-and the result of that evaluation replaces the nested command within the
-original outer command.
-Strings that contain embedded white space, forward slashes, or invalid
-tokens must be enclosed in quotes (either single or double). Common cases are
-URL strings and Unix path names. Numbers are any non-quoted strings that can
-be parsed as double-precision floating point numbers. The strings true,
-True, false, and False are converted to their corresponding boolean
-values. Strings, quoted strings, and numbers are delimited from each other by
-white space.
-Commands in the configuration file have four special forms: point,
-matrix, top-level, and built-in commands.
-Don't pass 2D, 3D, or 4D points to commands that expect two, three, or four
-numbers instead. This will generate a syntax error indicating an invalid
-number of arguments.
-Command names can either specify top-level or built-in commands. Top-level
-commands generally configure Java 3D core and utility classes and can only
-appear at the outermost level of parentheses. Built-in commands are provided
-by the parser itself to help construct the arguments to top-level commands.
-Points, matrices, and built-in commands can only be nested within other
-commands.
-An error will result if points, matrices, or built-in commands are invoked at
-the outermost level of nesting. Sometimes this error is caused by prematurely
-closing the opening parenthesis of the current top-level command. Such an
-error is usually preceded by an error from the command indicating an invalid
-number of arguments.
-Similarly, errors will be generated if top-level commands are nested. Errors
-to this effect are sometimes caused by failing to close all the open
-parentheses of the preceding top-level command.
-(Include "file:${user.home}/myBody.cfg")
-would evaluate the contents of the file "myBody.cfg" in the user's home
-directory on Unix systems. An error is issued if no Java property exists with
-the specified name.
-Java property substitution happens early, after tokenization but before command
-evaluation. Substitution can occur any number of times anywhere within any
-quoted or non-quoted string, including command names, property names, and
-property values, as long as the property substitution syntax is not nested.
-Most top-level commands configure concrete Java 3D core and utility classes.
-These include PhysicalBody, PhysicalEnvironment, Screen, Sensor, View, and
-ViewPlatform. The Screen, View, and ViewPlatform commands also implicitly
-configure the Canvas3D core class and the Viewer and ViewingPlatform utility
-classes respectively.
-These commands come in two forms: the New<class name> and
-<class name>Property commands. All New commands except
-NewSensor create new class instances and bind names to
-them, while the Property commands refer to these names and configure
-their corresponding class instances with the parameters specified by the
-command arguments. All references must be to objects previously instantiated
-in the file; forward referencing is not supported. Names must be unique within
-each class.
-Implementations of the Java 3D InputDevice interface and concrete subclasses of
-the abstract ViewPlatformBehavior utility class can also be instantiated and
-configured with the same command forms. The New commands for these
-objects accept class names as command arguments and instantiate the objects
-through introspection. Since the details of the implementations are not known,
-configuration parameters are passed through methods which are invoked through
-introspection of the method names specified in the Property command
-arguments.
-A method invoked through introspection with a Property command gets its
-arguments as a single array of Objects. Boolean strings get wrapped into
-Boolean objects, and number strings get wrapped into Double. 2D, 3D, and 4D
-points get wrapped into Point2d, Point3d, and Point4d objects respectively,
-while 3D and 4D matrices get wrapped into Matrix3d and Matrix4d
-respectively.
-The sample configuration files are annotated to assist users in modifying them
-to suit their particular viewing environments, but it can be helpful to know
-some of the basics of the Java 3D view model that are relevant to writing a
-configuration file. This overview should only be considered an informal
-adjunct to the detailed description in the Java 3D Specification. Reading the
-source code to the ViewInfo utility (a public
-implementation of the Java 3D view model) may also be helpful in understanding
-the details of the view model.
-In the traditional camera model the camera or eyepoint is positioned and
-oriented with respect to the virtual world via a view transform. Objects
-contained within the field of view are projected onto an image plane, which is
-then mapped onto a display surface, usually a window on a desktop display
-system. While the view direction and camera position can be freely oriented
-and placed anywhere in the virtual world, the projection is accomplished using
-a static frustum defined by the field of view and a flat image plane centered
-about and normal to the view direction.
-This model emulates a typical physical camera quite well, but there are many
-viewing configurations that cannot be implemented using image planes that are
-fixed with respect to the view direction. In a multiple screen environment the
-projection frustum for each screen is skewed with respect to the image plane,
-based on the user's nominal viewing position. Realistic stereo views on fixed
-displays use skewed projection frustums derived from the offsets of the two
-eyes from the center of the image plane, while head tracking with fixed
-displays involves dynamically adjusting projection frustums in response to
-varying eye positions relative to the image plane.
-In a low-level API such as OpenGL these situations are handled by concatenating
-all defined model and viewing transforms into a single modelview matrix,
-and for a fixed-screen environment explicitly computing the projection
-matrix for each eye, each display surface, and each new head
-position. Every application handling such viewing configurations typically
-reimplements the framework for computing those matrices itself. In these cases
-it would be useful to be able to separate the projection components out of the
-view transform in some representation based on display and eye locations.
-Based on these requirements, a high-level view model should provide standard
-mechanisms to 1) define a screen's position and orientation in relation to
-other screens in the viewing environment; 2) specify the position of the user's
-eyes or an HMD relative to the physical space in which the screens or nominal
-user position are defined, and to have them updated automatically if tracking
-hardware exists; and 3) describe where the whole physical space is placed and
-oriented in the virtual world. In such a model the appropriate images could
-then be rendered without further computation in application code.
-In the Java 3D view model, screen (image plate) positions and
-orientations are defined relative to a fixed frame of reference in the physical
-world, the tracker base, through the
-TrackerBaseToImagePlate property. The
-tracker base is somewhat abstract in that it is always used to define that
-fixed frame of reference, even if no physical tracking hardware is being
-used. If the ViewPolicy is HMD_VIEW, then the left
-and right image plates for head mounted displays are defined relative to the
-head tracking sensor, which reports head orientation and position relative to
-the tracker base.
-Coexistence coordinates are defined with the
-CoexistenceToTrackerBase property. It
-provides a frame of reference in the physical world which can be set up by the
-user or application in whatever way is most convenient for positioning and
-orienting screens, physical body attributes, and sensing devices in the virtual
-world. If tracking is enabled, then the eye positions in coexistence are
-computed from the position and orientation of the head tracking sensor and the
-HeadToHeadTracker matrix; otherwise the eye
-positions in coexistence are set according to the
-CenterEyeInCoexistence property. In HMD
-mode the eye positions are fixed with respect to the image plates.
-The mapping of coexistence coordinates into the virtual world is accomplished
-through the ViewAttachPolicy, which specifies
-the point in coexistence coordinates to which the origin of the view
-platform should be mapped. The view platform is positioned in the virtual
-world by manipulating its view transform, the composite of all the
-transforms from the view platform up to its Locale. The basis vectors (X, Y,
-and Z directions) of the view platform are always aligned with coexistence
-coordinates, and the scaling between view platform coordinates and physical
-coordinates is specified by the
-ScreenScalePolicy, so this
-establishes the complete mapping of the physical world into the virtual world.
-The projection of the virtual world onto the physical display surfaces is then
-performed automatically by the Java 3D renderer.
-By default Java 3D tries to emulate the familiar camera model as much as
-possible to make it easy to run in a conventional windowed desktop display
-environment. It accomplishes this through the following default settings:
-Top-level commands can only appear at the outermost command nesting level.
-This command instantiates the InputDevice implementation specified by the fully
-qualified class name and binds it to instance name. The
-InputDevice is instantiated through introspection of the class name. The
-implementation must provide a parameterless constructor; this can usually be
-done by extending or wrapping available InputDevice implementations.
-The last two arguments are optional and define an alias for instance
-name. This is useful in providing a longer descriptive name for the
-application to recognize, or conversely, to provide a shorter alias for a
-longer instance name. Either name may be used to identify the instance.
-At the conclusion of configuration file processing all InputDevice
-implementations so defined will be initialized and registered with any
-PhysicalEnvironments that reference them.
-
-The details of the InputDevice implementation specified by instance name
-are not known to ConfigContainer, so any parameters to be set through the
-configuration file are passed to the InputDevice instance by invoking method
-name through introspection. The arguments following the method name are
-evaluated and the results passed to the method as an array of Objects.
-The required methods can usually be provided by extending or wrapping existing
-InputDevice implementations.
-Retrieves the Sensor at index sensor index in the InputDevice device
-name and binds it to the name specified by instance name. The
-sensor index is a number truncated to its integer value. The InputDevice
-implementation is responsible for creating its own Sensor objects, so this
-command does not create any new instances.
-Instance name is used by other commands to reference the indicated
-Sensor. In addition, the name and its associated Sensor instance is made
-available to applications through a Map returned by the ConfigContainer
-method
-getNamedSensors.
-
-The last two arguments are optional and define an alias for instance
-name. This is useful in providing a longer descriptive name for the
-application to recognize, or conversely, to provide a shorter alias for a
-longer instance name. Either name may be used to identify the instance.
-If the Sensor is to be used for head tracking, or tracking the position and
-orientation of other objects in the physical world, then it must generate 6
-degree of freedom data relative to the tracker base.
-Sets a Sensor property. The sensor instance is specified by instance
-name, the property to be set by property name, and the value to be
-set by property value. The following sole property may be
-configured:
-The above two commands are equivalent. Both create new window resources and
-associate them with the name specified by instance name. The device
-index is a number truncated to its integer value. This integer is the
-index at which the desired AWT GraphicsDevice appears in the array returned by
-the static getScreenDevices() method of GraphicsEnvironment, and specifies the
-physical screen upon which the window should be created. The GraphicsDevice
-order in the array is specific to the local viewing site and display
-system.
-The last two arguments are optional and define an alias for instance
-name. This is useful in providing a longer descriptive name for the
-application to recognize, or conversely, to provide a shorter alias for a
-longer instance name. Either name may be used to identify the instance.
-The above two commands are equivalent. The screen or window instance is
-specified by instance name, the property to be set by property
-name, and the value to be set by property value. The following
-properties are configurable:
-Image plate dimensions are expressed in meters. The origin of the image plate
-is the lower left corner of the screen's image area, with X increasing to the
-right, Y increasing to the top, and Z increasing away from the screen.
-The tracker base is somewhat abstract. It is used as a local fixed frame of
-reference for specifying the orientation and position of a screen even when
-tracking hardware is not being used. It is also the frame of reference for
-defining coexistence coordinates with the
-CoexistenceToTrackerBase matrix.
-The built-in commands Translate,
-Rotate, RotateTranslate, and TranslateRotate are available to make it easier
-to create transforms of this type.
-
-
-These are only used when a ViewPolicy of
-The HMD manufacturer's specifications in terms of angle of view, distance to
-the focal plane, aspect ratio, and percentage of image overlap between the left
-and right views can be used to derive the apparent screen positions with
-respect to the head, and from there the positions with respect to the head
-tracker mounted on the head. In most cases there is 100% overlap between the
-two stereo images, so the matrices for both the left and right screens should
-be identical.
-Some HMD devices support field-sequential stereo and are driven as if they were
-a single screen. In that case, only a single screen should be defined, but
-both the left and right head tracker to image plate transforms need to
-be specified for that same screen.
-Some HMD devices can be driven as a single screen if the HMD supports
-field-sequential stereo, so the default policy will work for them as well if a
-stereo view is enabled. If stereo is not enabled, an IllegalStateException will
-be thrown when the ViewPolicy is set to
-The
-Creates a new PhysicalEnvironment and binds it to the name given by instance
-name. This specifies the available input devices, which Sensor to use as
-the head tracker, and defines the coexistence coordinate system. Note that
-aside from the head tracker, the configuration file does not provide a way to
-place Sensors into the array maintained by the PhysicalEnvironment. See the
-getNamedSensors
-method of ConfigContainer.
-The last two arguments are optional and define an alias for instance
-name. This is useful in providing a longer descriptive name for the
-application to recognize, or conversely, to provide a shorter alias for a
-longer instance name. Either name may be used to identify the instance.
-Sets a PhysicalEnvironment property. The instance is specified by instance
-name, the property to be set by property name, and the value to be
-set by property value. The following properties are configurable:
-There is no actual method in the core PhysicalEnvironment class to set the head
-tracker. This property is a simplified interface for setting the
-PhysicalEnvironment head index and assigning the head tracking sensor to that
-index. Direct access to the PhysicalEnvironment Sensor array is not supported
-by the configuration file.
-The coexistence origin (center of coexistence) positions the physical
-world with respect to the origin of the ViewPlatform in the virtual world.
-This is established through the
-ViewAttachPolicy, which attaches the view
-platform to either the center of coexistence, the nominal head, or the nominal
-feet. Coexistence coordinates can essentially be thought of as physical
-coordinates, but the real purpose is to define the space in which coordinates
-systems in the physical world - such as tracker base, image plate, and physical
-body - coexist and interact with the virtual world coordinate systems.
-The basis vectors (X, Y, and Z directions) of coexistence coordinates are
-always aligned with the basis vectors of the ViewPlatform in the virtual world,
-and the scale factor going from ViewPlatform coordinates to coexistence
-coordinates is set by the ScreenScalePolicy.
-Together with the ViewPlatform's view attach policy and view transform this
-establishes the complete mapping of the physical world into the virtual
-world.
-The positioning and orientation of coexistence coordinates with respect to the
-physical environment is up to the user or application. In a fixed screen
-environment it usually makes most sense to define it in a convenient
-relationship to the primary screen or some intersection of the available
-screens, such that the coexistence origin is in front of and aligned with the
-user's nominal forward gaze direction. This is because the -Z axis of
-coexistence coordinates always points along the view direction defined by the
-view platform's -Z axis.
-For example, when using a single screen, the most common mapping puts the
-center of coexistence in the middle of the screen with its basis vectors
-aligned with the screen's image plate coordinate system. With a dual-screen
-system it is usually most convenient to place the center of coexistence in the
-middle of the edge shared by both screens, with its Z axis extending
-perpendicular to the shared edge and maintaining an equal angle to both
-screens. For a 2x2 array of four screens putting the center of coexistence at
-the center of the array is usually a good choice. In a cave configuration
-having the center of coexistence in the middle of the viewing environment can
-facilitate the sense of immersion.
-In HMD mode the view attach policy is ignored and is always effectively
-
-Note: the normal Java 3D default is to place the center of coexistence
-in the middle of the screen or canvas by setting
-CoexistenceCenteringEnable true by
-default. This only works for a single screen and if both the
-TrackerBaseToImagePlate and CoexistenceToTrackerBase matrices are identity. If
-either of these matrices are set from their default identity values in the
-configuration file, and CoexistenceCenteringEnable has not been set, then the
-centering property will be set false by default.
-
-Creates a new PhysicalBody and binds it to the name given by instance
-name. The PhysicalBody is essentiallly the users's head, with the origin
-halfway between the eyes in the plane of the face. Positive X extends to the
-right eye, positive Y up, and positive Z extends into the skull opposite to the
-forward gaze direction. Dimensions are expressed in meters.
-The last two arguments are optional and define an alias for instance
-name. This is useful in providing a longer descriptive name for the
-application to recognize, or conversely, to provide a shorter alias for a
-longer instance name. Either name may be used to identify the instance.
-Sets a PhysicalBody property. The instance is specified by instance
-name, the property to be set by property name, and the value to be
-set by property value. The following properties are configurable:
-This property is a simplified interface to setting the PhysicalBody's separate
-left and right eye positions; there is no actual method in PhysicalBody to set
-stereo eye separation, but the results are exactly equivalent.
-Creates a new view and binds it to the name given by instance name.
-In the configuration file the term view refers to an instance of the
-Viewer utility class, which contains both an
-instance of a core Java 3D View class and an array of Canvas3D instances into
-which to render.
-The last two arguments are optional and define an alias for instance
-name. This is useful in providing a longer descriptive name for the
-application to recognize, or conversely, to provide a shorter alias for a
-longer instance name. Either name may be used to identify the instance.
-ConfiguredUniverse requires that at least one view be defined. If a view
-platform is not provided, then ConfiguredUniverse will create a default one and
-attach the view to that. If multiple views are defined, then at least one view
-platform must be explicitly provided by the configuration, and the
-ViewPlatform property must be used to attach each view to a view platform.
-Sets a View property. The view instance is specified by instance name,
-the property to be set by property name, and the value to be set by
-property value. The following properties are configurable:
-This only works if a single screen is being used and if both the
-TrackerBaseToImagePlate and
-CoexistenceToTrackerBase matrices are
-identity. If CoexistenceCenteringEnable is not explicitly set, and either the
-CoexistenceToTrackerBase transform for the view has been set or
-TrackerBaseToImagePlate has been set for any screen, then the centering enable
-will be set to false by default; otherwise, the normal default is true. This
-property is also effectively false whenever the ViewPolicy is set to
-
-For the
-These polices are ignored if head tracking is enabled.
-This property is a simplified interface to setting the View's left
-and right manual eyes in coexistence; there is no actual method in View
-to set a center eye position.
-If the value is
-
-The view platform is positioned in the virtual world through a chain of
-transforms to the root of the scene graph; this composite transform is its
-localToVWorld transform and must be congruent. If we take the the inverse of
-the scale factor in this transform and call it the view platform scale,
-then the scale from virtual world units to physical world units can be computed
-as the product of this view platform scale, the screen scale, and, when using a
-resize policy of
-With the default clip policies of
-There is a quirk, however, with physical clip plane scaling when the
-
-This quirk applies only to scaling physical clip plane distances, and only with
-the
-There is no actual method in the core Java 3D View or utility Viewer class to
-enable stereo. A true value for this property causes ConfigContainer to
-attempt to create stereo-capable canvases for all the screens associated with
-this view. Stereo will then be enabled for each canvas successfully created
-with stereo capability.
-Setting this property true causes WindowEyepointPolicy to be ignored; it will
-effectively be
-A true value for this property causes ConfigContainer to attempt to create
-a canvas capable of scene antialiasing on each screen associated with this
-view. The scene will then be antialiased on each canvas successfully created
-with that capability.
-Line and point antialiasing are independent of scene antialiasing and are
-controlled by the LineAttribute and PointAttribute components of an Appearance.
-If line and point antialiasing is enabled, then they will be antialiased prior
-to scene antialiasing; if scene antialiasing is turned off, then antialiased
-lines and points will still be antialiased.
-Creates a new view platform and binds it to the name given by instance
-name. In the configuration file the term view platform refers to an
-instance of the ViewingPlatform utility
-class, which is an extension of BranchGroup containing an instance of a core
-Java 3D ViewPlatform class.
-The last two arguments are optional and define an alias for instance
-name. This is useful in providing a longer descriptive name for the
-application to recognize, or conversely, to provide a shorter alias for a
-longer instance name. Either name may be used to identify the instance.
-Sets a ViewPlatform property. The instance is specified by instance
-name, the property to be set by property name, and the value to be
-set by property value. The following properties are configurable:
-For a ViewAttachPolicy of
-For a ViewAttachPolicy of
-For a ViewAttachPolicy of
-Note: The normal Java 3D default is
-This command instantiates the concrete subclass of ViewPlatformBehavior
-specified by the fully qualified class name and binds it to instance
-name. The ViewPlatformBehavior is instantiated through introspection of
-the class name. The subclass must provide a parameterless constructor. If no
-such constructor is available, then the behavior must be extended or wrapped to
-provide one and the derived class used instead.
-The last two arguments are optional and define an alias for instance
-name. This is useful in providing a longer descriptive name for the
-application to recognize, or conversely, to provide a shorter alias for a
-longer instance name. Either name may be used to identify the instance.
-View platform behaviors often need sensors or canvases as event sources to
-drive the behavior action. A subclass of ViewPlatformBehavior always gets the
-current ViewingPlatform through its
-setViewingPlatform
-method. When the behavior is initialized, the canvases used by the
-ViewingPlatform can be retrieved by calling its
-getViewers method and
-then calling each Viewer's
-getCanvas3Ds method. Sensors
-can be retrieved by calling the ViewingPlatform method
-getUniverse, checking
-to see if the returned SimpleUniverse is a ConfiguredUniverse, and then calling
-its
-getNamedSensors
-method.
-Alternatively, the behavior implementation can define its own properties
-and receive canvas and sensor instances directly through the
-Canvas3D and Sensor built-in
-commands.
-Sets a property of a ViewPlatformBehavior. The instance is specified by
-instance name, the property to be set by property name, and the
-value to be set by property value. The following properties are
-pre-defined by the abstract ViewPlatformBehavior superclass and may be
-configured directly:
-
-
-The details of a concrete subclass of ViewPlatformBehavior are not known to
-ConfigContainer, so any properties specific to the subclass are set by
-using introspection to invoke property name as a method accepting an
-array of Objects as its single parameter. The arguments following the property
-name are evaluated and the results passed to the method through that array of
-Objects. Such methods can usually be provided by extending or wrapping
-existing ViewPlatformBehavior implementations.
-This command instantiates a generic object specified by class
-name and binds it to instance name. The object is instantiated
-through introspection of the class name. The object must provide a
-parameterless constructor; this can usually be done by extending or
-wrapping existing objects.
-The last two arguments are optional and define an alias for instance
-name. This is useful in providing a longer descriptive name for the
-application to recognize, or conversely, to provide a shorter alias for a
-longer instance name. Either name may be used to identify the instance.
-Objects so defined may be accessed from ConfigContainer through the
-getNamedGenericObjects method.
-Sets a property of a generic object. The details of the object specified by
-instance name are not known to ConfigContainer, so any parameters to be
-set through the configuration file are passed to the object instance by
-invoking method name through introspection. The arguments following the
-method name are evaluated and the results passed to the method as an array of
-Objects. The required methods can usually be provided by extending or wrapping
-existing objects.
-Sets the Java system property propertyName to the string
-propertyValue. If the optional Default keyword is supplied, then the
-property is set only if it doesn't currently have a value.
-Java system properties which affect Java 3D are evaluated at the first
-reference to a VirtualUniverse. Setting such properties in the configuration
-file is therefore ineffective if a ConfiguredUniverse constructor which accepts
-a URL directly is used; ConfigContainer must be used instead. Even then, care
-must be taken to avoid static references to VirtualUniverse from objects such
-as Transform3D.
-The special Java property substitution syntax ${<propertyName>}
-may be used to access the value of a Java system property anywhere within a
-configuration file.
-Retrieves the configuration file specified by URL string and includes it
-into the current configuration file at the current line. The content of the
-included file is evaluated exactly as if it were pasted into the current file
-at that line. Included files may be arbitrarily nested.
-URL strings must be quoted.
-
-Creates an alias for the object specified by originalName (which itself
-may be an alias). baseName may be Device, Object, PhysicalBody,
-PhysicalEnvironment, Screen, Window, Sensor, View, ViewPlatform, or
-ViewPlatformBehavior; it specifies the type of the object being aliased.
-Original names and aliases must be unique within a type. Note that there is no
-white space between baseName and Alias.
-Aliases are useful for providing shorter or longer descriptive names for an
-original name. This function is also provided by the optional Alias keyword
-available for all New top-level commands. This separate command can be
-used to substitute new names for objects created by generic include files in
-order to conform to the names expected by specific applications.
-Built-in commands are provided by the parser itself to help construct the
-arguments to top-level commands. They cannot appear at the top level of
-command nesting.
-Translate, Rotate, TranslateRotate, and RotateTranslate are useful for
-computing simple affine transforms of the form SourceToTarget
-(e.g., TrackerBaseToImagePlate). These transform points from the
-Source coordinate system to the Target coordinate system by
-concatenating translation and rotation matrices. Here is a general rule for
-creating such transforms:
-If instead it is easier to measure or compute the source origin relative to the
-target origin along the target basis vectors, rotate first with Euler angles
-that move the target basis vectors to their corresponding source basis vectors,
-and then add (translate) the source origin.
-The Canvas3D, Sensor, Device, PhysicalBody, PhysicalEnvironment, View,
-ViewPlatform, ViewPlatformBehavior, and Object built-in commands return
-references to the objects named by their arguments. These are mostly useful
-for InputDevice and ViewPlatformBehavior implementations that define their own
-properties. The return values of these built-in commands should not be passed
-to commands that expect strings.
-Returns a 4D matrix that translates by the given X, Y, and Z values.
-Returns a 4D matrix that rotates by the given Euler angles around static X, Y,
-and Z basis vectors: first about X, then Y, and then Z. See the
-setEuler
-method of Transform3D.
-Returns a 4D matrix that concatenates 4D matrices m1 and m2 in
-that order. If a point is transformed by the resulting matrix, then in effect
-the points are first transformed by m1 and then m2.
-An alias for the Concatenate command. This is useful to make the
-result of the concatenation explicit.
-An alias for the Concatenate command. This is useful to make the
-result of the concatenation explicit.
-Returns a BoundingSphere object using the 3D point center and the given
-radius in meters. radius may be either a number or the string
-Infinite.
-Returns the Canvas3D instance specified by the given name. A named Canvas3D is
-created whenever any of the following configuration commands are used:
-
-
-Note: the NewScreen and NewWindow commands do not create Canvas3D
-instances themselves; they are created only by the above configuration
-commands.
-Returns the Sensor instance specified by the given name.
-Returns the InputDevice instance specified by the given name.
-Returns the PhysicalBody instance specified by the given name.
-Returns the PhysicalEnvironment instance specified by the given name.
-Returns the Viewer instance specified by the given name.
-Returns the ViewingPlatform instance specified by the given name.
-Returns the ViewPlatformBehavior instance specified by the given name.
-Returns the generic object instance specified by the given name. A generic
-named object is created by the following configuration command:
-
-
-Returns a reference to the current ConfigContainer. Provides utility classes for setting up the Java 3D universe,
-including the viewing configuration.
+ * NOTE: AudioEngine developers should not subclass this class directly.
+ * Subclass AudioEngine3DL2 instead.
+ */
+public abstract class AudioEngine implements AudioDevice {
+
+ /*
+ * This device's UNIX file descriptor
+ */
+ int fileDescriptor;
+
+ /*
+ * Type of audio output device J3D sound is played over:
+ * HEADPHONE, MONO_SPEAKER, STEREO_SPEAKERS
+ */
+ int audioPlaybackType = HEADPHONES;
+
+ /*
+ * Distance from center ear (midpoint between ears) to physical speaker.
+ * Default reflects distance for headphones.
+ * For two speakers it is assumed that the speakers are the same
+ * distance from the listener and that
+ */
+ float distanceToSpeaker = 0.0f;
+
+ /*
+ * Angle between the vector from center ear parallel to head coordiate
+ * Z axis and the vector from the center ear to the speaker.
+ * For two speakers it is assumed that the speakers are placed at the
+ * same angular offset from the listener.
+ */
+ float angleOffsetToSpeaker = 0.0f;
+
+ /*
+ * Channels currently available
+ */
+ int channelsAvailable = 8;
+
+ /*
+ * Total number of Channels ever available
+ */
+ int totalChannels = 8;
+
+ /**
+ * Construct a new AudioEngine with the specified P.E.
+ * @param physicalEnvironment the physical environment object where we
+ * want access to this device.
+ */
+ public AudioEngine(PhysicalEnvironment physicalEnvironment ) {
+ physicalEnvironment.setAudioDevice(this);
+ }
+
+ /**
+ * Code to initialize the device
+ * @return flag: true is initialized sucessfully, false if error
+ */
+ @Override
+ public abstract boolean initialize();
+
+ /**
+ * Code to close the device
+ * @return flag: true is closed sucessfully, false if error
+ */
+ @Override
+ public abstract boolean close();
+
+ /*
+ * Audio Playback Methods
+ */
+ /**
+ * Set Type of Audio Playback physical transducer(s) sound is output to.
+ * Valid types are HEADPHONE, MONO_SPEAKER, STEREO_SPEAKERS
+ * @param type of audio output device
+ */
+ @Override
+ public void setAudioPlaybackType(int type) {
+ audioPlaybackType = type;
+ }
+
+ /**
+ * Get Type of Audio Playback Output Device
+ * returns audio playback type to which sound is currently output
+ */
+ @Override
+ public int getAudioPlaybackType() {
+ return audioPlaybackType;
+ }
+
+ /**
+ * Set Distance from the Center Ear to a Speaker
+ * @param distance from the center ear and to the speaker
+ */
+ @Override
+ public void setCenterEarToSpeaker(float distance) {
+ distanceToSpeaker = distance;
+ }
+
+ /**
+ * Get Distance from Ear to Speaker
+ * returns value set as distance from listener's ear to speaker
+ */
+ @Override
+ public float getCenterEarToSpeaker() {
+ return distanceToSpeaker;
+ }
+
+ /**
+ * Set Angle Offset To Speaker
+ * @param angle in radian between head coordinate Z axis and vector to speaker */
+ @Override
+ public void setAngleOffsetToSpeaker(float angle) {
+ angleOffsetToSpeaker = angle;
+ }
+
+ /**
+ * Get Angle Offset To Speaker
+ * returns value set as angle between vector to speaker and Z head axis
+ */
+ @Override
+ public float getAngleOffsetToSpeaker() {
+ return angleOffsetToSpeaker;
+ }
+
+ /**
+ * Query total number of channels available for sound rendering
+ * for this audio device.
+ * returns number of maximum sound channels you can run with this
+ * library/device-driver.
+ */
+ @Override
+ public int getTotalChannels() {
+ // this method should be overridden by a device specific implementation
+ return (totalChannels);
+ }
+
+ /**
+ * Query number of channels currently available for use by the
+ * returns number of sound channels currently available (number
+ * not being used by active sounds.
+ */
+ @Override
+ public int getChannelsAvailable() {
+ return (channelsAvailable);
+ }
+
+ /**
+ * Query number of channels that would be used to render a particular
+ * sound node.
+ * @param sound refenence to sound node that query to be performed on
+ * returns number of sound channels used by a specific Sound node
+ * @deprecated This method is now part of the Sound class
+ */
+ @Override
+ public int getChannelsUsedForSound(Sound sound) {
+ if (sound != null)
+ return sound.getNumberOfChannelsUsed();
+ else
+ return -1;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/audioengines/AudioEngine3D.java b/src/classes/share/org/jogamp/java3d/audioengines/AudioEngine3D.java
new file mode 100644
index 0000000..7209a0c
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/audioengines/AudioEngine3D.java
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.audioengines;
+
+import java.util.ArrayList;
+
+import org.jogamp.java3d.AudioDevice3D;
+import org.jogamp.java3d.MediaContainer;
+import org.jogamp.java3d.PhysicalEnvironment;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.View;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Vector3d;
+
+
+/**
+ * The AudioEngine3D Class defines an audio output device that generates
+ * sound 'image' from high-level sound parameters passed to it during
+ * scene graph.
+ *
+ *
+ * The methods in this class are meant to be optionally overridden by an
+ * extended class. This extended class would provice device specific code.
+ *
+ *
+ * Error checking on all parameters passed to these methods is already
+ * explicitly being done by the Java 3D core code that calls these methods.
+ *
+ *
+ * NOTE: AudioEngine developers should not subclass this class directly.
+ * Subclass AudioEngine3DL2 instead.
+ */
+
+public abstract class AudioEngine3D extends AudioEngine implements AudioDevice3D
+{
+ /*
+ * Identifiers of sample associated with sound source
+ * This array grows as the AudioDevice3D implementation requires it larger.
+ */
+ protected ArrayList samples = new ArrayList(64);
+
+ /**
+ * Current View sound is being rendered
+ */
+ protected View currentView = (View)null;
+
+ /*
+ * current Aural attribute Parameters
+ */
+ protected AuralParameters attribs = new AuralParameters();
+
+ /**
+ * Construct a new AudioEngine with the specified PhysicalEnvironment.
+ * @param physicalEnvironment the physical environment object where we
+ * want access to this device.
+ */
+ public AudioEngine3D(PhysicalEnvironment physicalEnvironment ) {
+ super(physicalEnvironment);
+ }
+
+ /*
+ *
+ * Methods that affect AudioEngine3D fields that are NOT associated
+ * with a specific sound sample
+ *
+ */
+
+ /**
+ * Save a reference to the current View object.
+ * @param reference to current view object
+ */
+ @Override
+ public void setView(View reference) {
+ currentView = reference;
+ return;
+ }
+ /**
+ * Get reference to the current View object.
+ * @return reference to current view object
+ */
+ public View getView() {
+ return (currentView);
+ }
+
+ /*
+ *
+ * Methods explicitly affect sound rendering and that require
+ * audio device specific methods that override this class.
+ *
+ */
+
+ /**
+ * Prepare Sound in device.
+ * Makes sound assessible to device - in this case attempts to load sound
+ * Stores sound type and data.
+ * @param soundType denotes type of sound: Background, Point or Cone
+ * @param soundData descrition of sound source data
+ * @return index into sample vector of Sample object for sound
+ */
+ @Override
+ public int prepareSound(int soundType, MediaContainer soundData) {
+ // This method must be overridden by device specific implementation
+ return Sample.NULL_SAMPLE;
+ }
+
+ /**
+ * Clear Sound.
+ * Removes/clears associated sound data with this sound source node
+ * @param index device specific reference number to device driver sample
+ */
+ @Override
+ public abstract void clearSound(int index);
+
+ /**
+ * Set the transform for local to virtual world coordinate space
+ * @param index device specific reference number to device driver sample
+ * @param trans is a reference to virtual world composite transform
+ */
+ @Override
+ public void setVworldXfrm(int index, Transform3D trans) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.vworldXfrm.set(trans);
+ return;
+ }
+ /**
+ * Start sample playing on audio device
+ * @param index device specific reference number to device driver sample
+ * @return status: < 0 denotes an error
+ */
+ @Override
+ public abstract int startSample(int index);
+
+ /**
+ * Stop sample playing on audio device
+ * @param index device specific reference number to device driver sample
+ * @return status: < 0 denotes an error
+ */
+ @Override
+ public abstract int stopSample(int index);
+
+ /**
+ * Update sample.
+ * Implies that some parameters affecting rendering have been modified.
+ * @param index device specific reference number to device driver sample
+ */
+ // TODO: The update method exists on a TEMPORARY basis.
+ @Override
+ public abstract void updateSample(int index);
+
+ /**
+ * Mute sample.
+ * @param index device specific reference number to device driver sample
+ */
+ @Override
+ public abstract void muteSample(int index);
+
+ /**
+ * Unmute sample.
+ * @param index device specific reference number to device driver sample
+ */
+ @Override
+ public abstract void unmuteSample(int index);
+
+ /**
+ * Pause sample.
+ * @param index device specific reference number to device driver sample
+ */
+ @Override
+ public abstract void pauseSample(int index);
+
+ /**
+ * Unpause sample.
+ * @param index device specific reference number to device driver sample
+ */
+ @Override
+ public abstract void unpauseSample(int index);
+
+ /*
+ *
+ * Methods that affect fields associated with the sound sample
+ * and that may cause implicit rendering.
+ *
+ */
+ /**
+ * Set gain scale factor applied to sample.
+ * @param index device specific reference number to device driver sample
+ * @param scaleFactor floating point multiplier applied to sample amplitude
+ */
+ @Override
+ public void setSampleGain(int index, float scaleFactor) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.setGain(scaleFactor);
+ return;
+ }
+
+ /**
+ * Set number of times sample is looped.
+ * @param index device specific reference number to device driver sample
+ * @param count number of times sample is repeated
+ */
+ @Override
+ public void setLoop(int index, int count) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.setLoopCount(count);
+ return;
+ }
+
+ /**
+ * Set location of sample.
+ * @param index device specific reference number to device driver sample
+ * @param position point location in virtual world coordinate of sample
+ */
+ @Override
+ public void setPosition(int index, Point3d position) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.setPosition(position);
+ return;
+ }
+
+ /* Set elliptical distance attenuation arrays applied to sample amplitude.
+ * @param index device specific reference number to device driver sample
+ * @param frontDistance defines an array of distance along the position axis
+ * thru which ellipses pass
+ * @param frontAttenuationScaleFactor gain scale factors
+ * @param backDistance defines an array of distance along the negative axis
+ * thru which ellipses pass
+ * @param backAttenuationScaleFactor gain scale factors
+ */
+ @Override
+ public void setDistanceGain(int index,
+ double[] frontDistance, float[] frontAttenuationScaleFactor,
+ double[] backDistance, float[] backAttenuationScaleFactor) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.setDistanceGain(frontDistance, frontAttenuationScaleFactor,
+ backDistance, backAttenuationScaleFactor);
+ return;
+ }
+
+ /**
+ * Set direction vector of sample.
+ * @param index device specific reference number to device driver sample
+ * @param direction vector in virtual world coordinate.
+ */
+ @Override
+ public void setDirection(int index, Vector3d direction) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.setDirection(direction);
+ return;
+ }
+
+ /**
+ * Set angular attenuation arrays affecting angular amplitude attenuation
+ * and angular distance filtering.
+ * @param index device specific reference number to device driver sample
+ * @param filterType denotes type of filtering (on no filtering) applied
+ * to sample.
+ * @param angle array containing angular distances from sound axis
+ * @param attenuationScaleFactor array containing gain scale factor
+ * @param filterCutoff array containing filter cutoff frequencies.
+ * The filter values for each tuples can be set to Sound.NO_FILTER.
+ */
+ @Override
+ public void setAngularAttenuation(int index, int filterType,
+ double[] angle, float[] attenuationScaleFactor, float[] filterCutoff) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.setAngularAttenuation(filterType, angle,
+ attenuationScaleFactor, filterCutoff);
+ return;
+ }
+
+ /**
+ * Set rolloff value for current aural attribute applied to all samples.
+ * @param rolloff scale factor applied to standard speed of sound.
+ */
+ @Override
+ public void setRolloff(float rolloff) {
+ attribs.rolloff = rolloff;
+ return;
+ }
+
+ /**
+ * Set reverberation surface reflection coefficient value for current aural
+ * attribute applied to all samples.
+ * @param coefficient applied to amplitude of reverbation added at each
+ * iteration of reverb processing.
+ */
+ @Override
+ public void setReflectionCoefficient(float coefficient) {
+ attribs.reflectionCoefficient = coefficient;
+ return;
+ }
+
+ /**
+ * Set reverberation delay time for current aural attribute applied to
+ * all samples.
+ * @param reverbDelay amount of time in millisecond between each
+ * iteration of reverb processing.
+ */
+ @Override
+ public void setReverbDelay(float reverbDelay) {
+ attribs.reverbDelay = reverbDelay;
+ return;
+ }
+
+ /**
+ * Set reverberation order for current aural attribute applied to all
+ * samples.
+ * @param reverbOrder number of times reverb process loop is iterated.
+ */
+ @Override
+ public void setReverbOrder(int reverbOrder) {
+ attribs.reverbOrder = reverbOrder;
+ return;
+ }
+
+ /**
+ * Set distance filter for current aural attribute applied to all samples.
+ * @param filterType denotes type of filtering (on no filtering) applied
+ * to all sample based on distance between listener and sound.
+ * @param dist is an attenuation array of distance and low-pass filter values.
+ */
+ @Override
+ public void setDistanceFilter(int filterType,
+ double[] dist, float[] filterCutoff) {
+ attribs.setDistanceFilter(filterType, dist, filterCutoff);
+ return;
+ }
+
+ /**
+ * Set frequency scale factor for current aural attribute applied to all
+ * samples.
+ * @param scaleFactor frequency scale factor applied to samples normal
+ * playback rate.
+ */
+ @Override
+ public void setFrequencyScaleFactor(float scaleFactor) {
+ attribs.frequencyScaleFactor = scaleFactor;
+ return;
+ }
+ /**
+ * Set velocity scale factor for current aural attribute applied to all
+ * samples when Doppler is calculated.
+ * @param scaleFactor scale factor applied to postional samples'
+ * listener-to-soundSource velocity.
+ * playback rate.
+ */
+ @Override
+ public void setVelocityScaleFactor(float scaleFactor) {
+ attribs.velocityScaleFactor = scaleFactor;
+ return;
+ }
+
+ /**
+ * Get number of channels used by a particular sample on the audio device.
+ * @param index device specific reference number to device driver sample
+ * @return number of channels currently being used by this sample.
+ */
+ @Override
+ public int getNumberOfChannelsUsed(int index) {
+ // This method must be overridden by device specific implementation
+ Sample sample = getSample(index);
+ if (sample != null)
+ return (sample.getNumberOfChannelsUsed());
+ else
+ return 0;
+ }
+
+ /**
+ * Get number of channels that would be used by a particular sample on
+ * the audio device given the mute flag passed in as a parameter.
+ * @param index device specific reference number to device driver sample
+ * @param muteFlag denotes the mute state to assume while executing this
+ * query. This mute value does not have to match the current mute state
+ * of the sample.
+ * @return number of channels that would be used by this sample if it
+ * were playing.
+ */
+ @Override
+ public int getNumberOfChannelsUsed(int index, boolean muteFlag) {
+ // This method must be overridden by device specific implementation
+ Sample sample = getSample(index);
+ if (sample != null)
+ return (sample.getNumberOfChannelsUsed());
+ else
+ return 0;
+ }
+
+ /**
+ * Get length of time a sample would play if allowed to play to completion.
+ * @param index device specific reference number to device driver sample
+ * @return length of sample in milliseconds
+ */
+ @Override
+ public long getSampleDuration(int index) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ return (sample.getDuration());
+ else
+ return 0L;
+ }
+
+ /**
+ * Get time this sample begun playing on the audio device.
+ * @param index device specific reference number to device driver sample
+ * @return system clock time sample started
+ */
+ @Override
+ public long getStartTime(int index) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ return (sample.getStartTime());
+ else
+ return 0L;
+ }
+
+ /**
+ * Get reference to the array list of samples
+ * @return reference to samples list
+ * @deprecated unsafe to get reference to samples list with this method.
+ * It's better to directly reference samples list within a synchronized
+ * block which also contains calls to .getSample(index).
+ */
+ protected ArrayList getSampleList() {
+ return (samples);
+ }
+
+ public int getSampleListSize() {
+ return (samples.size());
+ }
+
+ /**
+ * Get specific sample from indexed sample list
+ * Checks for valid index before attempting to get sample from list.
+ * @param index device specific reference number to device driver sample
+ * @return reference to sample; returns null if index out of range.
+ *
+ * @since Java 3D 1.2.1
+ */
+ public Sample getSample(int index) {
+ synchronized(samples) {
+ if ((index >= 0) && (index < samples.size())) {
+ Sample sample = (Sample)samples.get(index);
+ return (sample);
+ }
+ else
+ return null;
+ }
+ }
+
+ /*
+ * Get reference to current aural attribute parameters associated with
+ * this audio device.
+ * @return reference to current aural attribute parameters
+ */
+ public AuralParameters getAuralParameters() {
+ return (attribs);
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/audioengines/AudioEngine3DL2.java b/src/classes/share/org/jogamp/java3d/audioengines/AudioEngine3DL2.java
new file mode 100644
index 0000000..c441063
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/audioengines/AudioEngine3DL2.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.audioengines;
+
+import org.jogamp.java3d.AudioDevice3DL2;
+import org.jogamp.java3d.AuralAttributes;
+import org.jogamp.java3d.PhysicalEnvironment;
+import org.jogamp.java3d.Sound;
+
+
+/**
+ * The AudioEngine3DL2 Class defines an audio output device that generates
+ * sound 'image' from high-level sound parameters passed to it during
+ * scene graph.
+ *
+ *
+ * The methods in this class are meant to be optionally overridden by an
+ * extended class. This extended class would provice device specific code.
+ *
+ *
+ * Error checking on all parameters passed to these methods is already
+ * explicitly being done by the Java 3D core code that calls these methods.
+ *
+ *
+ * These methods should NOT be called by any application if the audio engine
+ * is associated with a Physical Environment used by Java3D Core.
+ *
+ * @since Java 3D 1.3
+ */
+public abstract class AudioEngine3DL2 extends AudioEngine3D implements AudioDevice3DL2 {
+ /**
+ * Construct a new AudioEngine3DL2 with the specified PhysicalEnvironment.
+ * @param physicalEnvironment the physical environment object where we
+ * want access to this device.
+ */
+ public AudioEngine3DL2(PhysicalEnvironment physicalEnvironment ) {
+ super(physicalEnvironment);
+ }
+
+ /*
+ *
+ * Methods that affect AudioEngine3DLD fields that are NOT associated
+ * with a specific sound sample
+ *
+ */
+
+ /**
+ * Pauses audio device engine without closing the device and associated
+ * threads.
+ * Causes all cached sounds to be paused and all streaming sounds to be
+ * stopped.
+ */
+ @Override
+ public abstract void pause();
+
+ /**
+ * Resumes audio device engine (if previously paused) without
+ * reinitializing the device.
+ * Causes all paused cached sounds to be resumed and all streaming
+ * sounds restarted.
+ */
+ @Override
+ public abstract void resume();
+
+ /**
+ * Set overall gain control of all sounds playing on the audio device.
+ * @param scaleFactor scale factor applied to calculated amplitudes for
+ * all sounds playing on this device
+ */
+ @Override
+ public abstract void setGain(float scaleFactor);
+
+ /*
+ *
+ * Methods explicitly affect a particular sound rendering and that
+ * require audio device specific methods that override this class.
+ *
+ */
+
+ /**
+ * Set scale factor applied to sample playback rate for a particular sound
+ * associated with the audio device.
+ * Changing the device sample rate affects both the pitch and speed.
+ * This scale factor is applied to ALL sound types.
+ * Changes (scales) the playback rate of a sound independent of
+ * Doppler rate changes.
+ * @param index device specific reference to device driver sample
+ * @param scaleFactor non-negative factor applied to calculated
+ * amplitudes for all sounds playing on this device
+ * @see Sound#setRateScaleFactor
+ */
+ @Override
+ public void setRateScaleFactor(int index, float scaleFactor) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.setRateScaleFactor(scaleFactor);
+ return;
+ }
+
+
+ /*
+ *
+ * Methods explicitly affect aural attributes of the listening space
+ * used to calculated reverberation during sound rendering.
+ * These require audio device specific methods that override this class.
+ *
+ */
+
+ /**
+ * Set late reflection (referred to as 'reverb') attenuation.
+ * This scale factor is applied to iterative, indistinguishable
+ * late reflections that constitute the tail of reverberated sound in
+ * the aural environment.
+ * This parameter, along with the early reflection coefficient, defines
+ * the reflective/absorptive characteristic of the surfaces in the
+ * current listening region.
+ * @param coefficient late reflection attenuation factor
+ * @see AuralAttributes#setReverbCoefficient
+ */
+ @Override
+ public void setReverbCoefficient(float coefficient) {
+ attribs.reverbCoefficient = coefficient;
+ return;
+ }
+
+
+ /**
+ * Sets the early reflection delay time.
+ * In this form, the parameter specifies the delay time between each order
+ * of reflection (while reverberation is being rendered) explicitly given
+ * in milliseconds.
+ * @param reflectionDelay time between each order of early reflection
+ * @see AuralAttributes#setReflectionDelay
+ */
+ @Override
+ public void setReflectionDelay(float reflectionDelay) {
+ attribs.reflectionDelay = reflectionDelay;
+ return;
+ }
+
+ /**
+ * Set reverb decay time.
+ * Defines the reverberation decay curve.
+ * @param time decay time in milliseconds
+ * @see AuralAttributes#setDecayTime
+ */
+ @Override
+ public void setDecayTime(float time) {
+ attribs.decayTime = time;
+ return;
+ }
+
+ /**
+ * Set reverb decay filter.
+ * This provides for frequencies above the given cutoff frequency to be
+ * attenuated during reverb decay at a different rate than frequencies
+ * below this value. Thus, defining a different reverb decay curve for
+ * frequencies above the cutoff value.
+ * @param frequencyCutoff value of frequencies in Hertz above which a
+ * low-pass filter is applied.
+ * @see AuralAttributes#setDecayFilter
+ */
+ @Override
+ public void setDecayFilter(float frequencyCutoff) {
+ attribs.decayFrequencyCutoff = frequencyCutoff;
+ return;
+ }
+
+ /**
+ * Set reverb diffusion.
+ * This defines the echo dispersement (also referred to as 'echo density').
+ * The value of this reverb parameter is expressed as a percent of the
+ * audio device's minimum-to-maximum values.
+ * @param diffusion percentage expressed within the range of 0.0 and 1.0
+ * @see AuralAttributes#setDiffusion
+ */
+ @Override
+ public void setDiffusion(float diffusion) {
+ attribs.diffusion = diffusion;
+ return;
+ }
+
+ /**
+ * Set reverb density.
+ * This defines the modal density (also referred to as 'spectral
+ * coloration').
+ * The value of this parameter is expressed as a percent of the audio
+ * device's minimum-to-maximum values for this reverb parameter.
+ * @param density reverb density expressed as a percentage,
+ * within the range of 0.0 and 1.0
+ * @see AuralAttributes#setDensity
+ */
+ @Override
+ public void setDensity(float density) {
+ attribs.density = density;
+ return;
+ }
+
+
+ /**
+ * Set the obstruction gain control. This method allows for attenuating
+ * sound waves traveling between the sound source and the listener
+ * obstructed by objects. Direct sound signals/waves for obstructed sound
+ * source are attenuated but not indirect (reflected) waves.
+ * There is no corresponding Core AuralAttributes method at this time.
+ * @param index device specific reference to device driver sample
+ * @param scaleFactor non-negative factor applied to direct sound gain
+ */
+ @Override
+ public void setObstructionGain(int index, float scaleFactor) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.setObstructionGain(scaleFactor);
+ return;
+ }
+
+ /**
+ * Set the obstruction filter control.
+ * This provides for frequencies above the given cutoff frequency
+ * to be attenuated, during while the gain of an obstruction signal
+ * is being calculated, at a different rate than frequencies
+ * below this value.
+ * There is no corresponding Core AuralAttributes method at this time.
+ * @param index device specific reference to device driver sample
+ * @param frequencyCutoff value of frequencies in Hertz above which a
+ * low-pass filter is applied.
+ */
+
+ @Override
+ public void setObstructionFilter(int index, float frequencyCutoff) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.setObstructionFilter(frequencyCutoff);
+ return;
+ }
+
+ /**
+ * Set the occlusion gain control. This method allows for attenuating
+ * sound waves traveling between the sound source and the listener
+ * occluded by objects. Both direct and indirect sound signals/waves
+ * for occluded sound sources are attenuated.
+ * There is no corresponding Core AuralAttributes method at this time.
+ * @param index device specific reference to device driver sample
+ * @param scaleFactor non-negative factor applied to direct sound gain
+ */
+ @Override
+ public void setOcclusionGain(int index, float scaleFactor) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.setObstructionGain(scaleFactor);
+ return;
+ }
+
+ /**
+ * Set the occlusion filter control.
+ * This provides for frequencies above the given cutoff frequency
+ * to be attenuated, during while the gain of an occluded signal
+ * is being calculated, at a different rate than frequencies below
+ * this value.
+ * There is no corresponding Core AuralAttributes method at this time.
+ * @param index device specific reference to device driver sample
+ * @param frequencyCutoff value of frequencies in Hertz above which a
+ * low-pass filter is applied.
+ */
+ @Override
+ public void setOcclusionFilter(int index, float frequencyCutoff) {
+ Sample sample = getSample(index);
+ if (sample != null)
+ sample.setObstructionFilter(frequencyCutoff);
+ return;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/audioengines/AudioEngineThread.java b/src/classes/share/org/jogamp/java3d/audioengines/AudioEngineThread.java
new file mode 100644
index 0000000..eece565
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/audioengines/AudioEngineThread.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.audioengines;
+
+/*
+ * Audio Engine Thread
+ */
+
+
+/**
+ * The Thread Class extended for Audio Device engines that must process
+ * calls dynamically, in 'real-time" to asynchronously change engine
+ * parameters.
+ *
+ *
+ * NOTE: this class is probably not needed for those Audio Device implementations
+ * that handle all dynamic parameters in the low-level audio library.
+ */
+public class AudioEngineThread extends Thread {
+
+ // Debug print flag
+ static final protected boolean debugFlag = false;
+
+
+ protected void debugPrint(String message) {
+ if (debugFlag)
+ System.out.println(message);
+ }
+
+ /**
+ * The classification types.
+ */
+ protected static final int WORK_THREAD = 0x01;
+ protected static final int UPDATE_THREAD = 0x02;
+
+ /**
+ * This runMonitor action puts the thread into an initial wait state
+ */
+ protected static final int WAIT = 0;
+
+ /**
+ * This runMonitor action notifies MasterControl that this thread
+ * has completed and wait.
+ */
+ protected static final int NOTIFY_AND_WAIT = 1;
+
+ /**
+ * This runMonitor action tells the thread to run N number of
+ * iterations.
+ */
+ protected static final int RUN = 2;
+
+ /**
+ * This runMonitor action tells the thread to stop running
+ */
+ protected static final int STOP = 3;
+
+ /**
+ * This indicates that this thread has been activated by MC
+ */
+ protected boolean active = false;
+
+ /**
+ * This indicates that this thread is alive and running
+ */
+ protected boolean running = true;
+
+
+ /**
+ * This indicates that this thread is ready
+ */
+ protected boolean started = false;
+
+ /**
+ * The time values passed into this thread
+ */
+ protected long referenceTime;
+
+ /**
+ * Use to assign threadOpts WAIT_ALL_THREADS
+ */
+ protected long lastWaitTimestamp = 0;
+
+ /**
+ * The type of this thread. It is one of the above constants.
+ */
+ protected int type;
+
+ /**
+ * The classification of this thread. It is one of the above constants.
+ */
+ protected int classification = WORK_THREAD;
+
+ /**
+ * The arguments passed in for this thread
+ */
+ protected Object[] args = null;
+
+ /**
+ * Flag to indicate that user initiate a thread stop
+ */
+ protected boolean userStop = false;
+
+ /**
+ * Flag to indicate that this thread is waiting to be notify
+ */
+ protected boolean waiting = false;
+
+ /**
+ * Some variables used to name threads correctly
+ */
+ protected static int numInstances = 0;
+ protected int instanceNum = -1;
+
+ /**
+ * This constructor simply assigns the given id.
+ */
+ public AudioEngineThread(ThreadGroup t, String threadName) {
+ super(t, threadName);
+ if (debugFlag)
+ debugPrint("AudioEngineThread.constructor("+threadName +")");
+ }
+
+ synchronized int newInstanceNum() {
+ return (++numInstances);
+ }
+
+ int getInstanceNum() {
+ if (instanceNum == -1)
+ instanceNum = newInstanceNum();
+ return instanceNum;
+ }
+
+ /**
+ * This method is defined by all slave threads to implement
+ * one iteration of work.
+ */
+ synchronized public void doWork() {
+ if (debugFlag)
+ debugPrint("AudioEngineThread.doWork()");
+ }
+
+ /**
+ * This initializes this thread. Once this method returns, the thread is
+ * ready to do work.
+ */
+ public void initialize() {
+ if (debugFlag)
+ debugPrint("AudioEngineThread.initialize()");
+ this.start();
+ while (!started) {
+ try {
+ Thread.currentThread().sleep(1, 0);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ /**
+ * This causes the threads run method to exit.
+ */
+ public void finish() {
+ while (!waiting) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {}
+ }
+ runMonitor(STOP, 0,null);
+ }
+
+ /*
+ * This thread controls the syncing of all the canvases attached to
+ * this view.
+ */
+ @Override
+ public void run() {
+ if (debugFlag)
+ debugPrint("AudioEngineThread.run");
+ runMonitor(WAIT, 0, null);
+ while (running) {
+ doWork();
+ runMonitor(WAIT, 0, null);
+ }
+ // resource clean up
+ shutdown();
+ }
+
+ synchronized public void runMonitor(int action, long referenceTime, Object[] args){
+ switch (action) {
+ case WAIT:
+ if (debugFlag)
+ debugPrint("AudioEngineThread.runMonitor(WAIT)");
+ try {
+ started = true;
+ waiting = true;
+ wait();
+ } catch (InterruptedException e) {
+ System.err.println(e);
+ }
+ waiting = false;
+ break;
+ case RUN:
+ if (debugFlag)
+ debugPrint("AudioEngineThread.runMonitor(RUN)");
+ this.referenceTime = referenceTime;
+ this.args = args;
+ notify();
+ break;
+ case STOP:
+ if (debugFlag)
+ debugPrint("AudioEngineThread.runMonitor(STOP)");
+ running = false;
+ notify();
+ break;
+ }
+ }
+
+ public void shutdown() {
+ }
+
+ // default resource clean up method
+ public void cleanup() {
+ active = false;
+ running = true;
+ started = true;
+ lastWaitTimestamp = 0;
+ classification = WORK_THREAD;
+ args = null;
+ userStop = false;
+ referenceTime = 0;
+
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/audioengines/AuralParameters.java b/src/classes/share/org/jogamp/java3d/audioengines/AuralParameters.java
new file mode 100644
index 0000000..c44b148
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/audioengines/AuralParameters.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.audioengines;
+
+
+/**
+ * The AuralParameters Class defines a set of fields that define the
+ * Aural listening environment. Many of the parameters correspond to
+ * AuralAttribute fields.
+ *
+ *
+ * Error checking on all parameters passed to these methods is already
+ * explicitly being done by the Java 3D core code that calls these methods.
+ */
+
+public class AuralParameters
+{
+ // Speed of Sound in meters/milliseconds
+ public static final float SPEED_OF_SOUND = 0.344f;
+ public static final int NO_FILTERING = -1;
+
+ public float rolloff = 1.0f;
+ public float reflectionCoefficient = 0.0f;
+ public float reverbDelay = 40.0f;
+ public int reverbOrder = 0;
+ public float frequencyScaleFactor = 1.0f;
+ public float velocityScaleFactor = 0.0f;
+ int filterType = NO_FILTERING;
+ double[] filterDistance = null;
+ float[] filterCutoff = null;
+
+ /*
+ * @since Java 3D 1.3
+ */
+ public float reverbCoefficient = 1.0f;
+ public float reflectionDelay = 20.0f;
+ public float decayTime = 1000.0f;
+ public float decayFrequencyCutoff = 5000.0f;
+ public float diffusion = 1.0f; // 100%
+ public float density = 1.0f; // 100%
+
+ /**
+ * Construct a new AuralParameters object
+ */
+ public AuralParameters() {
+ frequencyScaleFactor = 1.0f;
+ velocityScaleFactor = 0.0f;
+ rolloff = 1.0f;
+ reflectionCoefficient = 0.0f;
+ reflectionDelay = 20.0f;
+ reverbCoefficient = 1.0f;
+ reverbDelay = 40.0f;
+ reverbOrder = 0;
+ filterType = NO_FILTERING;
+ filterDistance = new double[2]; // start out with array of two
+ filterCutoff = new float[2]; // start out with array of two
+ decayTime = 1000.0f;
+ decayFrequencyCutoff = 5000.0f;
+ diffusion = 1.0f; // 100%
+ density = 1.0f; // 100%
+ }
+
+ public void setDistanceFilter(int filterType, double[] distance,
+ float[] filterCutoff) {
+ boolean error = false;
+ boolean allocate = false;
+ int attenuationLength = 0;
+ if (distance == null || filterCutoff == null) {
+ error = true;
+ }
+ else {
+ attenuationLength = distance.length;
+ if (attenuationLength == 0 || filterType == NO_FILTERING) {
+ error = true;
+ }
+ }
+ if (error) {
+ this.filterType = NO_FILTERING;
+ this.filterDistance = null;
+ this.filterCutoff = null;
+ if (debugFlag)
+ debugPrint("setDistanceFilter NO_FILTERING");
+ return;
+ }
+ this.filterType = filterType;
+ if (debugFlag)
+ debugPrint("setDistanceFilter type = " + filterType);
+ if ((filterDistance == null) || (filterCutoff == null)) {
+ allocate = true;
+ }
+ else if (attenuationLength > filterDistance.length) {
+ allocate = true;
+ }
+ if (allocate) {
+ if (debugFlag)
+ debugPrint("setDistanceFilter length = " + attenuationLength);
+ this.filterDistance = new double[attenuationLength];
+ this.filterCutoff = new float[attenuationLength];
+ }
+ System.arraycopy(distance, 0, this.filterDistance, 0,
+ attenuationLength);
+ System.arraycopy(filterCutoff, 0, this.filterCutoff, 0,
+ attenuationLength);
+
+ if (debugFlag) {
+ debugPrint("setDistanceFilter arrays = ");
+ for (int i=0; i
+ * NOTE: This class is not yet implemented.
+ */
+
+class JSStream extends JSChannel {
+ private static boolean warningReported = false;
+
+ JSStream() {
+ // Report a "not implemented" warning message
+ if (!warningReported) {
+ System.err.println("***");
+ System.err.println("*** WARNING: JavaSoundMixer: Streaming (uncached) audio not implemented");
+ System.err.println("***");
+ warningReported = true;
+ }
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/audioengines/javasound/JSThread.java b/src/classes/share/org/jogamp/java3d/audioengines/javasound/JSThread.java
new file mode 100644
index 0000000..e8a55c9
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/audioengines/javasound/JSThread.java
@@ -0,0 +1,854 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.audioengines.javasound;
+
+/*
+ * JavaSound engine Thread
+ *
+ * IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs
+ * to be rewritten. When this is done, we may or may not need this class.
+ */
+
+import org.jogamp.java3d.audioengines.AudioEngine3D;
+import org.jogamp.java3d.audioengines.AudioEngine3DL2;
+
+/**
+ * The Thread Class extended for JavaSound Mixer specific audio device
+ * calls that dynamically, in 'real-time" change engine parameters
+ * such as volume/gain and sample-rate/frequency(pitch).
+ */
+
+class JSThread extends org.jogamp.java3d.audioengines.AudioEngineThread {
+
+ /**
+ * The thread data for this thread
+ */
+ int totalChannels = 0;
+ /**
+ * flags denoting if dynamic gain or rate interpolation is to be performed
+ */
+ boolean rampGain = false;
+
+ // global thread flat rampRate set true only when setTargetRate called
+ // for any sample. but it is cleared only by doWork when no sample
+ // has a need for the rate to be ramped any further.
+ boolean rampRate = false;
+
+/*** TODO:
+ *
+ * scalefactors applied to current sample rate to determine delta changes
+ * in rate (in Hz)
+ *
+ float currentGain = 1.0f;
+ float targetGain = 1.0f;
+***********/
+
+ // reference to engine that created this thread
+ AudioEngine3D audioEngine = null;
+
+ /**
+ * This constructor simply assigns the given id.
+ */
+ JSThread(ThreadGroup t, AudioEngine3DL2 engine) {
+ super(t, "J3D-JavaSoundThread");
+ audioEngine = engine;
+ // TODO: really get total JavaSound channels
+ totalChannels = 32;
+ if (debugFlag)
+ debugPrint("JSThread.constructor("+t+")");
+ }
+
+
+
+ /**
+ * This method performs one iteration of pending work to do
+ *
+ * Wildly "garbled" sounds was caused by unequal changes in delta
+ * time verses delta distances (resulting in jumps in rate factors
+ * calculated for Doppler. This work thread is meant to smoothly
+ * increment/decrement changes in rate (and other future parameters)
+ * until the target value is reached.
+ */
+ @Override
+ synchronized public void doWork() {
+ if (debugFlag)
+ debugPrint("JSThread.doWork()");
+/*******
+ while (rampRate || rampGain) {
+*********/
+/****** DESIGN
+// Loop while sound is playing, reget attributes and gains/reverb,... params
+// update lowlevel params then read modify then copy to line(s)
+
+can keep my own loop count for streams??? not really
+
+*******/
+ // QUESTION: will size ever get smaller after get performed???
+ int numSamples = audioEngine.getSampleListSize();
+ JSSample sample = null;
+ int numRateRamps = 0;
+ for (int index = 0; index < numSamples; index++) {
+ // loop thru samples looking for ones needing rate incremented
+ sample = (JSSample)audioEngine.getSample(index);
+ if (sample == null)
+ continue;
+ if (sample.getRampRateFlag()) {
+ if (debugFlag)
+ debugPrint(" rampRate true");
+ boolean endOfRampReached = adjustRate(sample);
+ sample.setRampRateFlag(!endOfRampReached);
+ if (!endOfRampReached)
+ numRateRamps++;
+ }
+ // TODO: support changes in gain this way as well
+ }
+ if (numRateRamps > 0) {
+ rampRate = true;
+runMonitor(RUN, 0, null);
+ }
+ else
+ rampRate = false;
+/*********
+ try {
+ Thread.sleep(4);
+ } catch (InterruptedException e){}
+*********/
+/********
+ } // while
+*********/
+ // otherwise do nothing
+ }
+
+ int getTotalChannels() {
+ return (totalChannels);
+ }
+
+ /**
+ * Gradually change rate scale factor
+ *
+ * If the rate change is too great suddenly, it sounds like a
+ * jump, so we need to change gradually over time.
+ * Since an octive delta change up is 2.0 but down is 0.5, forced
+ * "max" rate of change is different for both.
+ * @return true if target rate value was reached
+ */
+ boolean adjustRate(JSSample sample) {
+ // QUESTION: what should max delta rate changes be
+ // Using 1/32 of a half-step (1/12 of an octive)???
+ double maxRateChangeDown = 0.00130213;
+ double maxRateChangeUp = 0.00260417;
+
+ double lastActualRateRatio = sample.getCurrentRateRatio();
+ double requestedRateRatio = sample.getTargetRateRatio();
+ boolean endOfRamp = false; // flag denotes if target rate reached
+ if ( lastActualRateRatio > 0 ) {
+ double sampleRateRatio = requestedRateRatio; // in case diff = 0
+ double diff = 0.0;
+ if (debugFlag) {
+ debugPrint("JSThread.adjustRate: between " +
+ lastActualRateRatio + " & " + requestedRateRatio);
+ }
+ diff = requestedRateRatio - lastActualRateRatio;
+ if (diff > 0.0) { // direction of movement is towards listener
+ // inch up towards the requested target rateRatio
+ if (diff >= maxRateChangeUp) {
+ sampleRateRatio = lastActualRateRatio + maxRateChangeUp;
+ if (debugFlag) {
+ debugPrint(" adjustRate: " +
+ "diff >= maxRateChangeUp so ");
+ debugPrint(" adjustRate: " +
+ " sampleRateRatio incremented up by max");
+ }
+ endOfRamp = false; // target value not reached
+ }
+ /*
+ * otherwise delta change is within tolerance
+ * so use requested RateRatio as calculated w/out change
+ */
+ else {
+ sampleRateRatio = requestedRateRatio;
+ if (debugFlag) {
+ debugPrint(" adjustRate: " +
+ " requestedRateRatio reached");
+ }
+ endOfRamp = true; // reached
+ }
+ }
+ else if (diff < 0.0) { // movement is away from listener
+ // inch down towards the requested target rateRatio
+ if ((-diff) >= maxRateChangeDown) {
+ sampleRateRatio = lastActualRateRatio - maxRateChangeDown;
+ if (debugFlag) {
+ debugPrint(" adjustRate: " +
+ "-(diff) >= maxRateChangeUp so ");
+ debugPrint(" adjustRate: " +
+ " sampleRateRatio incremented down by max ");
+ }
+ endOfRamp = false; // target value not reached
+ }
+ /*
+ * otherwise negitive delta change is within tolerance so
+ * use sampleRateRatio as calculated w/out change
+ */
+ else {
+ sampleRateRatio = requestedRateRatio;
+ if (debugFlag) {
+ debugPrint(" adjustRate: " +
+ " requestedRateRatio reached");
+ }
+ endOfRamp = true; // reached
+ }
+ }
+ else // there is no difference between last set and requested rates
+ return true;
+
+ this.setSampleRate(sample, (float)sampleRateRatio);
+ }
+ else {
+ // this is the first time thru with a rate change
+ if (debugFlag) {
+ debugPrint(" adjustRate: " +
+ "last requested rateRatio not set yet " +
+ "so sampleRateRatio left unchanged");
+ }
+ this.setSampleRate(sample, (float)requestedRateRatio);
+ endOfRamp = false; // target value not reached
+ }
+ return endOfRamp;
+ } // adjustRate
+
+ void setSampleRate(JSSample sample, JSAuralParameters attribs) {
+// TODO:
+ }
+
+ // gain set at start sample time as well
+ void setSampleGain(JSSample sample, JSAuralParameters attribs) {
+/*******
+ // take fields as already set in sample and updates gain
+ // called after sample.render performed
+ if (debugFlag)
+ debugPrint("JSThread.setSampleGain()");
+leftGain, rightGain
+ if (debugFlag) {
+ debugPrint(" " +
+ "StereoGain during update " + leftGain +
+ ", " + rightGain);
+ debugPrint(" " +
+ "StereoDelay during update " + leftDelay +
+ ", " + rightDelay);
+ }
+ int dataType = sample.getDataType();
+ int soundType = sample.getSoundType();
+ boolean muted = sample.getMuteFlag();
+
+ if (debugFlag)
+ debugPrint("setStereoGain for sample "+sample+" " + leftGain +
+ ", " + rightGain);
+ if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA ||
+ dataType == JSAuralParameters.BUFFERED_AUDIO_DATA ) {
+ thread.setSampleGain(sample, leftGain);
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ thread.setSampleGain(
+ ((JSPositionalSample)sample).getSecondIndex(), rightGain); thread.setSampleGain(
+ ((JSPositionalSample)sample).getReverbIndex(), reverbGain);
+ }
+ }
+ // TODO: JavaSound does not support MIDI song panning yet
+ else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
+
+ dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
+ // Stereo samples not used for Midi Song playback
+ thread.setSampleGain(sample, (leftGain+rightGain) );
+ ******
+ // -1.0 far left, 0.0 center, 1.0 far right
+ position = (leftGain - rightGain) / (leftGain + rightGain);
+ JSMidi.setSamplePan(sample, position);
+
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ JSMidi.setSampleGain(
+ ((JSPositionalSample)sample).getSecondIndex(), rightGain); JSMidi.setSampleGain(
+ ((JSPositionalSample)sample).getReverbIndex(), reverbGain);
+ }
+ ******
+ }
+ else {
+ if (debugFlag)
+ debugPrint( "JSThread: Internal Error setSampleGain dataType " +
+ dataType + " invalid");
+ return;
+ }
+ *****
+ // force specific gain
+ // go ahead and set gain immediately
+ this.setSampleGain(sample, scaleFactor);
+ rampGain = false; // disable ramping of gain
+******/
+ }
+
+ void setSampleDelay(JSSample sample, JSAuralParameters attribs) {
+/******
+ // take fields as already set in sample and updates delay
+ // called after sample.render performed
+ // adjust by attrib rolloff
+ float delayTime = attribs.reverbDelay * attribs.rolloff;
+
+ leftDelay = (int)(sample.leftDelay * attribs.rolloff);
+ rightDelay = (int)(sample.rightDelay * attribs.rolloff);
+leftDelay, rightDelay
+ int dataType = sample.getDataType();
+ int soundType = sample.getSoundType();
+ if (debugFlag)
+ debugPrint("setStereoDelay for sample "+sample+" " + leftDelay +
+ ", " + rightDelay);
+ if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ JSStream.setSampleDelay(
+ sample, leftDelay);
+ JSStream.setSampleDelay(
+ ((JSPositionalSample)sample).getSecondIndex(), rightDelay);
+ }
+ else
+ JSStream.setSampleDelay(sample, 0);
+ }
+ else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ JSClip.setSampleDelay(
+ sample, leftDelay);
+ JSClip.setSampleDelay(
+ ((JSPositionalSample)sample).getSecondIndex(), rightDelay);
+ }
+ else
+ JSClip.setSampleDelay(sample, 0);
+ }
+ else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
+
+ dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
+ ********
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ JSMidi.setSampleDelay(
+ sample, leftDelay);
+ JSMidi.setSampleDelay(
+ ((JSPositionalSample)sample).getSecondIndex(), rightDelay);
+ }
+ else
+ ********
+ JSMidi.setSampleDelay(sample, 0);
+ }
+ else {
+ if (debugFlag)
+ debugPrint( "JSThread: Internal Error setSampleDelay dataType " +
+ dataType + " invalid");
+ return;
+ }
+******/
+ }
+
+ void setTargetGain(JSSample sample, float scaleFactor) {
+/**********
+// TODO: implement this
+ // current gain is used as starting scalefactor for ramp
+// TEMPORARY: for now just set gain
+ this.setSampleGain(sample, scaleFactor);
+ rampGain = false;
+ rampGain = true;
+ targetGain = scaleFactor;
+ runMonitor(RUN, 0, null);
+**********/
+ }
+
+ void setRate(JSSample sample, float rateScaleFactor) {
+ // force specific rate
+ // go ahead and set rate immediately
+ // take fields as already set in sample and updates rate
+ // called after sample.render performed
+ this.setSampleRate(sample, rateScaleFactor);
+ // disables rate from being gradually increased or decreased
+ // don't set global thread flat rampRate false just because
+ // one sample's rate is set to a specific value.
+ sample.setRampRateFlag(false);
+ }
+
+ void setTargetRate(JSSample sample, float rateScaleFactor) {
+ // make gradual change in rate factors up or down to target rate
+ sample.setRampRateFlag(true);
+ sample.setTargetRateRatio(rateScaleFactor);
+ rampRate = true;
+ runMonitor(RUN, 0, null);
+ }
+
+// TODO: should have methods for delay and pan as well
+
+ void setSampleGain(JSSample sample, float gain) {
+/***********
+// QUESTION: What needs to be synchronized???
+ if (debugFlag)
+ debugPrint("JSThread.setSampleGain for sample "+sample+" " + gain );
+ int dataType = sample.getDataType();
+ int soundType = sample.getSoundType();
+ boolean muted = sample.getMuteFlag();
+// TODO:
+ if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA)
+{
+ com.sun.j3d.audio.J3DHaeStream.setSampleGain(index, gain);
+ }
+ else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
+ com.sun.j3d.audio.J3DHaeClip.setSampleGain(index, gain);
+ }
+ else {
+ // dataType==JSAuralParameters.STREAMING_MIDI_DATA
+ // dataType==JSAuralParameters.BUFFERED_MIDI_DATA
+ com.sun.j3d.audio.J3DHaeMidi.setSampleGain(index, gain);
+ }
+***************/
+ }
+
+ void setSampleRate(JSSample sample, float scaleFactor) {
+/*********
+// QUESTION: What needs to be synchronized???
+ // TODO: use sample.rateRatio??
+ if (debugFlag)
+ debugPrint("JSThread.setSampleRate sample " +
+ sample + ", scale factor = " + scaleFactor);
+ int dataType = sample.getDataType();
+ int soundType = sample.getSoundType();
+
+// TODO:
+ if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
+ com.sun.j3d.audio.J3DHaeStream.scaleSampleRate(index, scaleFactor);
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ com.sun.j3d.audio.J3DHaeStream.scaleSampleRate(
+ ((JSPositionalSample)sample).getSecondIndex(),
+ scaleFactor);
+ com.sun.j3d.audio.J3DHaeStream.scaleSampleRate(
+ ((JSPositionalSample)sample).getReverbIndex(),
+ scaleFactor);
+ }
+ }
+ else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
+ com.sun.j3d.audio.J3DHaeClip.scaleSampleRate(index, scaleFactor);
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ com.sun.j3d.audio.J3DHaeClip.scaleSampleRate(
+ ((JSPositionalSample)sample).getSecondIndex(),
+ scaleFactor);
+ com.sun.j3d.audio.J3DHaeClip.scaleSampleRate(
+ ((JSPositionalSample)sample).getReverbIndex(),
+ scaleFactor);
+ }
+ }
+ else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
+ dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
+ com.sun.j3d.audio.J3DHaeMidi.scaleSampleRate(index, scaleFactor);
+ // TODO: MIDI only supported for Background sounds
+ }
+***********/
+ sample.setCurrentRateRatio(scaleFactor);
+ }
+
+ boolean startSample(JSSample sample) {
+/**********
+// QUESTION: should this have a return values - error - or not??
+
+ int returnValue = 0;
+ AuralParameters attribs = audioEngine.getAuralParameters();
+ int soundType = sample.getSoundType();
+ boolean muted = sample.getMuteFlag();
+ int dataType = sample.getDataType();
+ int loopCount = sample.getLoopCount();
+ float leftGain = sample.leftGain;
+ float rightGain = sample.rightGain;
+ int leftDelay = (int)(sample.leftDelay * attribs.rolloff);
+ int rightDelay = (int)(sample.rightDelay * attribs.rolloff);
+ if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
+ if (soundType == AudioDevice3D.BACKGROUND_SOUND) {
+ returnValue = JSStream.startSample(sample,
+ loopCount, leftGain);
+ if (debugFlag)
+ debugPrint("JSThread " +
+ "start stream backgroundSound with gain " + leftGain);
+ }
+ else { // soundType is POINT_SOUND or CONE_SOUND
+ // start up main left and right channels for spatial rendered sound
+ returnValue = JSStream.startSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex(),
+ loopCount, leftGain, rightGain, leftDelay, rightDelay);
+ //
+ // start up reverb channel w/out delay even if reverb not on now //
+ float reverbGain = 0.0f;
+ if (!muted && auralParams.reverbFlag) {
+ reverbGain = sample.getGain() *
+ attribs.reflectionCoefficient;
+ }
+ int reverbRtrnVal = JSStream.startSample(
+ ((JSPositionalSample)sample).getReverbIndex(), loopCount, reverbGain);
+ if (debugFlag)
+ debugPrint("JSThread " +
+ "start stream positionalSound with gain "+ leftGain +
+ ", " + rightGain);
+ }
+ }
+
+ else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
+ if (soundType == AudioDevice3D.BACKGROUND_SOUND) {
+ returnValue = JSClip.startSample(sample,
+ loopCount, leftGain );
+ if (debugFlag)
+ debugPrint("JSThread " +
+ "start buffer backgroundSound with gain " + leftGain);
+ }
+ else { // soundType is POINT_SOUND or CONE_SOUND
+ // start up main left and right channels for spatial rendered sound
+ returnValue = JSClip.startSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex(),
+ loopCount, leftGain, rightGain, leftDelay, rightDelay);
+ //
+ // start up reverb channel w/out delay even if reverb not on now //
+ float reverbGain = 0.0f;
+ if (!muted && auralParams.reverbFlag) {
+ reverbGain = sample.getGain() *
+ attribs.reflectionCoefficient;
+ }
+ int reverbRtrnVal = JSClip.startSample(
+ ((JSPositionalSample)sample).getReverbIndex(),
+ loopCount, reverbGain);
+
+ if (debugFlag)
+ debugPrint("JSThread " +
+ "start stream positionalSound with gain " + leftGain
+ + ", " + rightGain);
+ }
+ }
+ else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
+ dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
+ if (soundType == AudioDevice3D.BACKGROUND_SOUND) {
+ returnValue = JSMidi.startSample(sample,
+ loopCount, leftGain);
+ if (debugFlag)
+ debugPrint("JSThread " +
+ "start Midi backgroundSound with gain " + leftGain);
+ }
+ else { // soundType is POINT_SOUND or CONE_SOUND
+ // start up main left and right channels for spatial rendered sound
+ returnValue = JSMidi.startSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex(),
+ loopCount, leftGain, rightGain, leftDelay, rightDelay);
+ *******
+ // TODO: positional MIDI sounds not supported.
+ // The above startSamples really just start on sample
+ // Don't bother with reverb channel for now.
+
+ //
+ // start up reverb channel w/out delay even if reverb not on now //
+ float reverbGain = 0.0f;
+ if (!muted && auralParams.reverbFlag) {
+ reverbGain = sample.getGain() *
+ attribs.reflectionCoefficient;
+ }
+ int reverbRtrnVal = JSMidi.startSample(
+ ((JSPositionalSample)sample).getReverbIndex(), loopCount, reverbGain);
+ *******
+ if (debugFlag)
+ debugPrint("JSThread " +
+ "start Midi positionalSound with gain "+ leftGain +
+ ", " + rightGain);
+ }
+ }
+
+ else {
+ if (debugFlag)
+ debugPrint(
+ "JSThread: Internal Error startSample dataType " +
+ dataType + " invalid");
+ return false;
+ }
+ // TODO: have to look at return values and conditionally return 'success'
+**********/
+ return true;
+ }
+
+ boolean stopSample(JSSample sample) {
+/***********
+// QUESTION: should this have a return values - error - or not??
+ int dataType = sample.getDataType();
+ int soundType = sample.getSoundType();
+
+ int returnValue = 0;
+ if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ returnValue = JSStream.stopSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex());
+ returnValue = JSStream.stopSample(
+ ((JSPositionalSample)sample).getReverbIndex());
+ }
+ else
+ returnValue = JSStream.stopSample(sample);
+ }
+ else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ returnValue = JSClip.stopSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex());
+ returnValue = JSClip.stopSample(
+ ((JSPositionalSample)sample).getReverbIndex());
+ }
+ else
+ returnValue = JSClip.stopSample(sample);
+ }
+ else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
+ dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
+
+ *****
+ // TODO: positional sounds NOT supported yet
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ returnValue = JSMidi.stopSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex());
+ returnValue = JSMidi.stopSample(
+ ((JSPositionalSample)sample).getReverbIndex());
+ }
+ else
+ *****
+ returnValue = JSMidi.stopSample(sample);
+ }
+ else {
+ if (debugFlag)
+ debugPrint( "JSThread: Internal Error stopSample dataType " +
+ dataType + " invalid");
+ return -1;
+ }
+
+************/
+ return true;
+ }
+
+
+ void pauseSample(JSSample sample) {
+/**********
+ int dataType = sample.getDataType();
+ int soundType = sample.getSoundType();
+ int returnValue = 0;
+ if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ returnValue = JSStream.pauseSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex());
+ returnValue = JSStream.pauseSample(
+ ((JSPositionalSample)sample).getReverbIndex());
+ }
+ else
+ returnValue = JSStream.pauseSample(sample);
+ }
+ else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ returnValue = JSClip.pauseSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex());
+ returnValue = JSClip.pauseSample(
+ ((JSPositionalSample)sample).getReverbIndex());
+ }
+ else
+ returnValue = JSClip.pauseSample(sample);
+ }
+ else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
+
+ dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
+ *******
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ returnValue = JSMidi.pauseSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex());
+ returnValue = JSMidi.pauseSample(
+ ((JSPositionalSample)sample).getReverbIndex());
+ }
+ else
+ *****
+ returnValue = JSMidi.pauseSample(sample);
+ }
+ else {
+ if (debugFlag)
+ debugPrint(
+ "JSThread: Internal Error pauseSample dataType " +
+ dataType + " invalid");
+ }
+ if (returnValue < 0) {
+ if (debugFlag)
+ debugPrint( "JSThread: Internal Error pauseSample " +
+ "for sample " + sample + " failed");
+ }
+// QUESTION: return value or not???
+ return;
+*************/
+ }
+
+ void unpauseSample(JSSample sample) {
+/**************
+ int dataType = sample.getDataType();
+ int soundType = sample.getSoundType();
+ int returnValue = 0;
+ if (dataType == JSAuralParameters.STREAMING_AUDIO_DATA) {
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ returnValue = JSStream.unpauseSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex());
+ returnValue = JSStream.unpauseSample(
+ ((JSPositionalSample)sample).getReverbIndex());
+ }
+ else
+ returnValue = JSStream.unpauseSample(sample);
+ }
+ else if (dataType == JSAuralParameters.BUFFERED_AUDIO_DATA) {
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ returnValue = JSClip.unpauseSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex());
+ returnValue = JSClip.unpauseSample(
+ ((JSPositionalSample)sample).getReverbIndex());
+ }
+ else
+ returnValue = JSClip.unpauseSample(sample);
+ }
+ else if (dataType == JSAuralParameters.STREAMING_MIDI_DATA ||
+
+ dataType == JSAuralParameters.BUFFERED_MIDI_DATA) {
+ *********
+ // TODO: positional Midi sounds
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ returnValue = JSMidi.unpauseSamples(sample,
+ ((JSPositionalSample)sample).getSecondIndex());
+ returnValue = JSMidi.unpauseSample(
+ ((JSPositionalSample)sample).getReverbIndex());
+ }
+ else
+ *********
+ returnValue = JSMidi.unpauseSample(sample);
+ }
+ else {
+ if (debugFlag)
+ debugPrint(
+ "JSThread: Internal Error unpauseSample dataType " + dataType + " invalid");
+ }
+ if (returnValue < 0) {
+ if (debugFlag)
+ debugPrint( "JSThread: Internal Error unpauseSample " +
+ "for sample " + sample + " failed");
+
+ }
+// QUESTION: return value or not???
+ return;
+*************/
+ }
+
+// TODO:
+ void muteSample(JSSample sample) {
+ // is this already muted? if so don't do anytning
+
+ // This determines if mute is done as a zero gain or
+ // as a stop, advance restart...
+ }
+
+// TODO:
+ void unmuteSample(JSSample sample) {
+ if (debugFlag)
+ debugPrint( "JSThread.unmuteSample not implemented");
+ }
+
+ int startStreams() {
+// QUESTION: return value or not???
+ return 0;
+ }
+ int startStream() {
+// QUESTION: return value or not???
+ return 0;
+ }
+ int startClips() {
+// QUESTION: return value or not???
+ return 0;
+ }
+ int startClip() {
+// QUESTION: return value or not???
+ return 0;
+ }
+
+ /**
+ * This initializes this thread. Once this method returns, the thread is
+ * ready to do work.
+ */
+ @Override
+ public void initialize() {
+ super.initialize();
+ // this.setPriority(Thread.MAX_PRIORITY);
+ // TODO: init values of fields???
+ if (debugFlag)
+ debugPrint("JSThread.initialize()");
+ // TODO: doesn't do anything yet
+ }
+
+ /**
+ * Code to close the device
+ * @return flag: true is closed sucessfully, false if error
+ */
+ boolean close() {
+ // TODO: for now do nothing
+ return false;
+ }
+
+ @Override
+ public void shutdown() {
+ }
+
+
+
+
+ // default resource clean up method
+ @Override
+ public void cleanup() {
+ super.cleanup();
+ if (debugFlag)
+ debugPrint("JSThread.cleanup()");
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/audioengines/javasound/JavaSoundMixer.java b/src/classes/share/org/jogamp/java3d/audioengines/javasound/JavaSoundMixer.java
new file mode 100644
index 0000000..f1691e9
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/audioengines/javasound/JavaSoundMixer.java
@@ -0,0 +1,984 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+/*
+ * Audio device driver using Java Sound Mixer Engine.
+ *
+ * IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs
+ * to be rewritten.
+ */
+
+package org.jogamp.java3d.audioengines.javasound;
+
+import org.jogamp.java3d.AudioDevice3D;
+import org.jogamp.java3d.MediaContainer;
+import org.jogamp.java3d.PhysicalEnvironment;
+import org.jogamp.java3d.Sound;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Vector3d;
+
+import org.jogamp.java3d.audioengines.AudioEngine3DL2;
+import org.jogamp.java3d.audioengines.Sample;
+
+/**
+ * The JavaSoundMixer Class defines an audio output device that accesses
+ * JavaSound functionality stream data.
+ */
+public class JavaSoundMixer extends AudioEngine3DL2 {
+
+ // Debug print flags and methods
+ static final boolean debugFlag = false;
+ static final boolean internalErrors = false;
+
+ void debugPrint(String message) {
+ if (debugFlag)
+ System.out.println(message);
+ }
+
+ void debugPrintln(String message) {
+ if (debugFlag)
+ System.out.println(message);
+ }
+
+ // Determines method to call for added or setting sound into ArrayList
+ static final int ADD_TO_LIST = 1;
+ static final int SET_INTO_LIST = 2;
+
+ // current Aural Parameters = Aural Attributes from core + JavaSound
+ // specific fields, including reverberation parameters.
+ JSAuralParameters auralParams = null;
+
+ // thread for dynamically changing audio parameters such as volume
+ // and sample rate.
+ JSThread thread = null;
+
+ /*
+ * new fields in extended class
+ */
+ protected float deviceGain = 1.0f;
+
+ protected static final int NOT_PAUSED = 0;
+ protected static final int PAUSE_PENDING = 1;
+ protected static final int PAUSED = 2;
+ protected static final int RESUME_PENDING = 3;
+ protected int pause = NOT_PAUSED;
+
+ /*
+ * Construct a new JavaSoundMixer with the specified P.E.
+ * @param physicalEnvironment the physical environment object where we
+ * want access to this device.
+ */
+ public JavaSoundMixer(PhysicalEnvironment physicalEnvironment ) {
+ super(physicalEnvironment);
+ thread = new JSThread(Thread.currentThread().getThreadGroup(), this);
+ }
+
+ /**
+ * Query total number of channels available for sound rendering
+ * for this audio device.
+ * Overridden method from AudioEngine.
+ * @return number of maximum voices play simultaneously on JavaSound Mixer.
+ */
+ @Override
+ public int getTotalChannels() {
+ if (thread != null)
+ return thread.getTotalChannels();
+ else
+ return 32;
+ }
+
+ /**
+ * Code to initialize the device
+ * New interface to mixer/engine specific methods
+ * @return flag: true is initialized sucessfully, false if error
+ */
+ @Override
+ public boolean initialize() {
+ if (thread == null) {
+ return false;
+ }
+ // init JavaSound dynamic thread
+ thread.initialize();
+ auralParams = new JSAuralParameters();
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: JSStream.initialize returned true");
+ return true;
+ }
+
+ /**
+ * Code to close the device.
+ * New interface to mixer/engine specific methods
+ * @return flag: true is closed sucessfully, false if error
+ */
+ @Override
+ public boolean close() {
+ if (thread == null)
+ return false;
+ if (thread.close()) {
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: JSStream.close returned true");
+ return true;
+ }
+ else {
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: JSStream.close returned false");
+ return false;
+ }
+ }
+
+
+ /**
+ * Code to load sound data into a channel of device mixer.
+ * Load sound as one or mores sample into the Java Sound Mixer:
+ * a) as either a STREAM or CLIP based on whether cached is enabled
+ * b) positional and directional sounds use three samples per
+ * sound
+ * Overriden method from AudioEngine3D.
+ *
+ * Sound type determines if this is a Background, Point or Cone
+ * sound source and thus the JSXxxxSample object type
+ * Call JSXxxxxSample.loadSample()
+ * If no error
+ * Get the next free index in the samples list.
+ * Store a reference to JSXxxxSample object in samples list.
+ * @return index to the sample in samples list.
+ */
+ @Override
+ public int prepareSound(int soundType, MediaContainer soundData) {
+ int index = JSSample.NULL_SAMPLE;
+ int methodType = ADD_TO_LIST;
+ if (soundData == null)
+ return JSSample.NULL_SAMPLE;
+ synchronized(samples) {
+ // for now force to just add to end of samples list
+ int samplesSize = samples.size();
+ index = samplesSize;
+ samples.ensureCapacity(index+1);
+ boolean error = false;
+
+ if (soundType == AudioDevice3D.CONE_SOUND) {
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer.prepareSound type=CONE");
+ JSDirectionalSample dirSample = new JSDirectionalSample();
+ error = dirSample.load(soundData);
+ if (error)
+ return JSSample.NULL_SAMPLE;
+ if (methodType == SET_INTO_LIST)
+ samples.set(index, dirSample);
+ else
+ samples.add(index, dirSample);
+ /*
+ * Since no error occurred while loading, save all the
+ * characterstics for the sound in the sample.
+ */
+ dirSample.setDirtyFlags(0xFFFF);
+ dirSample.setSoundType(soundType);
+ dirSample.setSoundData(soundData);
+
+ }
+ else if (soundType == AudioDevice3D.POINT_SOUND) {
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer.prepareSound type=POINT");
+ JSPositionalSample posSample = new JSPositionalSample();
+ error = posSample.load(soundData);
+ if (error)
+ return JSSample.NULL_SAMPLE;
+ if (methodType == SET_INTO_LIST)
+ samples.set(index, posSample);
+ else
+ samples.add(index, posSample);
+ posSample.setDirtyFlags(0xFFFF);
+ posSample.setSoundType(soundType);
+ posSample.setSoundData(soundData);
+ }
+ else { // soundType == AudioDevice3D.BACKGROUND_SOUND
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer.prepareSound type=BACKGROUND");
+ JSSample sample = null;
+ sample = new JSSample();
+ error = sample.load(soundData);
+ if (error)
+ return JSSample.NULL_SAMPLE;
+ if (methodType == SET_INTO_LIST)
+ samples.set(index, sample);
+ else
+ samples.add(index, sample);
+ sample.setDirtyFlags(0xFFFF);
+ sample.setSoundType(soundType);
+ sample.setSoundData(soundData);
+ }
+ }
+
+ if (debugFlag) {
+ debugPrint(" prepareSound type = "+soundType);
+ debugPrintln("JavaSoundMixer.prepareSound returned "+index);
+ }
+ return index;
+ }
+
+ /**
+ * Clears the fields associated with sample data for this sound.
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public void clearSound(int index) {
+ // TODO: call JSXXXX clear method
+ JSSample sample = null;
+ if ( (sample = (JSSample)getSample(index)) == null)
+ return;
+ sample.clear();
+ synchronized(samples) {
+ samples.set(index, null);
+ }
+ }
+
+ /**
+ * Save a reference to the local to virtual world coordinate space
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public void setVworldXfrm(int index, Transform3D trans) {
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: setVworldXfrm for index " + index);
+ super.setVworldXfrm(index, trans);
+ if (debugFlag) {
+ double[] matrix = new double[16];
+ trans.get(matrix);
+ debugPrintln("JavaSoundMixer column-major transform ");
+ debugPrintln("JavaSoundMixer " + matrix[0]+", "+matrix[1]+
+ ", "+matrix[2]+", "+matrix[3]);
+ debugPrintln("JavaSoundMixer " + matrix[4]+", "+matrix[5]+
+ ", "+matrix[6]+", "+matrix[7]);
+ debugPrintln("JavaSoundMixer " + matrix[8]+", "+matrix[9]+
+ ", "+matrix[10]+", "+matrix[11]);
+ debugPrintln("JavaSoundMixer " + matrix[12]+", "+matrix[13]+
+ ", "+matrix[14]+", "+matrix[15]);
+ }
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return;
+ int soundType = sample.getSoundType();
+
+ if (soundType == AudioDevice3D.CONE_SOUND) {
+ JSDirectionalSample dirSample = null;
+ if ((dirSample = (JSDirectionalSample)getSample(index)) == null)
+ return;
+ dirSample.setXformedDirection();
+ dirSample.setXformedPosition();
+ // flag that VirtualWorld transform set
+ dirSample.setVWrldXfrmFlag(true);
+ }
+ else if (soundType == AudioDevice3D.POINT_SOUND) {
+ JSPositionalSample posSample = null;
+ if ((posSample = (JSPositionalSample)getSample(index)) == null)
+ return;
+ posSample.setXformedPosition();
+ // flag that VirtualWorld transform set
+ posSample.setVWrldXfrmFlag(true);
+ }
+ return;
+ }
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public void setPosition(int index, Point3d position) {
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: setPosition for index " + index);
+ super.setPosition(index, position);
+ JSPositionalSample posSample = null;
+ if ((posSample = (JSPositionalSample)getSample(index)) == null)
+ return;
+ int soundType = posSample.getSoundType();
+ if ( (soundType == AudioDevice3D.POINT_SOUND) ||
+ (soundType == AudioDevice3D.CONE_SOUND) ) {
+ posSample.setXformedPosition();
+ }
+ return;
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public void setDirection(int index, Vector3d direction) {
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: setDirection for index " + index);
+ super.setDirection(index, direction);
+ JSDirectionalSample dirSample = null;
+ if ((dirSample = (JSDirectionalSample)getSample(index)) == null)
+ return;
+ int soundType = dirSample.getSoundType();
+ if (soundType == AudioDevice3D.CONE_SOUND) {
+ dirSample.setXformedDirection();
+ }
+ return;
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public void setReflectionCoefficient(float coefficient) {
+ super.setReflectionCoefficient(coefficient);
+ auralParams.reverbDirty |= JSAuralParameters.REFLECTION_COEFF_CHANGED;
+ return;
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public void setReverbDelay(float reverbDelay) {
+ super.setReverbDelay(reverbDelay);
+ auralParams.reverbDirty |= JSAuralParameters.REVERB_DELAY_CHANGED;
+ return;
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public void setReverbOrder(int reverbOrder) {
+ super.setReverbOrder(reverbOrder);
+ auralParams.reverbDirty |= JSAuralParameters.REVERB_ORDER_CHANGED;
+ return;
+ }
+
+ /*
+ * QUESTION: if this is used, for now, exclusively, to start a Background
+ * or any single sampled Sounds, why are there if-else cases to handle
+ * Point and Cone sounds??
+ *
+ * For now background sounds are not reverberated
+ *
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public int startSample(int index) {
+ // TODO: Rewrite this function
+
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: STARTSample for index " + index);
+
+ JSSample sample = null;
+ if ( ( (sample = (JSSample)getSample(index)) == null) ||
+ thread == null )
+ return JSSample.NULL_SAMPLE;
+
+ int soundType = sample.getSoundType();
+ boolean muted = sample.getMuteFlag();
+ if (muted) {
+ if (debugFlag)
+ debugPrintln(" MUTEd start");
+ thread.muteSample(sample);
+ if (soundType != AudioDevice3D.BACKGROUND_SOUND)
+ setFilter(index, false, Sound.NO_FILTER);
+ }
+ else {
+ sample.render(sample.getDirtyFlags(), getView(), auralParams);
+ this.scaleSampleRate(index, sample.rateRatio);
+ // filtering
+ if (soundType != AudioDevice3D.BACKGROUND_SOUND)
+ setFilter(index, sample.getFilterFlag(), sample.getFilterFreq());
+ }
+
+ boolean startSuccessful;
+ startSuccessful = thread.startSample(sample);
+
+ sample.channel.startSample(sample.getLoopCount(), sample.getGain(), 0);
+
+ if (!startSuccessful) {
+ if (internalErrors)
+ debugPrintln(
+ "JavaSoundMixer: Internal Error startSample for index " +
+ index + " failed");
+ return JSSample.NULL_SAMPLE;
+ }
+ else {
+ if (debugFlag)
+ debugPrintln(" startSample worked, " +
+ "returning " + startSuccessful);
+ // NOTE: Set AuralParameters AFTER sound started
+ // Setting AuralParameters before you start sound doesn't work
+ if (!muted) {
+ if (auralParams.reverbDirty > 0) {
+ if (debugFlag) {
+ debugPrintln("startSample: reverb settings are:");
+ debugPrintln(" coeff = "+
+ auralParams.reflectionCoefficient +
+ ", delay = " + auralParams.reverbDelay +
+ ", order = " + auralParams.reverbOrder);
+ }
+ float delayTime = auralParams.reverbDelay * auralParams.rolloff;
+ calcReverb(sample);
+ }
+ // NOTE: it apprears that reverb has to be reset in
+ // JavaSound engine when sound re-started??
+ // force reset of reverb parameters when sound is started
+ setReverb(sample);
+ }
+ return index;
+ }
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public int stopSample(int index) {
+ // TODO: Rewrite this function
+
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: STOPSample for index " + index);
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return -1;
+
+ int dataType = sample.getDataType();
+ int soundType = sample.getSoundType();
+
+ boolean stopSuccessful = true;
+ stopSuccessful = thread.stopSample(sample);
+
+ sample.channel.stopSample();
+
+ if (!stopSuccessful) {
+ if (internalErrors)
+ debugPrintln( "JavaSoundMixer: Internal Error stopSample(s) for index " +
+ index + " failed");
+ return -1;
+ }
+ else {
+ // set fields in sample to reset for future start
+ sample.reset();
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: stopSample for index " +
+ index + " worked, returning " + stopSuccessful);
+ return 0;
+ }
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public void pauseSample(int index) {
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: PAUSESample for index " + index);
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return;
+ // check thread != null
+ thread.pauseSample(sample);
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public void unpauseSample(int index) {
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: UNPAUSESample for index " + index);
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return;
+ thread.unpauseSample(sample);
+ }
+
+ /*
+ * Force thread to update sample.
+ * Overriden method from AudioEngine3D.
+ */
+
+ @Override
+ public void updateSample(int index) {
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: UPDATESample for index " + index);
+ JSSample sample = null;
+ if ( ( (sample = (JSSample)getSample(index)) == null) ||
+ thread == null )
+ return;
+
+ int soundType = sample.getSoundType();
+ boolean muted = sample.getMuteFlag();
+
+ if (muted) {
+ if (soundType != AudioDevice3D.BACKGROUND_SOUND)
+ setFilter(index, false, Sound.NO_FILTER);
+ thread.muteSample(sample);
+ if (debugFlag)
+ debugPrintln(" Mute during update");
+ }
+ else {
+ // If reverb parameters changed resend to audio device
+ if (auralParams.reverbDirty > 0) {
+ if (debugFlag) {
+ debugPrintln("updateSample: reverb settings are:");
+ debugPrintln(" coeff = " + auralParams.reflectionCoefficient+
+ ", delay = " + auralParams.reverbDelay +
+ ", order = " + auralParams.reverbOrder);
+ }
+ float delayTime = auralParams.reverbDelay * auralParams.rolloff;
+ calcReverb(sample);
+ }
+ // TODO: Only re-set reverb if values different
+ // For now force reset to ensure that reverb is currently correct
+ setReverb(sample); // ensure reverb is current/correct
+
+ // TODO: For now sum left & rightGains for reverb gain
+ float reverbGain = 0.0f;
+ if (!muted && auralParams.reverbFlag) {
+ reverbGain = sample.getGain() * auralParams.reflectionCoefficient;
+ }
+
+ sample.render(sample.getDirtyFlags(), getView(), auralParams);
+
+ // filtering
+ if (soundType != AudioDevice3D.BACKGROUND_SOUND)
+ setFilter(index, sample.getFilterFlag(), sample.getFilterFreq());
+ thread.setSampleGain(sample, auralParams);
+ thread.setSampleRate(sample, auralParams);
+ thread.setSampleDelay(sample, auralParams);
+ }
+ return;
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public void muteSample(int index) {
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return;
+
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: muteSample");
+ sample.setMuteFlag(true);
+ thread.muteSample(sample);
+ return;
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public void unmuteSample(int index) {
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return;
+
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: unmuteSample");
+ sample.setMuteFlag(false);
+
+ // since while mute the reverb type and state was not updated...
+ // Reverb has to be recalculated when sound is unmuted .
+ auralParams.reverbDirty = 0xFFFF; // force an update of reverb params
+ sample.setDirtyFlags(0xFFFF); // heavy weight forcing of gain/delay update
+
+ // TODO: force an update of ALL parameters that could have changed
+ // while muting disabled...
+
+ thread.unmuteSample(sample);
+ return;
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public long getSampleDuration(int index) {
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return Sample.DURATION_UNKNOWN;
+ long duration;
+
+ if (sample != null)
+ duration = sample.getDuration();
+ else
+ duration = Sample.DURATION_UNKNOWN;
+ if (debugFlag)
+ debugPrintln(" return duration " + duration);
+ return duration;
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public int getNumberOfChannelsUsed(int index) {
+ /*
+ * Calls same method with different signature containing the
+ * sample's mute flag passed as the 2nd parameter.
+ */
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return 0;
+ else
+ return getNumberOfChannelsUsed(index, sample.getMuteFlag());
+ }
+
+ /**
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public int getNumberOfChannelsUsed(int index, boolean muted) {
+ /*
+ * The JavaSoundMixer implementation uses THREE channels to render
+ * the stereo image of each Point and Cone Sounds:
+ * Two for rendering the right and left portions of the rendered
+ * spatialized sound image - panned hard right or left respectively.
+ * This implementation uses one channel to render Background sounds
+ * whether the sample is mono or stereo.
+ *
+ * TODO: When muted is implemented, that flag should be check
+ * so that zero is returned.
+ */
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return 0;
+
+ int soundType = sample.getSoundType();
+ int dataType = sample.getDataType();
+
+ // TODO: for now positional Midi sound used only 1 sample
+ if (dataType == JSSample.STREAMING_MIDI_DATA ||
+ dataType == JSSample.BUFFERED_MIDI_DATA)
+ return 1;
+
+ if (soundType == BACKGROUND_SOUND)
+ return 1;
+ else // for Point and Cone sounds
+ return 3;
+ }
+
+ /*
+ * Overriden method from AudioEngine3D.
+ */
+ @Override
+ public long getStartTime(int index) {
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return 0L;
+ if (sample.channel == null)
+ return 0L;
+ return (long)sample.channel.startTime;
+ }
+
+ /*
+ * Methods called during rendering
+ */
+ void scaleSampleRate(int index, float scaleFactor) {
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: scaleSampleRate index " +
+ index + ", scale factor = " + scaleFactor);
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null ||
+ thread == null)
+ return;
+ int dataType = sample.getDataType();
+ if (debugFlag)
+ debugPrintln(" scaleSampleRate.dataType = " + dataType +
+ "using sample " + sample + " from samples[" +
+ index +"]");
+ int soundType = sample.getSoundType();
+
+ if (dataType == JSSample.STREAMING_AUDIO_DATA ||
+ dataType == JSSample.BUFFERED_AUDIO_DATA) {
+ thread.setSampleRate(sample, scaleFactor);
+ /**********
+ // TODO:
+ if (soundType != AudioDevice3D.BACKGROUND_SOUND) {
+ thread.setSampleRate( ((JSPositionalSample)sample).getSecondIndex(),
+ scaleFactor);
+ thread.setSampleRate(((JSPositionalSample)sample).getReverbIndex(),
+ scaleFactor);
+ }
+ **********/
+ }
+ else if (dataType == JSSample.STREAMING_MIDI_DATA ||
+ dataType == JSSample.BUFFERED_MIDI_DATA) {
+ thread.setSampleRate(sample, scaleFactor);
+ /**********
+ if (soundType != AudioDevice3D.BACKGROUND_SOUND) {
+ thread.setSampleRate(((JSPositionalSample)sample).getSecondIndex(),
+ scaleFactor);
+ thread.setSampleRate(((JSPositionalSample)sample).getReverbIndex(),
+ scaleFactor);
+ }
+ **********/
+ }
+ else {
+ if (internalErrors)
+ debugPrintln(
+ "JavaSoundMixer: Internal Error scaleSampleRate dataType " +
+ dataType + " invalid");
+ }
+ }
+
+ /*
+ * Methods called during rendering
+ */
+ void calcReverb(JSSample sample) {
+ /*
+ * Java Sound reverb parameters are a subset of Java 3D parameters
+ */
+ int dataType = sample.getDataType();
+ int soundType = sample.getSoundType();
+ float decay = auralParams.decayTime;
+ float delay = auralParams.reverbDelay * auralParams.rolloff;
+ float reflection = auralParams.reflectionCoefficient;
+ int order = auralParams.reverbOrder;
+ /*
+ * Remember Coeff change is choosen over Order change if BOTH made
+ * otherwise the last one changed take precidence.
+ */
+ if (auralParams.reflectionCoefficient == 0.0f ||
+ auralParams.reverbCoefficient == 0.0f)
+ auralParams.reverbFlag = false;
+ else {
+ auralParams.reverbFlag = true;
+ if (order > 0) {
+ // clamp reverb decay time to order*delay
+ float clampedTime = order * delay;
+ if ( clampedTime < decay)
+ decay = clampedTime;
+ }
+ if (delay < 100.0f) {
+ // "small" reverberant space
+ if (decay <= 1500.0f)
+ auralParams.reverbType = 2;
+ else
+ auralParams.reverbType = 4;
+ }
+ else if (delay < 500.0f) {
+ // "medium" reverberant space
+ if (decay <= 1500.0f)
+ auralParams.reverbType = 3;
+ else
+ auralParams.reverbType = 6;
+ }
+ else { // delay >= 500.0f
+ // "large" reverberant space
+ if (decay <= 1500.0f)
+ auralParams.reverbType = 6;
+ else
+ auralParams.reverbType = 5;
+ }
+ }
+
+ if (debugFlag)
+ debugPrintln("JavaSoundMixer: setReverb for " +
+ sample + ", type = " + auralParams.reverbType + ", flag = " + auralParams.reverbFlag);
+
+ auralParams.reverbDirty = 0; // clear the attribute reverb dirty flags
+ }
+
+ /*
+ * Interal method for setting reverb parameters called during rendering.
+ * This not called by SoundScheduler.
+ */
+ void setReverb(JSSample sample) {
+ /*
+ * Only third sample of multisample sounds has reverb parameters set.
+ * For now, only positional and directional sounds are reverberated.
+ */
+ int soundType = sample.getSoundType();
+ int dataType = sample.getDataType();
+
+ // QUESTION: Should reverb be applied to background sounds?
+ if ( (soundType == AudioDevice3D.CONE_SOUND) ||
+ (soundType == AudioDevice3D.POINT_SOUND) ) {
+ if (debugFlag)
+ debugPrintln("setReverb called with type, on = " +
+ auralParams.reverbType + ", " + auralParams.reverbFlag);
+ if (sample == null)
+ return;
+ JSPositionalSample posSample = (JSPositionalSample)sample;
+ if (posSample.channel == null)
+ return;
+
+ /**********
+ // NOTE: no support for reverb channel yet...
+ int reverbIndex = posSample.getReverbIndex();
+ **********/
+ if (dataType == JSSample.STREAMING_AUDIO_DATA) {
+ JSStream stream = (JSStream)posSample.channel;
+ stream.setSampleReverb(auralParams.reverbType, auralParams.reverbFlag);
+ }
+ else if (dataType == JSSample.BUFFERED_AUDIO_DATA) {
+ JSClip clip = (JSClip)posSample.channel;
+ clip.setSampleReverb(auralParams.reverbType, auralParams.reverbFlag);
+ }
+ /**********
+ // TODO:
+ else if (dataType == JSSample.STREAMING_MIDI_DATA ||
+ dataType == JSSample.BUFFERED_MIDI_DATA) {
+ JSMidi.setSampleReverb(reverbIndex,
+ auralParams.reverbType, auralParams.reverbFlag);
+ }
+ **********/
+ else {
+ if (internalErrors)
+ debugPrintln( "JavaSoundMixer: Internal Error setReverb " +
+ "dataType " + dataType + " invalid");
+ }
+ }
+ }
+
+ // TEMPORARY: Override of method due to bug in Java Sound
+ @Override
+ public void setLoop(int index, int count) {
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return;
+ int dataType = sample.getDataType();
+
+ // WORKAROUND:
+ // Bug in Java Sound engine hangs when INFINITE_LOOP count
+ // for Audio Wave data. Leave count unchanged for Midi data.
+ if (dataType==JSSample.STREAMING_AUDIO_DATA ||
+ dataType==JSSample.BUFFERED_AUDIO_DATA) {
+ if (count == Sound.INFINITE_LOOPS) {
+ // LoopCount of 'loop Infinitely' forced to largest positive int
+ count = 0x7FFFFFF;
+ }
+ }
+ super.setLoop(index, count);
+ return;
+ }
+
+ // Perform device specific filtering
+ // Assumes that this is called for positional and directional sounds
+ // not background sounds, so there are at lease two samples assigned
+ // per sound.
+ // TODO: remove assumption from method
+ void setFilter(int index, boolean filterFlag, float filterFreq) {
+ JSPositionalSample posSample = null;
+ if ((posSample = (JSPositionalSample)getSample(index)) == null)
+ return;
+ if (posSample.channel == null)
+ return;
+ int dataType = posSample.getDataType();
+
+ // Filtering can NOT be performed on MIDI Songs
+ if (dataType == JSSample.STREAMING_MIDI_DATA ||
+ dataType == JSSample.BUFFERED_MIDI_DATA) {
+ return;
+ }
+
+ /****
+ // TODO: multiple clips per channel
+ int secondIndex = posSample.getSecondIndex();
+ *****/
+ if (dataType == JSSample.BUFFERED_AUDIO_DATA) {
+ JSClip clip = (JSClip)posSample.channel;
+ clip.setSampleFiltering(filterFlag,filterFreq);
+ /*****
+ JSClip.setSampleFiltering(econdIndex, filterFlag, filterFreq);
+ ******/
+ }
+ else { // dataType == JSSample.STREAMING_AUDIO_DATA
+ JSStream stream = (JSStream)posSample.channel;
+ stream.setSampleFiltering(filterFlag,filterFreq);
+ /*****
+ JSStream.setSampleFiltering(secondIndex, ilterFlag, filterFreq);
+ ******/
+ }
+ // QUESTION: should reverb channel be filtered???
+
+ if (debugFlag) {
+ debugPrintln("JavaSoundMixer:setFilter " +
+ "of non-backgroundSound by (" +
+ filterFlag + ", " + filterFreq + ")");
+ }
+ }
+ //
+ // Set overall gain for device
+ // @since Java 3D 1.3
+ //
+ @Override
+ public void setGain(float scaleFactor) {
+ float oldDeviceGain = deviceGain;
+ float gainFactor = scaleFactor/oldDeviceGain;
+ // TODO: for each sample, change gain by gainFactor
+ deviceGain = scaleFactor; // set given scalefactor as new device gain
+ return;
+ }
+
+ /*
+ * Set sample specific sample rate scale factor gain
+ * @since Java 3D 1.3
+ */
+ @Override
+ public void setRateScaleFactor(int index, float rateScaleFactor) {
+ JSSample sample = null;
+ if ((sample = (JSSample)getSample(index)) == null)
+ return;
+ sample.setRateScaleFactor(rateScaleFactor);
+ this.scaleSampleRate(index, rateScaleFactor);
+ }
+
+ /**
+ * Pauses audio device engine without closing the device and associated
+ * threads.
+ * Causes all cached sounds to be paused and all streaming sounds to be
+ * stopped.
+ */
+ @Override
+ public void pause() {
+ pause = PAUSE_PENDING;
+ // TODO: pause all sounds
+ return;
+ }
+ /**
+ * Resumes audio device engine (if previously paused) without reinitializing * the device.
+ * Causes all paused cached sounds to be resumed and all streaming sounds
+ * restarted.
+ */
+ @Override
+ public void resume() {
+ pause = RESUME_PENDING;
+ // TODO: unpause all sounds
+ return;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/audioengines/javasound/package.html b/src/classes/share/org/jogamp/java3d/audioengines/javasound/package.html
new file mode 100644
index 0000000..05122f4
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/audioengines/javasound/package.html
@@ -0,0 +1,11 @@
+
+
+ Provides a JavaSound-based implementation of a Java 3D audio device. Provides abstract classes for creating Java 3D audio devices.
+ * NOTE: this is an experimental interface, which is not intended for use
+ * by applications.
+ *
+ * @author pepe
+ *
+ * @since Java 3D 1.5
+ */
+public interface AutoOffScreenCanvas3D extends org.jogamp.java3d.AutoOffScreenCanvas3D {}
diff --git a/src/classes/share/org/jogamp/java3d/exp/swing/package.html b/src/classes/share/org/jogamp/java3d/exp/swing/package.html
new file mode 100644
index 0000000..8b1db83
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/exp/swing/package.html
@@ -0,0 +1,13 @@
+
+
+ EXPERIMENTAL: Provides a lightweight JCanvas3D class.
+Note that the API in this package is highly experimental and
+subject to change at any time.
+ * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2
+ * community source release on java.net. We should be able to get rid
+ * of this class.
+ */
+
+public abstract class BufferWrapper {
+
+ /**
+ * Value returned from getBufferType(), this indicates
+ * that the BufferWrapper contains a null buffer.
+ */
+ public static final int TYPE_NULL = 0;
+
+ /**
+ * Value returned from getBufferType(), this indicates
+ * that the BufferWrapper does not hold data of type
+ * byte, float, or double.
+ */
+ public static final int TYPE_UNKNOWN = 1;
+
+ /**
+ * Value returned from getBufferType(), this indicates
+ * that the BufferWrapper contains a java.nio.ByteBuffer.
+ */
+ public static final int TYPE_BYTE = 2;
+
+ /**
+ * Value returned from getBufferType(), this indicates
+ * that the BufferWrapper contains a java.nio.FloatBuffer.
+ */
+ public static final int TYPE_FLOAT = 3;
+
+ /**
+ * Value returned from getBufferType(), this indicates
+ * that the BufferWrapper contains a java.nio.DoubleBuffer.
+ */
+ public static final int TYPE_DOUBLE = 4;
+
+ /**
+ * Never used - this class is abstract.
+ */
+ public BufferWrapper() {
+ }
+
+ /**
+ * Must be implemented by sublasses.
+ */
+ abstract Buffer getBuffer();
+
+ /**
+ * @return Buffer as object of type Object.
+ */
+ public Object getBufferAsObject() {
+ return getBuffer();
+ }
+
+ // Wrapper for all relevant Buffer methods.
+
+ /**
+ * @return This buffer's capacity (set at initialization in
+ * allocateDirect() ).
+ * @see ByteBufferWrapper#allocateDirect
+ */
+ public int capacity() {
+ return getBuffer().capacity();
+ }
+
+ /**
+ * @return This buffer's limit.
+ */
+ public int limit() {
+ return getBuffer().limit();
+ }
+
+ /**
+ * @return This buffer's position.
+ */
+ public int position() {
+ return getBuffer().position();
+ }
+
+ /**
+ * Sets this buffer's position.
+ * @return This buffer.
+ */
+ public BufferWrapper position(int newPosition){
+ getBuffer().position(newPosition);
+ return this;
+ }
+
+ /**
+ * Resets this buffer's position to the previously marked
+ * position.
+ * @return This buffer.
+ */
+ public BufferWrapper rewind() {
+ getBuffer().rewind();
+ return this;
+ }
+
+ /**
+ * @return An integer indicating the type of data held in
+ * this buffer.
+ * @see #TYPE_NULL
+ * @see #TYPE_BYTE
+ * @see #TYPE_FLOAT
+ * @see #TYPE_DOUBLE
+ * @see #TYPE_UNKNOWN
+ */
+ public static int getBufferType(J3DBuffer b) {
+ int bufferType;
+ Buffer buffer = b.getBuffer();
+
+ if (buffer == null) {
+ bufferType = TYPE_NULL;
+ }
+ else if (buffer instanceof java.nio.ByteBuffer) {
+ bufferType = TYPE_BYTE;
+ }
+ else if (buffer instanceof java.nio.FloatBuffer) {
+ bufferType = TYPE_FLOAT;
+ }
+ else if (buffer instanceof java.nio.DoubleBuffer) {
+ bufferType = TYPE_DOUBLE;
+ }
+ else {
+ bufferType = TYPE_UNKNOWN;
+ }
+ return bufferType;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/internal/ByteBufferWrapper.java b/src/classes/share/org/jogamp/java3d/internal/ByteBufferWrapper.java
new file mode 100644
index 0000000..e4d0897
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/internal/ByteBufferWrapper.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.internal;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.jogamp.java3d.J3DBuffer;
+
+/**
+ * NIO Buffers are new in Java 1.4 but we need to run on 1.3
+ * as well, so this class was created to hide the NIO classes
+ * from non-1.4 Java 3D users.
+ *
+ *
+ * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2
+ * community source release on java.net. We should be able to get rid
+ * of this class.
+ */
+
+public class ByteBufferWrapper extends BufferWrapper {
+
+ private ByteBuffer buffer = null;
+
+ /**
+ * Constructor initializes buffer with a
+ * java.nio.ByteBuffer object.
+ */
+ public ByteBufferWrapper(ByteBuffer buffer) {
+ this.buffer = buffer;
+ }
+
+ /**
+ * Constructor initializes buffer with a
+ * org.jogamp.java3d.J3DBuffer object.
+ */
+ public ByteBufferWrapper(J3DBuffer b) {
+ buffer = (ByteBuffer)(b.getBuffer());
+ }
+
+ /**
+ * Allocate a direct ByteBuffer with the given capacity.
+ * @return New ByteBufferWrapper containing the
+ * new buffer.
+ */
+ public static ByteBufferWrapper allocateDirect(int capacity) {
+ ByteBuffer bb = ByteBuffer.allocateDirect(capacity);
+ return new ByteBufferWrapper(bb);
+ }
+
+ /**
+ * Returns the java.nio.Buffer contained within this
+ * ByteBufferWrapper.
+ */
+ @Override
+ public java.nio.Buffer getBuffer() {
+ return this.buffer;
+ }
+
+ // Wrapper for all relevant ByteBuffer methods.
+
+ /**
+ * @return A boolean indicating whether the java.nio.Buffer
+ * object contained within this ByteBuffer is direct or
+ * indirect.
+ */
+ public boolean isDirect() {
+ return buffer.isDirect();
+ }
+
+ /**
+ * Reads the byte at this buffer's current position,
+ * and then increments the position.
+ */
+ public byte get() {
+ return buffer.get();
+ }
+
+ /**
+ * Reads the byte at the given offset into the buffer.
+ */
+ public byte get(int index) {
+ return buffer.get(index);
+ }
+
+ /**
+ * Bulk get method. Transfers
+ * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2
+ * community source release on java.net. We should be able to get rid
+ * of this class.
+ */
+
+public class DoubleBufferWrapper extends BufferWrapper {
+
+ private DoubleBuffer buffer = null;
+
+ /**
+ * Constructor initializes buffer with a
+ * java.nio.DoubleBuffer object.
+ */
+ public DoubleBufferWrapper(DoubleBuffer buffer) {
+ this.buffer = buffer;
+ }
+
+ /**
+ * Constructor initializes buffer with a
+ * org.jogamp.java3d.J3DBuffer object.
+ */
+ public DoubleBufferWrapper(J3DBuffer b) {
+ buffer = (DoubleBuffer)(b.getBuffer());
+ }
+
+ /**
+ * Returns the java.nio.Buffer contained within this
+ * DoubleBufferWrapper.
+ */
+ @Override
+ public java.nio.Buffer getBuffer() {
+ return this.buffer;
+ }
+
+ // Wrapper for all relevant DoubleBuffer methods.
+
+ /**
+ * @return A boolean indicating whether the java.nio.Buffer
+ * object contained within this DoubleBuffer is direct or
+ * indirect.
+ */
+ public boolean isDirect() {
+ return buffer.isDirect();
+ }
+
+ /**
+ * Reads the double at this buffer's current position,
+ * and then increments the position.
+ */
+ public double get() {
+ return buffer.get();
+ }
+
+ /**
+ * Reads the double at the given offset into the buffer.
+ */
+ public double get(int index) {
+ return buffer.get(index);
+ }
+
+ /**
+ * Bulk get method. Transfers
+ * NOTE: We no longer need to support JDK 1.3 as of the Java 3D 1.3.2
+ * community source release on java.net. We should be able to get rid
+ * of this class.
+ */
+
+public class FloatBufferWrapper extends BufferWrapper {
+
+ private FloatBuffer buffer = null;
+
+ /**
+ * Constructor initializes buffer with a
+ * java.nio.FloatBuffer object.
+ */
+ public FloatBufferWrapper(FloatBuffer buffer) {
+ this.buffer = buffer;
+ }
+
+ /**
+ * Constructor initializes buffer with a
+ * org.jogamp.java3d.J3DBuffer object.
+ */
+ public FloatBufferWrapper(org.jogamp.java3d.J3DBuffer b) {
+ this.buffer = (FloatBuffer)(b.getBuffer());
+ }
+
+ /**
+ * Returns the java.nio.Buffer contained within this
+ * FloatBufferWrapper.
+ */
+ @Override
+ public java.nio.Buffer getBuffer() {
+ return this.buffer;
+ }
+
+ // Wrapper for all relevant FloatBuffer methods.
+
+ /**
+ * @return A boolean indicating whether the java.nio.Buffer
+ * object contained within this FloatBuffer is direct or
+ * indirect.
+ */
+ public boolean isDirect() {
+ return buffer.isDirect();
+ }
+
+ /**
+ * Reads the float at this buffer's current position,
+ * and then increments the position.
+ */
+ public float get() {
+ return buffer.get();
+ }
+
+ /**
+ * Reads the float at the given offset into the buffer.
+ */
+ public float get(int index) {
+ return buffer.get(index);
+ }
+
+ /**
+ * Bulk get method. Transfers Provides a Java 3D loader for Lightwave 3D scene files.
- * 1 ... if angle between 0 and 180 degrees
- * 2 ... if angle is 0 degrees
- * -1 ... if angle between 180 and 360 degrees
- * -2 ... if angle is 360 degrees
- */
- static int isConvexAngle(Triangulator triRef, int i, int j, int k, int ind) {
- int angle;
- double numericsHDot;
- int numericsHOri1;
- Point2f numericsHP, numericsHQ;
-
- // if((triRef.inPointsList(i)==false)||(triRef.inPointsList(j)==false)||
- // (triRef.inPointsList(k)==false))
- // System.out.println("Numerics.isConvexAngle: Not inPointsList " + i + " " + j
- // + " " + k);
-
- if (i == j) {
- if (j == k) {
- // all three vertices are identical; we set the angle to 1 in
- // order to enable clipping of j.
- return 1;
- }
- else {
- // two of the three vertices are identical; we set the angle to 1
- // in order to enable clipping of j.
- return 1;
- }
- }
- else if (j == k) {
- // two vertices are identical. we could either determine the angle
- // by means of yet another lengthy analysis, or simply set the
- // angle to -1. using -1 means to err on the safe side, as all the
- // incarnations of this vertex will be clipped right at the start
- // of the ear-clipping algorithm. thus, eventually there will be no
- // other duplicates at this vertex position, and the regular
- // classification of angles will yield the correct answer for j.
- return -1;
- }
- else {
- numericsHOri1 = orientation(triRef, i, j, k);
- // System.out.println("i " + i + " j " + j + " k " + k + " ind " + ind +
- // ". In IsConvexAngle numericsHOri1 is " +
- // numericsHOri1);
- if (numericsHOri1 > 0) {
- angle = 1;
- }
- else if (numericsHOri1 < 0) {
- angle = -1;
- }
- else {
- // 0, 180, or 360 degrees.
- numericsHP = new Point2f();
- numericsHQ = new Point2f();
- Basic.vectorSub2D(triRef.points[i], triRef.points[j], numericsHP);
- Basic.vectorSub2D(triRef.points[k], triRef.points[j], numericsHQ);
- numericsHDot = Basic.dotProduct2D(numericsHP, numericsHQ);
- if (numericsHDot < 0.0) {
- // 180 degrees.
- angle = 0;
- }
- else {
- // 0 or 360 degrees? this cannot be judged locally, and more
- // work is needed.
-
- angle = spikeAngle(triRef, i, j, k, ind);
- // System.out.println("SpikeAngle return is "+ angle);
- }
- }
- }
- return angle;
- }
-
-
- /**
- * This method checks whether point i4 is inside of or on the boundary
- * of the triangle i1, i2, i3.
- */
- static boolean pntInTriangle(Triangulator triRef, int i1, int i2, int i3, int i4) {
- boolean inside;
- int numericsHOri1;
-
- inside = false;
- numericsHOri1 = orientation(triRef, i2, i3, i4);
- if (numericsHOri1 >= 0) {
- numericsHOri1 = orientation(triRef, i1, i2, i4);
- if (numericsHOri1 >= 0) {
- numericsHOri1 = orientation(triRef, i3, i1, i4);
- if (numericsHOri1 >= 0) inside = true;
- }
- }
- return inside;
- }
-
-
- /**
- * This method checks whether point i4 is inside of or on the boundary
- * of the triangle i1, i2, i3. it also returns a classification if i4 is
- * on the boundary of the triangle (except for the edge i2, i3).
- */
- static boolean vtxInTriangle(Triangulator triRef, int i1, int i2, int i3,
- int i4, int[] type) {
- boolean inside;
- int numericsHOri1;
-
- inside = false;
- numericsHOri1 = orientation(triRef, i2, i3, i4);
- if (numericsHOri1 >= 0) {
- numericsHOri1 = orientation(triRef, i1, i2, i4);
- if (numericsHOri1 > 0) {
- numericsHOri1 = orientation(triRef, i3, i1, i4);
- if (numericsHOri1 > 0) {
- inside = true;
- type[0] = 0;
- }
- else if (numericsHOri1 == 0) {
- inside = true;
- type[0] = 1;
- }
- }
- else if (numericsHOri1 == 0) {
- numericsHOri1 = orientation(triRef, i3, i1, i4);
- if (numericsHOri1 > 0) {
- inside = true;
- type[0] = 2;
- }
- else if (numericsHOri1 == 0) {
- inside = true;
- type[0] = 3;
- }
- }
- }
- return inside;
- }
-
-
- /**
- * Checks whether the line segments i1, i2 and i3, i4 intersect. no
- * intersection is reported if they intersect at a common vertex.
- * the function assumes that i1 <= i2 and i3 <= i4. if i3 or i4 lies
- * on i1, i2 then an intersection is reported, but no intersection is
- * reported if i1 or i2 lies on i3, i4. this function is not symmetric!
- */
- static boolean segIntersect(Triangulator triRef, int i1, int i2, int i3,
- int i4, int i5) {
- int ori1, ori2, ori3, ori4;
-
- // if((triRef.inPointsList(i1)==false)||(triRef.inPointsList(i2)==false)||
- // (triRef.inPointsList(i3)==false)||(triRef.inPointsList(i4)==false))
- // System.out.println("Numerics.segIntersect Not inPointsList " + i1 + " " + i2
- // + " " + i3 + " " + i4);
- //
- // if((i1 > i2) || (i3 > i4))
- // System.out.println("Numerics.segIntersect i1>i2 or i3>i4 " + i1 + " " + i2
- // + " " + i3 + " " + i4);
-
- if ((i1 == i2) || (i3 == i4)) return false;
- if ((i1 == i3) && (i2 == i4)) return true;
-
- if ((i3 == i5) || (i4 == i5)) ++(triRef.identCntr);
-
- ori3 = orientation(triRef, i1, i2, i3);
- ori4 = orientation(triRef, i1, i2, i4);
- if (((ori3 == 1) && (ori4 == 1)) ||
- ((ori3 == -1) && (ori4 == -1))) return false;
-
- if (ori3 == 0) {
- if (strictlyInBetween(i1, i2, i3)) return true;
- if (ori4 == 0) {
- if (strictlyInBetween(i1, i2, i4)) return true;
- }
- else return false;
- }
- else if (ori4 == 0) {
- if (strictlyInBetween(i1, i2, i4)) return true;
- else return false;
- }
-
- ori1 = orientation(triRef, i3, i4, i1);
- ori2 = orientation(triRef, i3, i4, i2);
- if (((ori1 <= 0) && (ori2 <= 0)) ||
- ((ori1 >= 0) && (ori2 >= 0))) return false;
-
- return true;
- }
-
-
- /**
- * this function computes a quality measure of a triangle i, j, k.
- * it returns the ratio `base / height', where base is the length of the
- * longest side of the triangle, and height is the normal distance
- * between the vertex opposite of the base side and the base side. (as
- * usual, we again use the l1-norm for distances.)
- */
- static double getRatio(Triangulator triRef, int i, int j, int k) {
- double area, a, b, c, base, ratio;
- Point2f p, q, r;
-
- // if((triRef.inPointsList(i)==false)||(triRef.inPointsList(j)==false)||
- // (triRef.inPointsList(k)==false))
- // System.out.println("Numerics.getRatio: Not inPointsList " + i + " " + j
- // + " " + k);
-
- p = triRef.points[i];
- q = triRef.points[j];
- r = triRef.points[k];
-
-
- a = baseLength(p, q);
- b = baseLength(p, r);
- c = baseLength(r, q);
- base = max3(a, b, c);
-
- if ((10.0 * a) < Math.min(b, c)) return 0.1;
-
- area = stableDet2D(triRef, i, j, k);
- if (lt(area, triRef.epsilon)) {
- area = -area;
- }
- else if (!gt(area, triRef.epsilon)) {
- if (base > a) return 0.1;
- else return Double.MAX_VALUE;
- }
-
- ratio = base * base / area;
-
- if (ratio < 10.0) return ratio;
- else {
- if (a < base) return 0.1;
- else return ratio;
- }
- }
-
-
- static int spikeAngle(Triangulator triRef, int i, int j, int k, int ind) {
- int ind1, ind2, ind3;
- int i1, i2, i3;
-
- // if((triRef.inPointsList(i)==false)||(triRef.inPointsList(j)==false)||
- // (triRef.inPointsList(k)==false))
- // System.out.println("Numerics.spikeAngle: Not inPointsList " + i + " " + j
- // + " " + k);
-
- ind2 = ind;
- i2 = triRef.fetchData(ind2);
-
- // if(i2 != j)
- // System.out.println("Numerics.spikeAngle: i2 != j " + i2 + " " + j );
-
- ind1 = triRef.fetchPrevData(ind2);
- i1 = triRef.fetchData(ind1);
-
- // if(i1 != i)
- // System.out.println("Numerics.spikeAngle: i1 != i " + i1 + " " + i );
-
- ind3 = triRef.fetchNextData(ind2);
- i3 = triRef.fetchData(ind3);
-
- // if(i3 != k)
- // System.out.println("Numerics.spikeAngle: i3 != k " + i3 + " " + k );
-
- return recSpikeAngle(triRef, i, j, k, ind1, ind3);
- }
-
-
-
- static int recSpikeAngle(Triangulator triRef, int i1, int i2, int i3,
- int ind1, int ind3) {
- int ori, ori1, ori2, i0, ii1, ii2;
- Point2f pq, pr;
- double dot;
-
- if (ind1 == ind3) {
- // all points are collinear??? well, then it does not really matter
- // which angle is returned. perhaps, -2 is the best bet as my code
- // likely regards this contour as a hole.
- return -2;
- }
-
- if (i1 != i3) {
- if (i1 < i2) {
- ii1 = i1;
- ii2 = i2;
- }
- else {
- ii1 = i2;
- ii2 = i1;
- }
- if (inBetween(ii1, ii2, i3)) {
- i2 = i3;
- ind3 = triRef.fetchNextData(ind3);
- i3 = triRef.fetchData(ind3);
-
- if (ind1 == ind3) return 2;
- ori = orientation(triRef, i1, i2, i3);
- if (ori > 0) return 2;
- else if (ori < 0) return -2;
- else return recSpikeAngle(triRef, i1, i2, i3, ind1, ind3);
- }
- else {
- i2 = i1;
- ind1 = triRef.fetchPrevData(ind1);
- i1 = triRef.fetchData(ind1);
- if (ind1 == ind3) return 2;
- ori = orientation(triRef, i1, i2, i3);
- if (ori > 0) return 2;
- else if (ori < 0) return -2;
- else return recSpikeAngle(triRef, i1, i2, i3, ind1, ind3);
- }
- }
- else {
- i0 = i2;
- i2 = i1;
- ind1 = triRef.fetchPrevData(ind1);
- i1 = triRef.fetchData(ind1);
-
- if (ind1 == ind3) return 2;
- ind3 = triRef.fetchNextData(ind3);
- i3 = triRef.fetchData(ind3);
- if (ind1 == ind3) return 2;
- ori = orientation(triRef, i1, i2, i3);
- if (ori > 0) {
- ori1 = orientation(triRef, i1, i2, i0);
- if (ori1 > 0) {
- ori2 = orientation(triRef, i2, i3, i0);
- if (ori2 > 0) return -2;
- }
- return 2;
- }
- else if (ori < 0) {
- ori1 = orientation(triRef, i2, i1, i0);
- if (ori1 > 0) {
- ori2 = orientation(triRef, i3, i2, i0);
- if (ori2 > 0) return 2;
- }
- return -2;
- }
- else {
- pq = new Point2f();
- Basic.vectorSub2D(triRef.points[i1], triRef.points[i2], pq);
- pr = new Point2f();
- Basic.vectorSub2D(triRef.points[i3], triRef.points[i2], pr);
- dot = Basic.dotProduct2D(pq, pr);
- if (dot < 0.0) {
- ori = orientation(triRef, i2, i1, i0);
- if (ori > 0) return 2;
- else return -2;
- }
- else {
- return recSpikeAngle(triRef, i1, i2, i3, ind1, ind3);
- }
- }
- }
- }
-
-
- /**
- * computes the signed angle between p, p1 and p, p2.
- *
- * warning: this function does not handle a 180-degree angle correctly!
- * (this is no issue in our application, as we will always compute
- * the angle centered at the mid-point of a valid diagonal.)
- */
- static double angle(Triangulator triRef, Point2f p, Point2f p1, Point2f p2) {
- int sign;
- double angle1, angle2, angle;
- Point2f v1, v2;
-
- sign = Basic.signEps(Basic.det2D(p2, p, p1), triRef.epsilon);
-
- if (sign == 0) return 0.0;
-
- v1 = new Point2f();
- v2 = new Point2f();
- Basic.vectorSub2D(p1, p, v1);
- Basic.vectorSub2D(p2, p, v2);
-
- angle1 = Math.atan2(v1.y, v1.x);
- angle2 = Math.atan2(v2.y, v2.x);
-
- if (angle1 < 0.0) angle1 += 2.0*Math.PI;
- if (angle2 < 0.0) angle2 += 2.0*Math.PI;
-
- angle = angle1 - angle2;
- if (angle > Math.PI) angle = 2.0*Math.PI - angle;
- else if (angle < -Math.PI) angle = 2.0*Math.PI + angle;
-
- if (sign == 1) {
- if (angle < 0.0) return -angle;
- else return angle;
- }
- else {
- if (angle > 0.0) return -angle;
- else return angle;
- }
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Orientation.java b/src/classes/share/com/sun/j3d/utils/geometry/Orientation.java
deleted file mode 100644
index c8ae26d..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Orientation.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-
-class Orientation {
-
- /**
- * determine the outer polygon and the orientation of the polygons; the
- * default orientation is CCW for the outer-most polygon, and CW for the
- * inner polygons. the polygonal loops are referenced by loops[i1,..,i2-1].
- */
- static void adjustOrientation(Triangulator triRef, int i1, int i2) {
-
- double area;
- int i, outer;
- int ind;
-
- if(i1 >= i2)
- System.out.println("Orientation:adjustOrientation Problem i1>=i2 !!!");
-
- if (triRef.numLoops >= triRef.maxNumPolyArea) {
- // System.out.println("Orientation:adjustOrientation Expanding polyArea array .");
- triRef.maxNumPolyArea = triRef.numLoops;
- double old[] = triRef.polyArea;
- triRef.polyArea = new double[triRef.maxNumPolyArea];
- if(old != null)
- System.arraycopy(old, 0, triRef.polyArea, 0, old.length);
- }
-
- // for each contour, compute its signed area, i.e., its orientation. the
- // contour with largest area is assumed to be the outer-most contour.
- for (i = i1; i < i2; ++i) {
- ind = triRef.loops[i];
- triRef.polyArea[i] = polygonArea(triRef, ind);
- }
-
- // determine the outer-most contour
- area = Math.abs(triRef.polyArea[i1]);
- outer = i1;
- for (i = i1 + 1; i < i2; ++i) {
- if (area < Math.abs(triRef.polyArea[i])) {
- area = Math.abs(triRef.polyArea[i]);
- outer = i;
- }
- }
-
- // default: the outer contour is referenced by loops[i1]
- if (outer != i1) {
- ind = triRef.loops[i1];
- triRef.loops[i1] = triRef.loops[outer];
- triRef.loops[outer] = ind;
-
- area = triRef.polyArea[i1];
- triRef.polyArea[i1] = triRef.polyArea[outer];
- triRef.polyArea[outer] = area;
- }
-
- // adjust the orientation
- if (triRef.polyArea[i1] < 0.0) triRef.swapLinks(triRef.loops[i1]);
- for (i = i1 + 1; i < i2; ++i) {
- if (triRef.polyArea[i] > 0.0) triRef.swapLinks(triRef.loops[i]);
- }
- }
-
- /**
- * This function computes twice the signed area of a simple closed polygon.
- */
- static double polygonArea(Triangulator triRef, int ind) {
- int hook = 0;
- int ind1, ind2;
- int i1, i2;
- double area = 0.0, area1 = 0;
-
- ind1 = ind;
- i1 = triRef.fetchData(ind1);
- ind2 = triRef.fetchNextData(ind1);
- i2 = triRef.fetchData(ind2);
- area = Numerics.stableDet2D(triRef, hook, i1, i2);
-
- ind1 = ind2;
- i1 = i2;
- while (ind1 != ind) {
- ind2 = triRef.fetchNextData(ind1);
- i2 = triRef.fetchData(ind2);
- area1 = Numerics.stableDet2D(triRef, hook, i1, i2);
- area += area1;
- ind1 = ind2;
- i1 = i2;
- }
-
- return area;
- }
-
-
- /**
- * Determine the orientation of the polygon. The default orientation is CCW.
- */
- static void determineOrientation(Triangulator triRef, int ind) {
- double area;
-
- // compute the polygon's signed area, i.e., its orientation.
- area = polygonArea(triRef, ind);
-
- // adjust the orientation (i.e., make it CCW)
- if (area < 0.0) {
- triRef.swapLinks(ind);
- triRef.ccwLoop = false;
- }
-
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/PntNode.java b/src/classes/share/com/sun/j3d/utils/geometry/PntNode.java
deleted file mode 100644
index a2b0252..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/PntNode.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-// Placeholder list
-class PntNode extends Object {
- int pnt;
- int next;
-
- PntNode() {
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Primitive.java b/src/classes/share/com/sun/j3d/utils/geometry/Primitive.java
deleted file mode 100644
index 6080b3a..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Primitive.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry;
-
-import java.util.Hashtable;
-
-import javax.media.j3d.Appearance;
-import javax.media.j3d.Group;
-import javax.media.j3d.Material;
-import javax.media.j3d.Shape3D;
-import javax.vecmath.Color3f;
-
-/**
- * Base class for all Java 3D primitives. By default all primitives
- * with the same parameters share their geometry (e.g., you can have 50
- * shperes in your scene, but the geometry is stored only once). A
- * change to one primitive will effect all shared nodes. Another
- * implication of this implementation is that the capabilities of the
- * geometry are shared, and once one of the shared nodes is live, the
- * capabilities cannot be set. Use the GEOMETRY_NOT_SHARED flag if
- * you do not wish to share geometry among primitives with the same
- * parameters.
- */
-
-public abstract class Primitive extends Group {
- /**
- * Specifies that normals are generated along with the positions.
- */
- public static final int GENERATE_NORMALS = 0x01;
-
- /**
- * Specifies that texture coordinates are generated along with the
- * positions.
- */
- public static final int GENERATE_TEXTURE_COORDS = 0x02;
-
- /**
- * Specifies that normals are to be flipped along the surface.
- */
- public static final int GENERATE_NORMALS_INWARD = 0x04;
-
- /**
- * Specifies that texture coordinates are to be Y up.
- *
- * @since Java 3D 1.5.1
- */
- // Fix to Issue 411. Java 3D prefers images used for texture mapping to be Y-up
- public static final int GENERATE_TEXTURE_COORDS_Y_UP = 0x08;
-
-
- /**
- * Specifies that the geometry being created will not be shared by
- * another scene graph node. By default all primitives created with
- * the same parameters share their geometry (e.g., you can have 50
- * spheres in your scene, but the geometry is stored only once). A
- * change to one primitive will effect all shared nodes. You
- * specify this flag if you do not wish to share any geometry among
- * primitives of the same parameters. */
- public static final int GEOMETRY_NOT_SHARED = 0x10;
-
- /**
- * Specifies that the ALLOW_INTERSECT
- * capability bit should be set on the generated geometry.
- * This allows the object
- * to be picked using Geometry based picking.
- */
- public static final int ENABLE_GEOMETRY_PICKING = 0x20;
-
- /**
- * Specifies that the ALLOW_APPEARANCE_READ and
- * ALLOW_APPEARANCE_WRITE bits are to be set on the generated
- * geometry's Shape3D nodes.
- */
- public static final int ENABLE_APPEARANCE_MODIFY = 0x40;
-
- static final int SPHERE = 0x01;
- static final int CYLINDER = 0x02;
- static final int CONE = 0x04;
- static final int BOX = 0x08;
-
- // used for cached geometries of Cone and Cylinder
- static final int TOP_DISK = 0x10;
- static final int BOTTOM_DISK = 0x20;
- static final int CONE_DIVISIONS = 0x40;
-
- int numTris = 0;
- int numVerts = 0;
-
- /**
- * Primitive flags.
- */
- int flags;
-
-
- /**
- * Constructs a default primitive.
- */
- public Primitive()
- {
- flags = 0;
- setCapability(ENABLE_PICK_REPORTING);
- setCapability(ALLOW_CHILDREN_READ);
- }
-
- /**
- * Returns the total number of triangles in this primitive.
- * @return the total number of triangles in this primitive
- */
- public int getNumTriangles() {
- return numTris;
- }
-
- /**
- * @deprecated The number of triangles is an immutable attribute.
- */
- public void setNumTriangles(int num) {
- System.err.println("Warning: setNumTriangles has no effect");
- }
-
- /**
- * Returns the total number of vertices in this primitive.
- * @return the total number of vertices in this primitive
- */
- public int getNumVertices() {
- return numVerts;
- }
-
- /**
- * @deprecated The number of vertices is an immutable attribute.
- */
- public void setNumVertices(int num) {
- System.err.println("Warning: setNumVertices has no effect");
- }
-
- /** Returns the flags of primitive (generate normal, textures, caching, etc).
- */
- public int getPrimitiveFlags()
- {
- return flags;
- }
-
- /**
- * @deprecated The primitive flags must be set at construction time
- * via one of the subclass constructors.
- */
- public void setPrimitiveFlags(int fl) {
- System.err.println("Warning: setPrimitiveFlags has no effect");
- }
-
- /** Obtains a shape node of a subpart of the primitive.
- * @param partid identifier for a given subpart of the primitive.
- */
- public abstract Shape3D getShape(int partid);
-
- /** Gets the appearance of the primitive (defaults to first subpart).
- */
- public Appearance getAppearance(){
- return getShape(0).getAppearance();
- }
-
- /**
- * Gets the appearance of the specified part of the primitive.
- *
- * @param partId identifier for a given subpart of the primitive
- *
- * @return The appearance object associated with the partID. If an
- * invalid partId is passed in, null is returned.
- *
- * @since Java 3D 1.2.1
- */
- public abstract Appearance getAppearance(int partId);
-
- /** Sets the appearance of a subpart given a partid.
- */
-
- public void setAppearance(int partid, Appearance ap)
- {
- getShape(partid).setAppearance(ap);
- }
-
- /** Sets the main appearance of the primitive (all subparts) to
- * same appearance.
- */
- public abstract void setAppearance(Appearance ap);
-
-
- /** Sets the main appearance of the primitive (all subparts) to
- * a default white appearance.
- */
- public void setAppearance(){
-
- Color3f aColor = new Color3f(0.1f, 0.1f, 0.1f);
- Color3f eColor = new Color3f(0.0f, 0.0f, 0.0f);
- Color3f dColor = new Color3f(0.6f, 0.6f, 0.6f);
- Color3f sColor = new Color3f(1.0f, 1.0f, 1.0f);
-
- Material m = new Material(aColor, eColor, dColor, sColor, 100.0f);
- Appearance a = new Appearance();
- m.setLightingEnable(true);
- a.setMaterial(m);
- setAppearance(a);
- }
-
- static Hashtable geomCache = new Hashtable();
-
- String strfloat(float x)
- {
- return (new Float(x)).toString();
- }
-
- protected void cacheGeometry(int kind, float a, float b,
- float c, int d, int e, int flags,
- GeomBuffer geo)
- {
- String key = new String(kind+strfloat(a)+strfloat(b)+
- strfloat(c)+d+e+flags);
- geomCache.put(key, geo);
- }
-
- protected GeomBuffer getCachedGeometry(int kind, float a, float b, float c,
- int d, int e, int flags)
- {
- String key = new String(kind+strfloat(a)+strfloat(b)+
- strfloat(c)+d+e+flags);
- Object cache = geomCache.get(key);
-
- return((GeomBuffer) cache);
- }
-
- /**
- * Clear the shared geometry cache for all Primitive types.
- * Existing Shapes with shared geometry will continue to share
- * the geometry. New Primitives will create new shared geometry.
- *
- * @since Java 3D 1.3.2
- */
- public static void clearGeometryCache() {
- geomCache.clear();
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Project.java b/src/classes/share/com/sun/j3d/utils/geometry/Project.java
deleted file mode 100644
index 7bd92cc..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Project.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-import javax.vecmath.Matrix4f;
-import javax.vecmath.Point3f;
-import javax.vecmath.Tuple3f;
-import javax.vecmath.Vector3f;
-
-class Project {
-
- /**
- * This function projects the vertices of the polygons referenced by
- * loops[i1,..,i2-1] to an approximating plane.
- */
- static void projectFace(Triangulator triRef, int loopMin, int loopMax) {
- Vector3f normal, nr;
- int i, j;
- double d;
-
- normal = new Vector3f();
- nr = new Vector3f();
-
- // determine the normal of the plane onto which the points get projected
- determineNormal(triRef, triRef.loops[loopMin], normal);
- j = loopMin + 1;
- if (j < loopMax) {
- for (i = j; i < loopMax; ++i) {
- determineNormal(triRef, triRef.loops[i], nr);
- if (Basic.dotProduct(normal, nr) < 0.0) {
- Basic.invertVector(nr);
- }
- Basic.vectorAdd(normal, nr, normal);
- }
- d = Basic.lengthL2(normal);
- if (Numerics.gt(d, Triangulator.ZERO)) {
- Basic.divScalar(d, normal);
- }
- else {
- // System.out.println("*** ProjectFace: zero-length normal vector!? ***\n");
- normal.x = normal.y = 0.0f;
- normal.z = 1.0f;
- }
- }
-
- // project the points onto this plane. the projected points are stored in
- // the array `points[0,..,numPoints]'
-
- // System.out.println("loopMin " + loopMin + " loopMax " + loopMax);
- projectPoints(triRef, loopMin, loopMax, normal);
-
- }
-
-
- /**
- * This function computes the average of all normals defined by triples of
- * successive vertices of the polygon. we'll see whether this is a good
- * heuristic for finding a suitable plane normal...
- */
- static void determineNormal(Triangulator triRef, int ind, Vector3f normal) {
- Vector3f nr, pq, pr;
- int ind0, ind1, ind2;
- int i0, i1, i2;
- double d;
-
- ind1 = ind;
- i1 = triRef.fetchData(ind1);
- ind0 = triRef.fetchPrevData(ind1);
- i0 = triRef.fetchData(ind0);
- ind2 = triRef.fetchNextData(ind1);
- i2 = triRef.fetchData(ind2);
- pq = new Vector3f();
- Basic.vectorSub((Tuple3f) triRef.vertices[i0], (Tuple3f) triRef.vertices[i1], (Vector3f) pq);
- pr = new Vector3f();
- Basic.vectorSub((Tuple3f) triRef.vertices[i2], (Tuple3f) triRef.vertices[i1], (Vector3f) pr);
- nr = new Vector3f();
- Basic.vectorProduct(pq, pr, nr);
- d = Basic.lengthL2(nr);
- if (Numerics.gt(d, Triangulator.ZERO)) {
- Basic.divScalar(d, nr);
- normal.set(nr);
- }
- else {
- normal.x = normal.y = normal.z = 0.0f;
- }
-
- pq.set(pr);
- ind1 = ind2;
- ind2 = triRef.fetchNextData(ind1);
- i2 = triRef.fetchData(ind2);
- while (ind1 != ind) {
- Basic.vectorSub((Tuple3f) triRef.vertices[i2], (Tuple3f) triRef.vertices[i1], pr);
- Basic.vectorProduct(pq, pr, nr);
- d = Basic.lengthL2(nr);
- if (Numerics.gt(d, Triangulator.ZERO)) {
- Basic.divScalar(d, nr);
- if (Basic.dotProduct(normal, nr) < 0.0) {
- Basic.invertVector(nr);
- }
- Basic.vectorAdd(normal, nr, normal);
- }
- pq.set(pr);
- ind1 = ind2;
- ind2 = triRef.fetchNextData(ind1);
- i2 = triRef.fetchData(ind2);
- }
-
- d = Basic.lengthL2(normal);
- if (Numerics.gt(d, Triangulator.ZERO)) {
- Basic.divScalar(d, normal);
- }
- else {
- //System.out.println("*** DetermineNormal: zero-length normal vector!? ***\n");
- normal.x = normal.y = 0.0f; normal.z = 1.0f;
-
- }
- }
-
-
- /**
- * This function maps the vertices of the polygon referenced by `ind' to the
- * plane n3.x * x + n3.y * y + n3.z * z = 0. every mapped vertex (x,y,z)
- * is then expressed in terms of (x',y',z'), where z'=0. this is
- * achieved by transforming the original vertices into a coordinate system
- * whose z-axis coincides with n3, and whose two other coordinate axes n1
- * and n2 are orthonormal on n3. note that n3 is supposed to be of unit
- * length!
- */
- static void projectPoints(Triangulator triRef, int i1, int i2, Vector3f n3) {
- Matrix4f matrix = new Matrix4f();
- Point3f vtx = new Point3f();
- Vector3f n1, n2;
- double d;
- int ind, ind1;
- int i, j1;
-
-
- n1 = new Vector3f();
- n2 = new Vector3f();
-
- // choose n1 and n2 appropriately
- if ((Math.abs(n3.x) > 0.1) || (Math.abs(n3.y) > 0.1)) {
- n1.x = -n3.y;
- n1.y = n3.x;
- n1.z = 0.0f;
- }
- else {
- n1.x = n3.z;
- n1.z = -n3.x;
- n1.y = 0.0f;
- }
- d = Basic.lengthL2(n1);
- Basic.divScalar(d, n1);
- Basic.vectorProduct(n1, n3, n2);
- d = Basic.lengthL2(n2);
- Basic.divScalar(d, n2);
-
- // initialize the transformation matrix
- matrix.m00 = n1.x;
- matrix.m01 = n1.y;
- matrix.m02 = n1.z;
- matrix.m03 = 0.0f; // translation of the coordinate system
- matrix.m10 = n2.x;
- matrix.m11 = n2.y;
- matrix.m12 = n2.z;
- matrix.m13 = 0.0f; // translation of the coordinate system
- matrix.m20 = n3.x;
- matrix.m21 = n3.y;
- matrix.m22 = n3.z;
- matrix.m23 = 0.0f; // translation of the coordinate system
- matrix.m30 = 0.0f;
- matrix.m31 = 0.0f;
- matrix.m32 = 0.0f;
- matrix.m33 = 1.0f;
-
- // transform the vertices and store the transformed vertices in the array
- // `points'
- triRef.initPnts(20);
- for (i = i1; i < i2; ++i) {
- ind = triRef.loops[i];
- ind1 = ind;
- j1 = triRef.fetchData(ind1);
- matrix.transform((Point3f)triRef.vertices[j1], vtx);
- j1 = triRef.storePoint(vtx.x, vtx.y);
- triRef.updateIndex(ind1, j1);
- ind1 = triRef.fetchNextData(ind1);
- j1 = triRef.fetchData(ind1);
- while (ind1 != ind) {
- matrix.transform(triRef.vertices[j1], vtx);
- j1 = triRef.storePoint(vtx.x, vtx.y);
- triRef.updateIndex(ind1, j1);
- ind1 = triRef.fetchNextData(ind1);
- j1 = triRef.fetchData(ind1);
- }
- }
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Quadrics.java b/src/classes/share/com/sun/j3d/utils/geometry/Quadrics.java
deleted file mode 100644
index bfaaac0..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Quadrics.java
+++ /dev/null
@@ -1,539 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry;
-
-
-class Quadrics extends Object {
-
- Quadrics(){ }
-
- // new disk code to remove transforms in the primitive code
- GeomBuffer disk(double r, int xdiv, double y, boolean outside, boolean texCoordYUp) {
-
- double theta, dtheta, sign, sinTheta, cosTheta;
-
- if (outside) sign = 1.0;
- else sign = -1.0;
-
- dtheta = 2.0*Math.PI / xdiv;
-
- GeomBuffer gbuf = new GeomBuffer(xdiv+2);
-
- gbuf.begin(GeomBuffer.TRIANGLE_FAN);
- gbuf.normal3d(0.0, 1.0*sign, 0.0);
- gbuf.texCoord2d(0.5, 0.5);
- gbuf.vertex3d(0.0, y, 0.0);
-
- // create the disk by evaluating points along the unit circle.
- // theta is the angle around the y-axis. Then we obtain
- // (cos(theta), sin(theta)) = (x,z) sample points. The y value
- // was passed in as a parameter.
- // texture coordinates are obtain from the unit circle centered at
- // (.5, .5) in s, t space. thus portions of the texture are not used.
-
- if (!outside) {
- for (int i = 0; i <= xdiv; i++) {
- theta = i * dtheta;
- // add 90 degrees to theta so lines up wtih the body
- sinTheta = Math.sin(theta - Math.PI/2.0);
- cosTheta = Math.cos(theta - Math.PI/2.0);
- gbuf.normal3d(0.0, 1.0*sign, 0.0);
- if (texCoordYUp) {
- gbuf.texCoord2d(0.5+cosTheta*0.5, 1.0 - (0.5+sinTheta*0.5));
- }
- else {
- gbuf.texCoord2d(0.5+cosTheta*0.5, 0.5+sinTheta*0.5);
- }
- gbuf.vertex3d(r*cosTheta, y, r*sinTheta);
- }
- } else {
- for (int i = xdiv; i >= 0; i--) {
- theta = i * dtheta;
- // add 90 degrees to theta so lines up with the body
- sinTheta = Math.sin(theta - Math.PI/2.0);
- cosTheta = Math.cos(theta - Math.PI/2.0);
- gbuf.normal3d(0.0, 1.0*sign, 0.0);
- if (texCoordYUp) {
- gbuf.texCoord2d(0.5+cosTheta*0.5, 1.0 - (0.5-sinTheta*0.5));
- }
- else {
- gbuf.texCoord2d(0.5+cosTheta*0.5, 0.5-sinTheta*0.5);
- }
- gbuf.vertex3d(cosTheta*r, y, sinTheta*r);
- }
- }
-
- gbuf.end();
- return gbuf;
- }
-
-
- // new cylinder to remove transforms in the cylinder code and to optimize
- // by using triangle strip
- GeomBuffer cylinder(double height, double radius,
- int xdiv, int ydiv, boolean outside, boolean texCoordYUp) {
-
- double sign;
-
- if (outside) sign = 1.0;
- else sign = -1.0;
-
- // compute the deltas
- double dtheta = 2.0*Math.PI / (double)xdiv;
- double dy = height / (double)ydiv;
- double du = 1.0/(double)xdiv;
- double dv = 1.0/(double)ydiv;
-
- GeomBuffer gbuf = new GeomBuffer(ydiv*2*(xdiv+1));
-
- double s = 0.0, t = 0.0;
- double px, pz, qx, qz;
- double py = -height/2.0;
- double qy;
-
- gbuf.begin(GeomBuffer.QUAD_STRIP);
-
- for (int i = 0; i < ydiv; i++) {
- qy = py+dy;
- if (outside) {
- px = Math.cos(xdiv*dtheta - Math.PI/2.0);
- pz = Math.sin(xdiv*dtheta - Math.PI/2.0);
- qx = Math.cos((xdiv-1)*dtheta - Math.PI/2.0);
- qz = Math.sin((xdiv-1)*dtheta - Math.PI/2.0);
-
- // vert 2
- gbuf.normal3d(px*sign, 0.0, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - (t + dv));
- }
- else {
- gbuf.texCoord2d(s, t+dv);
- }
- gbuf.vertex3d(px*radius, qy, pz*radius);
-
- // vert 1
- gbuf.normal3d(px*sign, 0.0, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - t);
- } else {
- gbuf.texCoord2d(s, t);
- }
- gbuf.vertex3d(px*radius, py, pz*radius);
-
- // vert 4
- gbuf.normal3d(qx*sign, 0.0, qz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s+du, 1.0 - (t + dv));
- }
- else {
- gbuf.texCoord2d(s+du, t+dv);
- }
- gbuf.vertex3d(qx*radius, qy, qz*radius);
-
- // vert 3
- gbuf.normal3d(qx*sign, 0.0, qz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s+du, 1.0 - t);
- }
- else {
- gbuf.texCoord2d(s+du, t);
- }
- gbuf.vertex3d(qx*radius, py, qz*radius);
-
- s += (du*2.0);
-
- for (int j = xdiv-2; j >=0; j--) {
- px = Math.cos(j*dtheta - Math.PI/2.0);
- pz = Math.sin(j*dtheta - Math.PI/2.0);
-
- // vert 6
- gbuf.normal3d(px*sign, 0.0, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - (t + dv));
- }
- else {
- gbuf.texCoord2d(s, t+dv);
- }
- gbuf.vertex3d(px*radius, qy, pz*radius);
-
- // vert 5
- gbuf.normal3d(px*sign, 0.0, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - t);
- }
- else {
- gbuf.texCoord2d(s, t);
- }
- gbuf.vertex3d(px*radius, py, pz*radius);
-
- s += du;
- }
-
- } else {
-// c = 0;
- px = Math.cos(-Math.PI/2.0);
- pz = Math.sin(-Math.PI/2.0);
- qx = Math.cos(dtheta - Math.PI/2.0);
- qz = Math.sin(dtheta - Math.PI/2.0);
-
- gbuf.normal3d(px*sign, 0.0, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - (t + dv));
- }
- else {
- gbuf.texCoord2d(s, t+dv);
- }
- gbuf.vertex3d(px*radius, qy, pz*radius);
-
- // vert 1
- gbuf.normal3d(px*sign, 0.0, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - t);
- }
- else {
- gbuf.texCoord2d(s, t);
- }
- gbuf.vertex3d(px*radius, py, pz*radius);
-
- gbuf.normal3d(qx*sign, 0.0, qz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s+du, 1.0 - (t + dv));
- }
- else {
- gbuf.texCoord2d(s+du, t+dv);
- }
- gbuf.vertex3d(qx*radius, qy, qz*radius);
-
- gbuf.normal3d(qx*sign, 0.0, qz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s+du, 1.0 - t);
- }
- else {
- gbuf.texCoord2d(s+du, t);
- }
- gbuf.vertex3d(qx*radius, py, qz*radius);
-
- s += (du*2.0);
-
- for (int j = 2; j <= xdiv; j++) {
- px = Math.cos(j*dtheta - Math.PI/2.0);
- pz = Math.sin(j*dtheta - Math.PI/2.0);
-
- gbuf.normal3d(px*sign, 0.0, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - (t + dv));
- }
- else {
- gbuf.texCoord2d(s, t+dv);
- }
- gbuf.vertex3d(px*radius, qy, pz*radius);
-
- gbuf.normal3d(px*sign, 0.0, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - t);
- }
- else {
- gbuf.texCoord2d(s, t);
- }
- gbuf.vertex3d(px*radius, py, pz*radius);
-
- s += du;
- }
-
- }
- s = 0.0;
- t += dv;
- py += dy;
- }
-
- gbuf.end();
-
- return gbuf;
- }
-
- // new coneBody method to remove transform in the Cone primitive
- // and to optimize by using triangle strip
- GeomBuffer coneBody(double bottom, double top, double bottomR, double topR,
- int xdiv, int ydiv, double dv, boolean outside, boolean texCoordYUp) {
-
- double r, sign;
-
- if (outside) sign = 1.0;
- else sign = -1.0;
-
- // compute the deltas
- double dtheta = 2.0*Math.PI/(double)xdiv;
- double dr = (topR-bottomR)/(double)ydiv;
- double height = top-bottom;
- double dy = height/(double)ydiv;
- double ynormal = (bottomR-topR)/height;
- double du = 1.0/(double)xdiv;
-// double dv = 1.0/(double)(ydiv+1);
-
- GeomBuffer gbuf = new GeomBuffer(ydiv*2*(xdiv+1));
-
- double s = 0.0, t = 0.0;
- double px, pz, qx, qz;
- double py = bottom;
- double qy;
- r = bottomR;
-
- gbuf.begin(GeomBuffer.QUAD_STRIP);
-
- for (int i = 0; i < ydiv; i++) {
- qy = py+dy;
- if (outside) {
- px = Math.cos(xdiv*dtheta - Math.PI/2.0);
- pz = Math.sin(xdiv*dtheta - Math.PI/2.0);
- qx = Math.cos((xdiv-1)*dtheta - Math.PI/2.0);
- qz = Math.sin((xdiv-1)*dtheta - Math.PI/2.0);
-
- // vert2
- gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - (t + dv));
- }
- else {
- gbuf.texCoord2d(s, t+dv);
- }
- gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr));
-
- // vert1
- gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - t);
- }
- else {
- gbuf.texCoord2d(s, t);
- }
- gbuf.vertex3d(px*r, py, pz*r);
-
- // vert4
- gbuf.normal3d(qx*sign, ynormal*sign, qz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s+du, 1.0 - (t + dv));
- }
- else {
- gbuf.texCoord2d(s+du, t+dv);
- }
- gbuf.vertex3d(qx*(r+dr), qy, qz*(r+dr));
-
- // vert3
- gbuf.normal3d(qx*sign, ynormal*sign, qz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s+du, 1.0 - t);
- }
- else {
- gbuf.texCoord2d(s+du, t);
- }
- gbuf.vertex3d(qx*r, py, qz*r);
-
- s += (du*2.0);
-
- for (int j = xdiv-2; j >= 0; j--) {
- px = Math.cos(j*dtheta - Math.PI/2.0);
- pz = Math.sin(j*dtheta - Math.PI/2.0);
-
- // vert 6
- gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - (t + dv));
- } else {
- gbuf.texCoord2d(s, t+dv);
- }
- gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr));
-
- // vert 5
- gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - t);
- }
- else {
- gbuf.texCoord2d(s, t);
- }
- gbuf.vertex3d(px*r, py, pz*r);
-
- s += du;
- }
- } else {
- px = Math.cos(-Math.PI/2.0);
- pz = Math.sin(-Math.PI/2.0);
- qx = Math.cos(dtheta - Math.PI/2.0);
- qz = Math.sin(dtheta - Math.PI/2.0);
-
- // vert1
- gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - (t + dv));
- }
- else {
- gbuf.texCoord2d(s, t+dv);
- }
- gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr));
-
- gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - t);
- }
- else {
- gbuf.texCoord2d(s, t);
- }
- gbuf.vertex3d(px*r, py, pz*r);
-
- gbuf.normal3d(qx*sign, ynormal*sign, qz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s+du, 1.0 - (t + dv));
- }
- else {
- gbuf.texCoord2d(s+du, t+dv);
- }
- gbuf.vertex3d(qx*(r+dr), qy, qz*(r+dr));
-
- gbuf.normal3d(qx*sign, ynormal*sign, qz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s+du, 1.0 - t);
- }
- else {
- gbuf.texCoord2d(s+du, t);
- }
- gbuf.vertex3d(qx*r, py, qz*r);
-
- s += (du*2.0);
-
- for (int j = 2; j <= xdiv; j++) {
- px = Math.cos(j*dtheta - Math.PI/2.0);
- pz = Math.sin(j*dtheta - Math.PI/2.0);
-
- gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - (t + dv));
- }
- else {
- gbuf.texCoord2d(s, t+dv);
- }
- gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr));
-
- gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - t);
- }
- else {
- gbuf.texCoord2d(s, t);
- }
- gbuf.vertex3d(px*r, py, pz*r);
-
- s += du;
- }
- }
- s = 0.0;
- t += dv;
- py += dy;
- r += dr;
- }
- gbuf.end();
-
- return gbuf;
- }
-
- // new coneTop method to remove transforms in the cone code
- GeomBuffer coneTop(double bottom, double radius, double height,
- int xdiv,double t, boolean outside, boolean texCoordYUp) {
-
- double sign;
-
- if (outside) sign = 1.0;
- else sign = -1.0;
-
- // compute the deltas
- double dtheta = 2.0*Math.PI/(double)xdiv;
- double ynormal = radius/height;
- double du = 1.0/(double)xdiv;
- double top = bottom + height;
-
- // initialize the geometry buffer
- GeomBuffer gbuf = new GeomBuffer(xdiv + 2);
- gbuf.begin(GeomBuffer.TRIANGLE_FAN);
-
- // add the tip, which is the center of the fan
- gbuf.normal3d(0.0, ynormal*sign, 0.0);
- if (texCoordYUp) {
- gbuf.texCoord2d(.5, 0.0);
- }
- else {
- gbuf.texCoord2d(.5, 1.0);
- }
- gbuf.vertex3d(0.0, top, 0.0);
-
- // go around the circle and add the rest of the fan
- double s = 0.0;
- double px, pz;
- if (outside) {
- for (int i = xdiv; i >= 0; i--) {
- px = Math.cos(i*dtheta - Math.PI/2.0);
- pz = Math.sin(i*dtheta - Math.PI/2.0);
- gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - t);
- } else {
- gbuf.texCoord2d(s, t);
- }
- gbuf.vertex3d(px*radius, bottom, pz*radius);
-
- s += du;
- }
- } else {
- for (int i = 0; i <= xdiv; i++) {
- px = Math.cos(i*dtheta - Math.PI/2.0);
- pz = Math.sin(i*dtheta - Math.PI/2.0);
- gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
- if (texCoordYUp) {
- gbuf.texCoord2d(s, 1.0 - t);
- } else {
- gbuf.texCoord2d(s, t);
- }
- gbuf.vertex3d(px*radius, bottom, pz*radius);
- s += du;
- }
- }
- gbuf.end();
- return gbuf;
- }
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Simple.java b/src/classes/share/com/sun/j3d/utils/geometry/Simple.java
deleted file mode 100644
index a3605be..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Simple.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-import javax.vecmath.Point3f;
-
-
-class Simple {
-
- /**
- * Handle a triangle or a quadrangle in a simple and efficient way. if the
- * face is more complex than false is returned.
- *
- * warning: the correctness of this function depends upon the fact that
- * `CleanPolyhedralFace' has not yet been executed; i.e., the
- * vertex indices have not been changed since the execution of
- * `CleanPolyhedron'! (otherwise, we would have to get the original
- * indices via calls to `GetOriginal'...)
- */
- static boolean simpleFace(Triangulator triRef, int ind1) {
- int ind0, ind2, ind3, ind4;
- int i1, i2, i3, i0, i4;
-
- Point3f pq, pr, nr;
-
- double x, y, z;
- int ori2, ori4;
-
- ind0 = triRef.fetchPrevData(ind1);
- i0 = triRef.fetchData(ind0);
-
- if (ind0 == ind1) {
- // this polygon has only one vertex! nothing to triangulate...
- System.out.println("***** polygon with only one vertex?! *****\n");
- return true;
- }
-
- ind2 = triRef.fetchNextData(ind1);
- i2 = triRef.fetchData(ind2);
- if (ind0 == ind2) {
- // this polygon has only two vertices! nothing to triangulate...
- System.out.println("***** polygon with only two vertices?! *****\n");
- return true;
- }
-
- ind3 = triRef.fetchNextData(ind2);
- i3 = triRef.fetchData(ind3);
- if (ind0 == ind3) {
- // this polygon is a triangle! let's triangulate it!
- i1 = triRef.fetchData(ind1);
- // triRef.storeTriangle(i1, i2, i3);
- triRef.storeTriangle(ind1, ind2, ind3);
- return true;
- }
-
- ind4 = triRef.fetchNextData(ind3);
- i4 = triRef.fetchData(ind4);
- if (ind0 == ind4) {
- // this polygon is a quadrangle! not too hard to triangulate it...
- // we project the corners of the quadrangle onto one of the coordinate
- // planes
- triRef.initPnts(5);
- i1 = triRef.fetchData(ind1);
-
- pq = new Point3f();
- pr = new Point3f();
- nr = new Point3f();
- /*
- System.out.println("ind0 " + ind0 + ", ind1 " + ind1 + ", ind2 " +
- ind2 + ", ind3 " + ind3 + ", ind4 " + ind4);
- System.out.println("i0 " + i0 +", i1 " + i1 + ", i2 " + i2 +
- ", i3 " + i3 + ", i4 " + i4);
-
- System.out.println("vert[i1] " + triRef.vertices[i1] +
- "vert[i2] " + triRef.vertices[i2] +
- "vert[i3] " + triRef.vertices[i3]);
- */
-
- Basic.vectorSub(triRef.vertices[i1], triRef.vertices[i2], pq);
- Basic.vectorSub(triRef.vertices[i3], triRef.vertices[i2], pr);
- Basic.vectorProduct(pq, pr, nr);
-
- // System.out.println("pq " + pq + " pr " + pr + " nr " + nr);
- x = Math.abs(nr.x);
- y = Math.abs(nr.y);
- z = Math.abs(nr.z);
- if ((z >= x) && (z >= y)) {
- // System.out.println("((z >= x) && (z >= y))");
- triRef.points[1].x = triRef.vertices[i1].x;
- triRef.points[1].y = triRef.vertices[i1].y;
- triRef.points[2].x = triRef.vertices[i2].x;
- triRef.points[2].y = triRef.vertices[i2].y;
- triRef.points[3].x = triRef.vertices[i3].x;
- triRef.points[3].y = triRef.vertices[i3].y;
- triRef.points[4].x = triRef.vertices[i4].x;
- triRef.points[4].y = triRef.vertices[i4].y;
- }
- else if ((x >= y) && (x >= z)) {
- // System.out.println("((x >= y) && (x >= z))");
- triRef.points[1].x = triRef.vertices[i1].z;
- triRef.points[1].y = triRef.vertices[i1].y;
- triRef.points[2].x = triRef.vertices[i2].z;
- triRef.points[2].y = triRef.vertices[i2].y;
- triRef.points[3].x = triRef.vertices[i3].z;
- triRef.points[3].y = triRef.vertices[i3].y;
- triRef.points[4].x = triRef.vertices[i4].z;
- triRef.points[4].y = triRef.vertices[i4].y;
- }
- else {
- triRef.points[1].x = triRef.vertices[i1].x;
- triRef.points[1].y = triRef.vertices[i1].z;
- triRef.points[2].x = triRef.vertices[i2].x;
- triRef.points[2].y = triRef.vertices[i2].z;
- triRef.points[3].x = triRef.vertices[i3].x;
- triRef.points[3].y = triRef.vertices[i3].z;
- triRef.points[4].x = triRef.vertices[i4].x;
- triRef.points[4].y = triRef.vertices[i4].z;
- }
- triRef.numPoints = 5;
-
- // find a valid diagonal
- ori2 = Numerics.orientation(triRef, 1, 2, 3);
- ori4 = Numerics.orientation(triRef, 1, 3, 4);
-
- /*
- for(int i=0; i<5; i++)
- System.out.println("point " + i + ", " + triRef.points[i]);
- System.out.println("ori2 : " + ori2 + " ori4 : " + ori4);
- */
-
- if (((ori2 > 0) && (ori4 > 0)) ||
- ((ori2 < 0) && (ori4 < 0))) {
-
- // i1, i3 is a valid diagonal;
- //
- // encode as a 2-triangle strip: the triangles are (2, 3, 1)
- // and (1, 3, 4).
-
- // triRef.storeTriangle(i1, i2, i3);
- // triRef.storeTriangle(i1, i3, i4);
- triRef.storeTriangle(ind1, ind2, ind3);
- triRef.storeTriangle(ind1, ind3, ind4);
- }
- else {
- // i2, i4 has to be a valid diagonal. (if this is no valid
- // diagonal then the corners of the quad form a figure of eight;
- // shall we apply any heuristics in order to guess which diagonal
- // is more likely to be the better choice? alternatively, we could
- // return false and subject it to the standard triangulation
- // algorithm. well, let's see how this brute-force solution works.)
-
- // encode as a 2-triangle strip: the triangles are (1, 2, 4)
- // and (4, 2, 3).
-
- // triRef.storeTriangle(i2, i3, i4);
- // triRef.storeTriangle(i2, i4, i1);
- triRef.storeTriangle(ind2, ind3, ind4);
- triRef.storeTriangle(ind2, ind4, ind1);
- }
- return true;
- }
-
- return false;
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Sphere.java b/src/classes/share/com/sun/j3d/utils/geometry/Sphere.java
deleted file mode 100644
index 98f56ec..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Sphere.java
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry;
-
-import javax.media.j3d.Appearance;
-import javax.media.j3d.Node;
-import javax.media.j3d.NodeComponent;
-import javax.media.j3d.Shape3D;
-import javax.vecmath.Point3f;
-import javax.vecmath.TexCoord2f;
-import javax.vecmath.Vector3f;
-
-/**
- * Sphere is a geometry primitive created with a given radius and resolution.
- * It is centered at the origin.
- * getShape
.
- *
- * @see Sphere#getShape
- */
- public static final int BODY = 0;
-
- static final int MID_REZ_DIV = 16;
- float radius;
- int divisions;
-
- /**
- * Constructs a Sphere of a given radius. Normals are generated
- * by default, texture coordinates are not. The resolution defaults to
- * 15 divisions along sphere's axes. Appearance defaults to white.
- * @param radius Radius
- */
- public Sphere (float radius) {
- this(radius, GENERATE_NORMALS, MID_REZ_DIV);
- }
-
- /**
- * Constructs a default Sphere of radius of 1.0. Normals are generated
- * by default, texture coordinates are not.
- * Resolution defaults to 15 divisions. Appearance defaults to white.
- */
- public Sphere() {
- this(1.0f, GENERATE_NORMALS, MID_REZ_DIV);
- }
-
- /**
- * Constructs a Sphere of a given radius and appearance.
- * Normals are generated by default, texture coordinates are not.
- * @param radius Radius
- * @param ap Appearance
- */
-
- public Sphere (float radius, Appearance ap) {
- this(radius, GENERATE_NORMALS, MID_REZ_DIV, ap);
- }
-
- /**
- * Constructs a Sphere of a given radius and appearance with
- * additional parameters specified by the Primitive flags.
- * @param radius Radius
- * @param primflags
- * @param ap appearance
- */
- public Sphere(float radius, int primflags, Appearance ap) {
- this(radius, primflags, MID_REZ_DIV, ap);
- }
-
- /**
- * Constructs a Sphere of a given radius and number of divisions
- * with additional parameters specified by the Primitive flags.
- * Appearance defaults to white.
- * @param radius Radius
- * @param divisions Divisions
- * @param primflags Primflags
- */
- public Sphere(float radius, int primflags, int divisions) {
- this(radius, primflags, divisions, null);
- }
-
-
- /**
- * Obtains Sphere's shape node that contains the geometry.
- * This allows users to modify the appearance or geometry.
- * @param partId The part to return (must be BODY for Spheres)
- * @return The Shape3D object associated with the partId. If an
- * invalid partId is passed in, null is returned.
- */
- @Override
- public Shape3D getShape(int partId) {
- if (partId != BODY) return null;
-// return (Shape3D)((Group)getChild(0)).getChild(BODY);
- return (Shape3D)getChild(BODY);
- }
-
- /** Obtains Sphere's shape node that contains the geometry.
- */
- public Shape3D getShape() {
-// return (Shape3D)((Group)getChild(0)).getChild(BODY);
- return (Shape3D)getChild(BODY);
- }
-
- /** Sets appearance of the Sphere.
- */
- @Override
- public void setAppearance(Appearance ap) {
-// ((Shape3D)((Group)getChild(0)).getChild(BODY)).setAppearance(ap);
- ((Shape3D)getChild(BODY)).setAppearance(ap);
- }
-
- /**
- * Gets the appearance of the specified part of the sphere.
- *
- * @param partId identifier for a given subpart of the sphere
- *
- * @return The appearance object associated with the partID. If an
- * invalid partId is passed in, null is returned.
- *
- * @since Java 3D 1.2.1
- */
- @Override
- public Appearance getAppearance(int partId) {
- if (partId != BODY) return null;
- return getShape(partId).getAppearance();
- }
-
-
- /**
- * Constructs a customized Sphere of a given radius,
- * number of divisions, and appearance, with additional parameters
- * specified by the Primitive flags. The resolution is defined in
- * terms of number of subdivisions along the sphere's axes. More
- * divisions lead to more finely tesselated objects.
- * cloneNode
should be overridden by any user subclassed
- * objects. All subclasses must have their cloneNode
- * method consist of the following lines:
- *
- * @param forceDuplicate when set to
- * public Node cloneNode(boolean forceDuplicate) {
- * UserSubClass usc = new UserSubClass();
- * usc.duplicateNode(this, forceDuplicate);
- * return usc;
- * }
- *
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.
- *
- * @see Node#cloneTree
- * @see Node#duplicateNode
- * @see NodeComponent#setDuplicateOnCloneTree
- */
- @Override
- public Node cloneNode(boolean forceDuplicate) {
- Sphere s = new Sphere(radius, flags, divisions, getAppearance());
- s.duplicateNode(this, forceDuplicate);
-
- return s;
- }
-
- /**
- * 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.
- * 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
.
- *
- * @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.
- *
- * @see Node#cloneTree
- * @see Node#cloneNode
- * @see NodeComponent#setDuplicateOnCloneTree
- */
- @Override
- public void duplicateNode(Node originalNode, boolean forceDuplicate) {
- super.duplicateNode(originalNode, forceDuplicate);
- }
-
- /**
- * Returns the radius of the sphere
- *
- * @since Java 3D 1.2.1
- */
- public float getRadius() {
- return radius;
- }
-
- /**
- * Returns the number of divisions
- *
- * @since Java 3D 1.2.1
- */
- public int getDivisions() {
- return divisions;
- }
-
- void buildQuadrant(GeomBuffer gbuf, double startDelta, double endDelta,
- int sign, int nstep, int n, boolean upperSphere)
- {
-
- double ds, dt, theta, delta;
- int i, j, index, i2;
- double h, r, vx, vz;
- Point3f pt;
- Vector3f norm;
- TexCoord2f texCoord;
- double starth;
- double t;
- boolean leftToRight;
-
-
- if (upperSphere) {
- dt = Math.PI/(2*nstep);
- theta = dt;
- starth = 1;
- leftToRight = (sign > 0);
- } else {
- dt = -Math.PI/(2*nstep);
- theta = Math.PI + dt;
- starth = -1;
- leftToRight = (sign < 0);
- }
-
-
- for (i = 1; i <= nstep; i++) {
- h = Math.cos(theta);
- r = Math.sin(theta);
- if (sign > 0) {
- t = 1 - theta/Math.PI;
- } else {
- t = theta/Math.PI;
- }
-
- i2 = i << 1;
- // subdivision decreases towards the pole
- ds = (endDelta - startDelta) / i;
-
- gbuf.begin(GeomBuffer.TRIANGLE_STRIP);
-
- if (leftToRight) {
- // Build triangle strips from left to right
- delta = startDelta;
-
- for (j=0; j < i; j++) {
- vx = r*Math.cos(delta);
- vz = r*Math.sin(delta);
-
- gbuf.normal3d( vx*sign, h*sign, vz*sign );
- gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t);
- gbuf.vertex3d( vx*radius, h*radius, vz*radius );
- if (i > 1) {
- // get previous vertex from buffer
- index = gbuf.currVertCnt - i2;
- pt = gbuf.pts[index];
- norm = gbuf.normals[index];
- texCoord = gbuf.tcoords[index];
- // connect with correspondent vertices from previous row
- gbuf.normal3d(norm.x, norm.y, norm.z);
- gbuf.texCoord2d(texCoord.x, texCoord.y);
- gbuf.vertex3d(pt.x, pt.y, pt.z);
- } else {
- gbuf.normal3d(0, sign*starth, 0);
- if (sign > 0) {
- gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI),
- 1.0 - (theta - dt)/Math.PI);
- } else {
- gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI),
- (theta - dt)/Math.PI);
- }
- gbuf.vertex3d( 0, starth*radius, 0);
-
- }
- delta += ds;
- }
-
- // Put the last vertex in that row,
- // for numerical accuracy we don't use delta
- // compute from above.
- delta = endDelta;
- vx = r*Math.cos(delta);
- vz = r*Math.sin(delta);
- gbuf.normal3d( vx*sign, h*sign, vz*sign );
- gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t);
- gbuf.vertex3d( vx*radius, h*radius, vz*radius);
- } else {
- delta = endDelta;
- // Build triangle strips from right to left
- for (j=i; j > 0; j--) {
- vx = r*Math.cos(delta);
- vz = r*Math.sin(delta);
-
- gbuf.normal3d( vx*sign, h*sign, vz*sign );
- // Convert texture coordinate back to one
- // set in previous version
- gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t);
- gbuf.vertex3d( vx*radius, h*radius, vz*radius );
- if (i > 1) {
- // get previous vertex from buffer
- index = gbuf.currVertCnt - i2;
- pt = gbuf.pts[index];
- norm = gbuf.normals[index];
- texCoord = gbuf.tcoords[index];
- gbuf.normal3d(norm.x, norm.y, norm.z);
- gbuf.texCoord2d(texCoord.x, texCoord.y);
- gbuf.vertex3d(pt.x, pt.y, pt.z);
- } else {
- gbuf.normal3d(0, sign*starth, 0);
- if (sign > 0) {
- gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI),
- 1.0 - (theta - dt)/Math.PI);
- } else {
- gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI),
- (theta - dt)/Math.PI);
- }
- gbuf.vertex3d( 0, starth*radius, 0);
-
- }
- delta -= ds;
- }
-
- // Put the last vertex in that row,
- // for numerical accuracy we don't use delta
- // compute from above.
- delta = startDelta;
- vx = r*Math.cos(delta);
- vz = r*Math.sin(delta);
- gbuf.normal3d( vx*sign, h*sign, vz*sign );
- gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t);
- gbuf.vertex3d( vx*radius, h*radius, vz*radius );
-
- }
-
- gbuf.end();
-
- if (i < nstep) {
- theta += dt;
- } else { // take care of numerical imprecision
- theta = Math.PI/2;
- }
- }
-
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Stripifier.java b/src/classes/share/com/sun/j3d/utils/geometry/Stripifier.java
deleted file mode 100644
index e6f34a2..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Stripifier.java
+++ /dev/null
@@ -1,2529 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-import java.util.ArrayList;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-/**
- * The Stripifier utility will change the primitive of the GeometryInfo
- * object to Triangle Strips. The strips are made by analyzing the
- * triangles in the original data and connecting them together.
- * GeometryInfo gi = new GeometryInfo(TRIANGLE_ARRAY);
- * gi.setCoordinates(coordinateData);
- *
- * NormalGenerator ng = new NormalGenerator();
- * ng.generateNormals(gi);
- *
- * Stripifier st = new Stripifier()
- * st.stripify(gi);
- *
- * Shape3D part = new Shape3D();
- * part.setAppearance(appearance);
- * part.setGeometry(gi.getGeometryArray());
- *
- */
-public class Stripifier {
-
- final boolean DEBUG = false;
- final boolean CHECK_ORIENT = false;
-
- static final int EMPTY = -1;
-
- boolean hasNormals = false;
- boolean hasTextures = false;
- int texSetCount = 0;
- boolean hasColors = false;
- boolean colorStrips = false;
-
- StripifierStats stats;
-
- int[] numNhbrs;
-
- /**
- * Indicates to the stripifier to collect statistics on the data
- */
- public static final int COLLECT_STATS = 0x01;
-
- /**
- * Creates the Stripifier object.
- */
- public Stripifier() {
- }
-
- /**
- * Creates the Stripifier object.
- * @param flags Flags
- * @since Java 3D 1.2.1
- */
- public Stripifier(int flags) {
- if ((flags & COLLECT_STATS) != 0) {
- stats = new StripifierStats();
- }
- }
-
- /**
- * Converts the geometry contained in the GeometryInfo object into an
- * array of triangle strips.
- */
- public void stripify(GeometryInfo gi) {
- // System.out.println("stripify");
- long time = System.currentTimeMillis();
- // setup
- gi.convertToIndexedTriangles();
- gi.forgetOldPrim();
-
- // write out the gi object
- // System.out.println("write out the object");
- // gi.writeObj();
-
- Face[] faces = createFaceArray(gi);
- Edge[] edges = createEdgeArray(faces);
- buildAdjacencies(edges, faces);
-
- // print out the adjacency information
- if (DEBUG) {
- for (int i = 0; i < faces.length; i++) {
- faces[i].printVertices();
- }
- System.out.println("");
- for (int i = 0; i < faces.length; i++) {
- faces[i].printAdjacency();
- }
- System.out.println("");
- }
-
- Node[] faceNodes = new Node[faces.length];
- // Node[] queue = hybridSearch(faces, faceNodes);
- Node[] queue = dfSearch(faces, faceNodes);
-
- // print out the queue
- if (DEBUG) {
- for (int i = 0; i < queue.length; i++) {
- queue[i].print();
- }
- System.out.println("");
- }
-
- // int "pointers" for the numbers of strips and patches from
- // hamiliton
- int[] ns = new int[1];
- int[] np = new int[1];
- ArrayList hamiltons = hamilton(queue, ns, np);
- int numStrips = ns[0];
- int numPatches = np[0];
-
- // print out the hamiltonians
- if (DEBUG) {
- for (int i = 0; i < hamiltons.size(); i++) {
- System.out.println("Hamiltonian: " + i);
- ArrayList list = (ArrayList)hamiltons.get(i);
- for (int j = 0; j < list.size(); j++) {
- Face face = (Face)list.get(j);
- face.printVertices();
- }
- System.out.println("");
- }
- }
-
- // now make strips out of the hamiltonians
- ArrayList strips = stripe(hamiltons);
-
- // print out the strips
- if (DEBUG) {
- for (int i = 0; i < strips.size(); i++) {
- System.out.println("Strip: " + i);
- Istream istream = (Istream)strips.get(i);
- for (int j = 0; j < istream.length; j++) {
- System.out.println("vertex: " + istream.istream[j].index);
- }
- System.out.println("");
- }
- }
-
- // concatenate the strips
- concatenate(strips, faces);
-
- // print out the new strips
- if (DEBUG) {
- System.out.println("");
- System.out.println("concatenated strips: (" +
- (strips.size()) + ")");
- System.out.println("");
- for (int i = 0; i < strips.size(); i++) {
- System.out.println("Strip: " + i);
- Istream istream = (Istream)strips.get(i);
- for (int j = 0; j < istream.length; j++) {
- System.out.println("vertex: " + istream.istream[j].index);
- }
- System.out.println("");
- }
- }
-
- // put the stripified data into the GeometryInfo object
- putBackData(gi, strips);
-
- // System.out.println("time: " + (System.currentTimeMillis()-time));
- // System.out.println("");
-
- // add to stats
- if (stats != null) {
- stats.updateInfo(System.currentTimeMillis()-time, strips,
- faces.length);
- }
-
- // Stat.printInfo();
-
- // print out strip count info
- // System.out.println("numStrips = " + strips.size());
- // System.out.println("stripCounts:");
- // int avg = 0;
- // for (int i = 0; i < strips.size(); i++) {
- // System.out.print(((Istream)strips.get(i)).length + " ");
- // avg += ((Istream)strips.get(i)).length;
- // }
- // System.out.println("Avg: " + ((double)avg/(double)strips.size()));
- }
-
- /**
- * Prints out statistical information for the stripifier: the number of
- * original triangles, the number of original vertices, the number of
- * strips created, the number of vertices, the total number of triangles,
- * the minimum strip length (in # of tris) the maximum strip length
- * (in number of tris), the average strip length (in # of tris), the
- * average number of vertices per triangle, the total time it took to
- * stripify, and the strip length (how many strips of a given length.
- * The data is cumulative over all the times the stripifier is called
- * until the stats are printed, and then they are reset.
- */
- // public static void printStats() {
- // // stats.toString();
- // }
-
- /**
- * Returns the stripifier stats object.
- * @exception IllegalStateException if the Stripfier has not
- * been constructed
- * with the COLLECT_STATS flag
- * @since Java 3D 1.2.1
- */
- public StripifierStats getStripifierStats() {
- if (stats == null) {
- throw new IllegalStateException(J3dUtilsI18N.getString("Stripifier0"));
- }
- return stats;
- }
-
- /**
- * Creates an array of faces from the geometry in the GeometryInfo object.
- */
- Face[] createFaceArray(GeometryInfo gi) {
- int[] vertices = gi.getCoordinateIndices();
- int[] normals = gi.getNormalIndices();
-
- int[][] textures = null;
- int[] t1 = null;
- int[] t2 = null;
- int[] t3 = null;
- texSetCount = gi.getTexCoordSetCount();
- if (texSetCount > 0) {
- hasTextures = true;
- textures = new int[texSetCount][];
- for (int i = 0; i < texSetCount; i++) {
- textures[i] = gi.getTextureCoordinateIndices(i);
- }
- t1 = new int[texSetCount];
- t2 = new int[texSetCount];
- t3 = new int[texSetCount];
- } else hasTextures = false;
-
- int[] colors = gi.getColorIndices();
- Face[] faces = new Face[vertices.length/3];
- int n1, n2, n3, c1, c2, c3;
- Vertex v1, v2, v3;
- int count = 0;
- for (int i = 0; i < vertices.length;) {
- if (normals != null) {
- // System.out.println("hasNormals");
- hasNormals = true;
- n1 = normals[i];
- n2 = normals[i+1];
- n3 = normals[i+2];
- }
- else {
- // System.out.println("doesn't have normals");
- hasNormals = false;
- n1 = EMPTY;
- n2 = EMPTY;
- n3 = EMPTY;
- }
- if (hasTextures) {
- for (int j = 0; j < texSetCount; j++) {
- t1[j] = textures[j][i];
- t2[j] = textures[j][(i+1)];
- t3[j] = textures[j][(i+2)];
- }
- }
- if (colors != null) {
- hasColors = true;
- c1 = colors[i];
- c2 = colors[i+1];
- c3 = colors[i+2];
- }
- else {
- hasColors = false;
- c1 = EMPTY;
- c2 = EMPTY;
- c3 = EMPTY;
- }
- v1 = new Vertex(vertices[i], n1, texSetCount, t1, c1);
- v2 = new Vertex(vertices[i+1], n2, texSetCount, t2, c2);
- v3 = new Vertex(vertices[i+2], n3, texSetCount, t3, c3);
- if (!v1.equals(v2) && !v2.equals(v3) && !v3.equals(v1)) {
- faces[count] = new Face(count, v1, v2, v3);
- count++;
- }
- i+=3;
- }
-
- if (faces.length > count) {
- Face[] temp = faces;
- faces = new Face[count];
- System.arraycopy(temp, 0, faces, 0, count);
- }
- return faces;
- }
-
- /**
- * Creates an array of edges from the Face array.
- */
- Edge[] createEdgeArray(Face[] faces) {
- Edge[] edges = new Edge[faces.length*3];
- Face face;
- for (int i = 0; i < faces.length; i++) {
- face = faces[i];
- edges[i*3] = new Edge(face.verts[0], face.verts[1], face.key);
- edges[i*3+1] = new Edge(face.verts[1], face.verts[2], face.key);
- edges[i*3+2] = new Edge(face.verts[2], face.verts[0], face.key);
- }
- return edges;
- }
-
- /**
- * Builds the adjacency graph by finding the neighbors of the edges
- */
- void buildAdjacencies(Edge[] edges, Face[] faces) {
- // sortEdges(edges);
- quickSortEdges(edges, 0, edges.length-1);
- // int i = 1;
-
- // set up the edge list of each face
- Edge edge;
- Face face;
- Vertex[] verts;
- boolean flag;
- int k;
- for (int i = 0; i < edges.length; i++) {
- // edges are kept in order s.t. the ith edge is the opposite
- // edge of the ith vertex
- edge = edges[i];
- face = faces[edge.face];
- verts = face.verts;
-
- flag = true;
- if ((!verts[0].equals(edge.v1)) && (!verts[0].equals(edge.v2))) {
- face.edges[0] = edge;
- face.numNhbrs--;
- flag = false;
- }
- else if ((!verts[1].equals(edge.v1)) &&
- (!verts[1].equals(edge.v2))) {
- face.edges[1] = edge;
- face.numNhbrs--;
- flag = false;
- }
- else if ((!verts[2].equals(edge.v1)) &&
- (!verts[2].equals(edge.v2))) {
- face.edges[2] = edge;
- face.numNhbrs--;
- flag = false;
- }
- else {
- if (DEBUG) System.out.println("error!!! Stripifier.buildAdj");
- }
-
- // handle degenerencies
- if (flag) {
- Vertex i1;
- // triangle degenerated to a point
- if ((edge.v1).equals(edge.v2)) {
- face.edges[--face.numNhbrs] = edge;
- }
- // triangle degenerated to an edge
- else {
- if (verts[0].equals(verts[1])) {
- i1 = verts[1];
- }
- else {
- i1 = verts[2];
- }
- if (verts[0].equals(i1) && face.edges[0] == null) {
- face.edges[0] = edge;
- face.numNhbrs--;
- }
- else if (verts[1].equals(i1) && face.edges[1] == null) {
- face.edges[1] = edge;
- face.numNhbrs--;
- }
- else {
- face.edges[2] = edge;
- face.numNhbrs--;
- }
- }
- }
- }
-
- // build the adjacency information by pairing up every two triangles
- // that share the same edge
- int i = 0; int j = 0;
- int j1, j2;
- while (i < (edges.length-1)) {
- j = i+1;
- if (edges[i].equals(edges[j])) {
- // determine the orientations of the common edge in the two
- // adjacent triangles. Only set them to be adjacent if they
- // are opposite
- j1 = edges[i].face;
- j2 = edges[j].face;
- if (j1 != j2) { // set up the two faces as neighbors
- edge = edges[i];
- face = faces[j1];
- k = face.getEdgeIndex(edge);
- if ((edge.v1.equals(face.verts[(k+1)%3])) &&
- (edge.v2.equals(face.verts[(k+2)%3]))) {
- flag = false;
- }
- else flag = true;
-
- edge = edges[j];
- face = faces[j2];
- k = face.getEdgeIndex(edge);
- if ((edge.v1.equals(face.verts[(k+1)%3])) &&
- (edge.v2.equals(face.verts[(k+2)%3]))) {
- flag = flag;
- }
- else flag = (!flag);
-
- if (flag) {
- edges[i].face = j2;
- edges[j].face = j1;
- (faces[j1].numNhbrs)++;
- (faces[j2].numNhbrs)++;
- j++;
- }
- else edges[i].face = EMPTY;
- }
- else edges[i].face = EMPTY;
- }
- else edges[i].face = EMPTY;
- i=j;
- }
- if (i <= (edges.length-1)) edges[i].face = EMPTY;
-
- // check, for each face, if it is duplicated. For a face that
- // neighbors its duplicate in the adjacency graph, it's possible
- // that two or more of its neighbors are the same (the duplicate).
- // This will be corrected to avoid introducing redundant faces
- // later on
-
- for (i = 0; i < faces.length; i++) {
- face = faces[i];
- if (face.numNhbrs == 3) {
- if ((j1 = face.edges[1].face) == face.edges[0].face) {
- face.edges[1].face = EMPTY;
- face.numNhbrs--;
- faces[j1].counterEdgeDel(face.edges[1]);
- }
- if ((j2 = face.edges[2].face) == face.edges[0].face) {
- face.edges[2].face = EMPTY;
- face.numNhbrs--;
- faces[j2].counterEdgeDel(face.edges[2]);
- }
- if ((face.edges[1].face != EMPTY) && (j1 == j2)) {
- face.edges[2].face = EMPTY;
- face.numNhbrs--;
- faces[j1].counterEdgeDel(face.edges[2]);
- }
- }
- }
- }
-
- /**
- * Sorts the edges using BubbleSort
- */
- void sortEdges(Edge[] edges) {
- int i = edges.length;
- boolean sorted = false;
- Edge temp = null;
- while ((i > 1) && !sorted) {
- sorted = true;
- for (int j = 1; j < i; j++) {
- if (edges[j].lessThan(edges[j-1])) {
- temp = edges[j-1];
- edges[j-1] = edges[j];
- edges[j] = temp;
- sorted = false;
- }
- }
- i--;
- }
- }
-
- /**
- * uses quicksort to sort the edges
- */
- void quickSortEdges(Edge[] edges, int l, int r) {
- if (edges.length > 0) {
- int i = l;
- int j = r;
- Edge k = edges[(l+r) / 2];
-
- do {
- while (edges[i].lessThan(k)) i++;
- while (k.lessThan(edges[j])) j--;
- if (i <= j) {
- Edge tmp = edges[i];
- edges[i] = edges[j];
- edges[j] = tmp;
- i++;
- j--;
- }
- } while (i <= j);
-
- if (l < j) quickSortEdges(edges, l, j);
- if (l < r) quickSortEdges(edges, i, r);
- }
- }
-
- /**
- * Takes a list of faces as input and performs a hybrid search, a
- * variated depth first search that returns to the highest level node
- * not yet fully explored. Returns an array of pointers to the faces
- * found in order from the search. The faceNodes parameter is an
- * array of the Nodes created for the faces.
- */
- Node[] hybridSearch(Face[] faces, Node[] faceNodes) {
-
- int numFaces = faces.length;
- int i = 0, j = 0, k = 0, ind = 0;
-
- // keep # of faces with certain # of neighbors
- int[] count = {0, 0, 0, 0};
-
- // faces sorted by number of neighbors
- int[] index = new int[numFaces];
- // the index of a certain face in the sorted array
- int[] rindex = new int[numFaces];
-
- // Control list pop up operation
- boolean popFlag = false;
-
- // queue of pointers to faces found in search
- Node[] queue = new Node[numFaces];
- // root of depth first tree
- Node source;
- // for the next node
- Node nnode;
- // a face
- Face face;
- // starting position for insertion into the list
- int start = 0;
- // list for search
- SortedList dlist;
-
- // count how many faces have a certain # of neighbors and
- // create a Node for each face
- for (i = 0; i < numFaces; i++) {
- j = faces[i].numNhbrs;
- count[j]++;
- faceNodes[i] = new Node(faces[i]);
- }
-
- // to help with sorting
- for (i = 1; i < 4; i++) {
- count[i] += count[i-1];
- }
-
- // decreasing i to make sorting stable
- for (i = numFaces - 1; i >= 0; i--) {
- j = faces[i].numNhbrs;
- count[j]--;
- index[count[j]] = i;
- rindex[i] = count[j];
- }
-
- // start the hybrid search
- for (i = 0; i < numFaces; i++) {
- if (index[i] != EMPTY) {
- dlist = new SortedList();
- source = faceNodes[index[i]];
- source.setRoot();
- queue[ind] = source;
- ind++;
- index[i] = EMPTY;
-
- while (source != null) {
- nnode = null;
- // use the first eligible for continuing search
- face = source.face;
- for (j = 0; j < 3; j++) {
- k = face.getNeighbor(j);
- if ((k != EMPTY) &&
- (faceNodes[k].notAccessed())) {
- nnode = faceNodes[k];
- break;
- }
- }
-
- if (nnode != null) {
- // insert the new node
- nnode.insert(source);
- if (!popFlag) {
- start = dlist.sortedInsert(source, start);
- }
- else popFlag = false;
- source = nnode;
- queue[ind] = source;
- ind++;
- index[rindex[k]] = EMPTY;
- }
- else {
- source.processed();
- source = dlist.pop();
- popFlag = true;
- start = 0;
- }
- } // while -- does popFlag need to be set to false here?
- }
- }
- return queue;
- }
-
- Node[] dfSearch(Face[] faces, Node[] faceNodes) {
- int numFaces = faces.length;
- int i = 0, j = 0, k = 0, ind = 0;
-
- // keep certain # of faces with certain # of neighbors
- int[] count = {0, 0, 0, 0};
-
- // faces sorted by # of neighbors
- int[] index = new int[numFaces];
- // index of a certain face in the sorted array
- int[] rindex = new int[numFaces];
-
- // queue of pointers to faces found in the search
- Node[] queue = new Node[numFaces];
- // root of the depth first tree
- Node source;
- // the current node
- Node node;
- // for the next Node
- Node nnode;
- // a face
- Face face;
-
- // count how many faces have a certain # of neighbors and create
- // a Node for each face
- for (i = 0; i < numFaces; i++) {
- j = faces[i].numNhbrs;
- count[j]++;
- faceNodes[i] = new Node(faces[i]);
- }
-
- // to help with sorting
- for (i = 1; i < 4; i++) count[i] += count[i-1];
-
- // dec i to make sorting stable
- for (i = numFaces-1; i >= 0; i--) {
- j = faces[i].numNhbrs;
- count[j]--;
- index[count[j]] = i;
- rindex[i] = count[j];
- }
-
- setNumNhbrs(faces);
- // start the dfs
- for (i = 0; i < numFaces; i++) {
- if (index[i] != EMPTY) {
- source = faceNodes[index[i]];
- source.setRoot();
- queue[ind] = source;
- ind++;
- index[i] = EMPTY;
- node = source;
-
- do {
- // if source has been done, stop
- if ((node == source) && (node.right != null)) break;
-
- nnode = null;
- face = node.face;
-
- // for (j = 0; j < 3; j++) {
- // if (((k = face.getNeighbor(j)) != EMPTY) &&
- // (faceNodes[k].notAccessed())) {
- // nnode = faceNodes[k];
- // break;
- // }
- // }
-
- k = findNext(node, faceNodes, faces);
- if (k != EMPTY) nnode = faceNodes[k];
- if (nnode != null) updateNumNhbrs(nnode);
-
- if (nnode != null) {
- // insert new node
- nnode.insert(node);
- node = nnode;
- queue[ind] = node;
- ind++;
- index[rindex[k]] = EMPTY;
- }
- else {
- node.processed();
- node = node.parent;
- }
- } while (node != source.parent);
- }
- }
- freeNhbrTable();
- return queue;
- }
-
- int findNext(Node node, Node[] faceNodes, Face[] faces) {
- Face face = node.face;
- // this face has no neighbors so return
- if (face.numNhbrs == 0) return EMPTY;
-
- int i, j, count;
- int[] n = new int[3]; // num neighbors of neighboring face
- int[] ind = {-1, -1, -1}; // neighboring faces
-
- // find the number of neighbors for each neighbor
- count = 0;
- for (i = 0; i < 3; i++) {
- if (((j = face.getNeighbor(i)) != EMPTY) &&
- (faceNodes[j].notAccessed())) {
- ind[count] = j;
- n[count] = numNhbrs[j];
- count++;
- }
- }
-
- // this face has no not accessed faces
- if (count == 0) return EMPTY;
-
- // this face has only one neighbor
- if (count == 1) return ind[0];
-
- if (count == 2) {
- // if the number of neighbors are the same, try reseting
- if ((n[0] == n[1]) && (n[0] != 0)) {
- n[0] = resetNhbr(ind[0], faces, faceNodes);
- n[1] = resetNhbr(ind[1], faces, faceNodes);
- }
- // if one neighbor has fewer neighbors, return that neighbor
- if (n[0] < n[1]) return ind[0];
- if (n[1] < n[0]) return ind[1];
- // neighbors tie. pick the sequential one
- Node pnode, ppnode;
- Face pface, ppface;
- if ((pnode = node.parent) != null) {
- pface = pnode.face;
- i = pface.findSharedEdge(face.key);
- if ((ppnode = pnode.parent) != null) {
- ppface = ppnode.face;
- if (pface.getNeighbor((i+1)%3) == ppface.key) {
- j = pface.verts[(i+2)%3].index;
- }
- else {
- j = pface.verts[(i+1)%3].index;
- }
- }
- else {
- j = pface.verts[(i+1)%3].index;
- }
- i = face.findSharedEdge(ind[0]);
- if (face.verts[i].index == j) return ind[0];
- else return ind[1];
- }
- else return ind[0];
- }
- // three neighbors
- else {
- if ((n[0] < n[1]) && (n[0] < n[2])) return ind[0];
- else if ((n[1] < n[0]) && (n[1] < n[2])) return ind[1];
- else if ((n[2] < n[0]) && (n[2] < n[1])) return ind[2];
- else if ((n[0] == n[1]) && (n[0] < n[2])) {
- if (n[0] != 0) {
- n[0] = resetNhbr(ind[0], faces, faceNodes);
- n[1] = resetNhbr(ind[1], faces, faceNodes);
- }
- if (n[0] <= n[1]) return ind[0];
- else return ind[1];
- }
- else if ((n[1] == n[2]) && n[1] < n[0]) {
- if (n[1] != 0) {
- n[1] = resetNhbr(ind[1], faces, faceNodes);
- n[2] = resetNhbr(ind[2], faces, faceNodes);
- }
- if (n[1] <= n[2]) return ind[1];
- else return ind[2];
- }
- else if ((n[2] == n[0]) && (n[2] < n[1])) {
- if (n[0] != 0) {
- n[0] = resetNhbr(ind[0], faces, faceNodes);
- n[2] = resetNhbr(ind[2], faces, faceNodes);
- }
- if (n[0] <= n[2]) return ind[0];
- else return ind[2];
- }
- else {
- if (n[0] != 0) {
- n[0] = resetNhbr(ind[0], faces, faceNodes);
- n[1] = resetNhbr(ind[1], faces, faceNodes);
- n[2] = resetNhbr(ind[2], faces, faceNodes);
- }
- if ((n[0] <= n[1]) && (n[0] <= n[2])) return ind[0];
- else if (n[1] <= n[2]) return ind[1];
- else return ind[2];
- }
- }
- }
-
- void setNumNhbrs(Face[] faces) {
- int numFaces = faces.length;
- numNhbrs = new int[numFaces];
- for (int i = 0; i < numFaces; i++) {
- numNhbrs[i] = faces[i].numNhbrs;
- }
- }
-
- void freeNhbrTable() {
- numNhbrs = null;
- }
-
- void updateNumNhbrs(Node node) {
- Face face = node.face;
- int i;
- if ((i = face.getNeighbor(0)) != EMPTY) numNhbrs[i]--;
- if ((i = face.getNeighbor(1)) != EMPTY) numNhbrs[i]--;
- if ((i = face.getNeighbor(2)) != EMPTY) numNhbrs[i]--;
- }
-
- int resetNhbr(int y, Face[] faces, Node[] faceNodes) {
- int x = EMPTY;
- Face nface = faces[y];
- int i;
- for (int j = 0; j < 3; j++) {
- if (((i = nface.getNeighbor(j)) != EMPTY) &&
- (faceNodes[i].notAccessed())) {
- if ((x == EMPTY) || (x > numNhbrs[i])) x = numNhbrs[i];
- }
- }
- return x;
- }
-
- /**
- * generates hamiltonian strips from the derived binary spanning tree
- * using the path peeling algorithm to peel off any node wiht double
- * children in a bottom up fashion. Returns a Vector of strips. Also
- * return the number of strips and patches in the numStrips and
- * numPatches "pointers"
- */
- ArrayList hamilton(Node[] sTree, int[] numStrips, int[] numPatches) {
- // the number of nodes in the tree
- int numNodes = sTree.length;
- // number of strips
- int ns = 0;
- // number of patches
- int np = 0;
- // some tree node variables
- Node node, pnode, cnode;
- // the Vector of strips
- ArrayList strips = new ArrayList();
- // the current strip
- ArrayList currStrip;
-
- // the tree nodes are visited in such a bottom-up fashion that
- // any node is visited prior to its parent
- for (int i = numNodes - 1; i >= 0; i--) {
- cnode = sTree[i];
-
- // if cnode is the root of a tree create a strip
- if (cnode.isRoot()) {
- // each patch is a single tree
- np++;
- // create a new strip
- currStrip = new ArrayList();
- // insert the current node into the list
- currStrip.add(0, cnode.face);
-
- // add the left "wing" of the parent node to the strip
- node = cnode.left;
- while (node != null) {
- currStrip.add(0, node.face);
- node = node.left;
- }
-
- // add the right "wing" of the parent node to the strip
- node = cnode.right;
- while (node != null) {
- currStrip.add(currStrip.size(), node.face);
- node = node.left;
- }
-
- // increase the number of strips
- ns++;
- // add the strip to the Vector
- strips.add(currStrip);
- }
-
- // if the number of children of this node is 2, create a strip
- else if (cnode.numChildren == 2) {
- // if the root has a single child with double children, it
- // could be left over as a singleton. However, the following
- // rearrangement reduces the chances
- pnode = cnode.parent;
- if (pnode.isRoot() && (pnode.numChildren == 1)) {
- pnode = cnode.right;
- if (pnode.left != null) cnode = pnode;
- else cnode = cnode.left;
- }
-
- // handle non-root case
-
- // remove the node
- cnode.remove();
-
- // create a new strip
- currStrip = new ArrayList();
- // insert the current node into the list
- currStrip.add(0, cnode.face);
-
- // add the left "wing" of cnode to the list
- node = cnode.left;
- while (node != null) {
- currStrip.add(0, node.face);
- node = node.left;
- }
-
- // add the right "wing" of cnode to the list
- node = cnode.right;
- while (node != null) {
- currStrip.add(currStrip.size(), node.face);
- node = node.left;
- }
-
- // increase the number of strips
- ns++;
- // add the strip to the Vector
- strips.add(currStrip);
- }
- }
-
- // put the ns and np in the "pointers to return
- numStrips[0] = ns;
- numPatches[0] = np;
-
- // return the strips
- return strips;
- }
-
- /**
- * creates the triangle strips
- */
- ArrayList stripe(ArrayList strips) {
- int numStrips = strips.size(); // the number of strips
- int count; // where we are in the hamiltonian
- Face face; // the face we are adding to the stream
- Face prev; // the previous face added to the stream
- boolean done; // whether we are done with the current strip
- boolean cont; // whether we should continue the current stream
- ArrayList currStrip; // the current hamiltonian
- Istream currStream; // the stream we are building
- ArrayList istreams = new ArrayList(); // the istreams to return
- boolean ccw = true;; // counter-clockwise
- int share; // the shared edge
- Vertex[] buf = new Vertex[4]; // a vertex array to start the stream
-
- // create streams for each hamiltonian
- for (int i = 0; i < numStrips; i++) {
- currStrip = (ArrayList)strips.get(i);
- count = 0;
- done = false;
- face = getNextFace(currStrip, count++);
-
- // while we are not done with the current hamiltonian
- while (!done) {
- cont = true;
-
- // if the current face is the only one left in the current
- // hamiltonian
- if (stripDone(currStrip, count)) {
- // create a new istream with the current face
- currStream = new Istream(face.verts, 3, false);
- // set the head of the strip to this face
- currStream.head = face.key;
- done = true;
- // since we are done with the strip, set the tail to this
- // face
- currStream.tail = face.key;
- }
-
- else {
- prev = face;
- face = getNextFace(currStrip, count++);
-
- // put the prev vertices in the correct order
- // to add the next tri on
- share = prev.findSharedEdge(face.key);
- buf[0] = prev.verts[share];
- buf[1] = prev.verts[(share+1)%3];
- buf[2] = prev.verts[(share+2)%3];
-
- // find the fourth vertex
- if (CHECK_ORIENT) {
- // check for clockwise orientation
- if (checkOrientCWSeq(buf[2], buf[1], face)) {
- share = face.findSharedEdge(prev.key);
- buf[3] = face.verts[share];
- currStream = new Istream(buf, 4, false);
- // set the head of this strip to the prev face
- currStream.head = prev.key;
- // if this was the last tri in the strip, then
- // we are done
- if (stripDone(currStrip, count)) {
- done = true;
- // set the tail for the strip to current face
- currStream.tail = face.key;
- }
- }
- else {
- cont = false;
- currStream = new Istream(buf, 3, false);
- // set the head to the prev face
- currStream.head = prev.key;
- // since we are not continuing, set
- // the tail to prev also
- currStream.tail = prev.key;
- }
-
- // orientation starts counter-clockwise for 3rd face
- ccw = true;
- }
- else {
- share = face.findSharedEdge(prev.key);
- buf[3] = face.verts[share];
- currStream = new Istream(buf, 4, false);
- // set the head of this strip to the prev face
- currStream.head = prev.key;
- // if this was the last tri in the strip, then
- // we are done
- if (stripDone(currStrip, count)) {
- done = true;
- // set the tail for the strip to current face
- currStream.tail = face.key;
- }
- }
-
- // while continue and the strip isn't finished
- // add more faces to the stream
- while (cont && !stripDone(currStrip, count)) {
- prev = face;
- face = getNextFace(currStrip, count++);
- share = face.findSharedEdge(prev.key);
-
- // if we can add the face without adding any
- // zero area triangles
- if (seq(currStream, face, share)) {
- if (CHECK_ORIENT) {
- // if we can add the next face with the correct
- // orientation
- if (orientSeq(ccw, currStream, face)) {
- // append the vertex opposite the
- //shared edge
- currStream.append(face.verts[share]);
- // next face must have opposite orientation
- ccw = (!ccw);
- // if this was the last tri in the
- //strip, then we are done
- if (stripDone(currStrip, count)) {
- done = true;
- // since we are done with this strip,
- // set the tail to the current face
- currStream.tail = face.key;
- }
- }
- // if we cannot add the face with the correct
- // orientation, do not continue with this
- // stream
- else {
- cont = false;
- // since we cannot continue with this strip
- // set the tail to prev
- currStream.tail = prev.key;
- }
- }
- else {
- // append the vertex opposite the
- //shared edge
- currStream.append(face.verts[share]);
- // if this was the last tri in the
- //strip, then we are done
- if (stripDone(currStrip, count)) {
- done = true;
- // since we are done with this strip,
- // set the tail to the current face
- currStream.tail = face.key;
- }
- }
- }
-
- // need zero area tris to add continue the strip
- else {
- if (CHECK_ORIENT) {
- // check the orientation for adding a zero
- // area tri and this face
- if (orientZAT(ccw, currStream, face)) {
- // swap the end of the current stream to
- // add a zero area triangle
- currStream.swapEnd();
- // append the vertex opposite the
- // shared edge
- currStream.append(face.verts[share]);
- // if this was the last tri in the
- // strip then we are done
- if (stripDone(currStrip, count)) {
- done = true;
- // set the tail because we are done
- currStream.tail = face.key;
- }
- }
- // if we cannot add the face with the correct
- // orientation, do not continue with this
- // stream
- else {
- cont = false;
- // since we cannot continue with this face,
- // set the tail to the prev face
- currStream.tail = prev.key;
- }
- }
- else {
- // swap the end of the current stream to
- // add a zero area triangle
- currStream.swapEnd();
- // append the vertex opposite the
- // shared edge
- currStream.append(face.verts[share]);
- // if this was the last tri in the
- // strip then we are done
- if (stripDone(currStrip, count)) {
- done = true;
- // set the tail because we are done
- currStream.tail = face.key;
- }
- }
- }
- } // while (cont && !stripDone)
- } // else
-
- // add the current strip to the strips to be returned
- istreams.add(currStream);
- } // while !done
- } // for each hamiltonian
- return istreams;
- } // stripe
-
- boolean stripDone(ArrayList strip, int count) {
- if (count < strip.size()) {
- return false;
- }
- else return true;
- }
-
- boolean seq(Istream stream, Face face, int share) {
- int length = stream.length;
- Vertex v1 = face.edges[share].v1;
- Vertex v2 = face.edges[share].v2;
- Vertex last = stream.istream[length-1];
- Vertex prev = stream.istream[length-2];
- if (((v1.equals(prev)) && (v2.equals(last))) ||
- ((v1.equals(last)) && (v2.equals(prev)))) {
- return true;
- }
- else return false;
- }
-
- boolean orientSeq(boolean ccw, Istream stream, Face face) {
- int length = stream.length;
- Vertex last = stream.istream[length-1];
- Vertex prev = stream.istream[length-2];
- if ((ccw && checkOrientCCWSeq(last, prev, face)) ||
- ((!ccw) && checkOrientCWSeq(last, prev, face))) {
- return true;
- }
- else return false;
- }
-
- boolean orientZAT(boolean ccw, Istream stream, Face face) {
- int length = stream.length;
- Vertex last = stream.istream[length-1];
- Vertex swap = stream.istream[length-3];
- if ((ccw && checkOrientCWSeq(last, swap, face)) ||
- ((!ccw) && checkOrientCCWSeq(last, swap, face))) {
- return true;
- }
- else return false;
- }
-
- boolean checkOrientCWSeq(Vertex last, Vertex prev, Face face) {
- System.out.println("checkOrientCWSeq");
- System.out.println("last = " + last.index);
- System.out.println("prev = " + prev.index);
- System.out.print("face = ");
- face.printVertices();
- if (last.equals(face.verts[0])) {
- if (!prev.equals(face.verts[1])) {
- if (DEBUG) System.out.println("ORIENTATION PROBLEM!");
- return false;
- }
- }
- else if (last.equals(face.verts[1])) {
- if (!prev.equals(face.verts[2])) {
- if (DEBUG) System.out.println("ORIENTATION PROBLEM!");
- return false;
- }
- }
- else if (last.equals(face.verts[2])) {
- if (!prev.equals(face.verts[0])) {
- if (DEBUG) System.out.println("ORIENTATION PROBLEM!");
- return false;
- }
- }
- return true;
- }
-
- boolean checkOrientCCWSeq(Vertex last, Vertex prev, Face face) {
- System.out.println("checkOrientCCWSeq");
- System.out.println("last = " + last.index);
- System.out.println("prev = " + prev.index);
- System.out.print("face = ");
- face.printVertices();
- if (prev.equals(face.verts[0])) {
- if (!last.equals(face.verts[1])) {
- System.out.println("ORIENTATION PROBLEM!");
- return false;
- }
- }
- else if (prev.equals(face.verts[1])) {
- if (!last.equals(face.verts[2])) {
- System.out.println("ORIENTATION PROBLEM!");
- return false;
- }
- }
- else if (prev.equals(face.verts[2])) {
- if (!last.equals(face.verts[0])) {
- System.out.println("ORIENTATION PROBLEM!");
- return false;
- }
- }
- return true;
- }
-
- Face getNextFace(ArrayList currStrip, int index) {
- if (currStrip.size() > index) return (Face)currStrip.get(index);
- else return null;
- }
-
- /**
- * joins tristrips if their end triangles neighbor each other. The
- * priority is performed in three stages: strips are concatenated to
- * save 2, 1, or no vertices
- */
- void concatenate(ArrayList strips, Face[] faces) {
- int numFaces = faces.length;
- int[] faceTable = new int[numFaces];
- Istream strm;
-
- // initialize the face table to empty
- for (int i = 0; i < numFaces; i++) {
- faceTable[i] = EMPTY;
- }
-
- // set up the faceTable so that a face index relates to a strip
- // that owns the face as one of its end faces
- for (int i = 0; i < strips.size(); i++) {
- strm = (Istream)strips.get(i);
- faceTable[strm.head] = i;
- faceTable[strm.tail] = i;
- }
-
- if (DEBUG) {
- System.out.println("");
- System.out.println("faceTable:");
- for (int i = 0; i < faceTable.length; i++) {
- System.out.println(faceTable[i]);
- }
- System.out.println("");
- }
-
- reduceCostByTwo(strips, faces, faceTable);
- reduceCostByOne(strips, faces, faceTable);
- reduceCostByZero(strips, faces, faceTable);
- }
-
- /**
- * find all the links that reduce the cost by 2
- */
- void reduceCostByTwo(ArrayList strips, Face[] faces, int[] faceTable) {
- // System.out.println("reduceCostByTwo");
- // number of faces in the face array
- int numFaces = faces.length;
- // possible adjacent strips
- int id, id1, id2;
- // Istreams
- Istream strm, strm1;
- // the length of the Istrem
- int len, len1;
- // vertex sequences for tristrips
- Vertex[] seq, seq1;
- // a face
- Face face;
- // the list of vertices for the face
- Vertex[] verts;
- // used to syncronize the orientation
- boolean sync, sync1;
- // a swap variable
- Vertex swap;
-
- for (int i = 0; i < numFaces; i++) {
- id = faceTable[i];
- if (id != EMPTY) {
- sync = false; sync1 = false;
- strm = (Istream)strips.get(id);
- len = strm.length;
- seq = strm.istream;
- face = faces[i];
- verts = face.verts;
-
- // sequential strips
- if (!strm.fan) {
-
- // a singleton strip
- if (len == 3) {
-
- // check all three neighbors
- for (int j = 0; j < 3; j++) {
- int k = face.getNeighbor(j);
- if ((k != EMPTY) &&
- ((id1 = faceTable[k]) != EMPTY) &&
- (id1 != id)) {
- // reassign the sequence
- seq[0] = verts[j];
- seq[1] = verts[(j+1)%3];
- seq[2] = verts[(j+2)%3];
-
- // the neighboring stream
- strm1 = (Istream)strips.get(id1);
- len1 = strm1.length;
- if (k != strm1.head) {
- strm1.invert();
- // if the length is odd set sync1 to true
- if ((len1 % 2) != 0) sync1 = true;
- }
- seq1 = strm1.istream;
-
- // append a singleton strip
- if (len1 == 3) {
- // System.out.println("reduce2");
- int m = faces[k].findSharedEdge(i);
- strm.append(faces[k].verts[m]);
- strm1.length = 0;
- strm1.istream = null;
- strm.tail = k;
- faceTable[k] = id;
- i--;
- break;
- }
-
- // append a strip of length over 2
- else {
- if ((len1 == 4) &&
- (seq[1].index == seq1[0].index) &&
- (seq[2].index == seq1[2].index)) {
-
- // swap seq1[1] and seq1[2] so that
- // seq[1] == seq1[0] and
- // seq[1] == seq1[1]
- swap = seq1[1];
- seq1[1] = seq1[2];
- seq1[2] = swap;
- }
-
- // see if we can join the strips
- if ((seq[1].index == seq1[0].index) &&
- (seq[2].index == seq1[1].index)) {
- // System.out.println("reduce2");
- // add the stream in
- strm.addStream(strm1);
- faceTable[k] = EMPTY;
- faceTable[strm.tail] = id;
-
- i--;
- break;
- }
- else if (sync1) {
- strm1.invert();
- sync1 = false;
- }
- }
- }
- }
- }
-
- // not a singleton strip
-
- // can append a stream where the current face is the tail
- // or is an even length so we can invert it
- else if ((i == strm.tail) || ((len % 2) == 0)) {
- // if the current face isn't the tail, then
- // have to invert the strip
- if (i != strm.tail) {
- strm.invert();
- seq = strm.istream;
- }
-
- // System.out.println("seq.length = " + seq.length);
- // System.out.println("len = " + len);
- // System.out.print("seq = ");
- // for (int l = 0; l < seq.length; l++) {
- // if (seq[l] == null) System.out.print(" null");
- // else System.out.print(" " + seq[l].index);
- // }
- // System.out.println("");
-
- swap = seq[len - 3];
-
- // find the neighboring strip
- int m = EMPTY;
- if (verts[0].index == swap.index) m = 0;
- else if (verts[1].index == swap.index) m = 1;
- else if (verts[2].index == swap.index) m = 2;
- if (m == EMPTY) {
- if (DEBUG) System.out.println("problem finding neighbor strip");
- }
- int j = face.getNeighbor(m);
- if (j == EMPTY) id1 = j;
- else id1 = faceTable[j];
- if ((id1 != EMPTY) &&
- (((Istream)strips.get(id1)).fan !=
- strm.fan)) {
- id1 = EMPTY;
- }
-
- if ((id1 != EMPTY) && (id1 != id)) {
- strm1 = (Istream)strips.get(id1);
- len1 = strm1.length;
-
- // if the shared face isn't the head, invert
- // the stream
- if (j != strm1.head) {
- strm1.invert();
- // set the sync var if the length is odd
- if ((len1 % 2) != 0) sync1 = true;
- }
- seq1 = strm1.istream;
-
- // append a singleton strip
- if (len1 == 3) {
- // System.out.println("reduce2");
- m = faces[j].findSharedEdge(i);
- strm.append(faces[j].verts[m]);
- strm1.length = 0;
- strm1.istream = null;
- strm.tail = j;
- faceTable[i] = EMPTY;
- faceTable[j] = id;
- }
-
- // append a non-singleton strip
- else {
- if ((len1 == 4) &&
- (seq[len-2].index == seq1[0].index) &&
- (seq[len-1].index == seq1[2].index)) {
-
- // swap seq1[1] and seq1[2] so that
- // seq[len-2] == seq1[0] and
- // seq[len-1] == seq1[1]
- swap = seq1[1];
- seq1[1] = seq1[2];
- seq1[2] = swap;
- }
-
- // see if we can append the strip
- if ((seq[len-2].index == seq1[0].index) &&
- (seq[len-1].index == seq1[1].index)) {
- // System.out.println("reduce2");
- strm.addStream(strm1);
- faceTable[i] = EMPTY;
- faceTable[strm.tail] = id;
- faceTable[j] = EMPTY;
- }
- else if (sync1) strm1.invert();
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * find all links that reduce cost by 1
- */
- void reduceCostByOne(ArrayList strips, Face[] faces, int[] faceTable) {
- // System.out.println("reduceCostByOne");
- // number of faces in the face array
- int numFaces = faces.length;
- // possible adjacent strips
- int id, id1, id2;
- // Istreams
- Istream strm, strm1;
- // the length of the Istream
- int len, len1;
- // vertex sequences for tristrips
- Vertex[] seq, seq1;
- // a face
- Face face;
- // the list of vertices for the face
- Vertex[] verts;
- // used to synchronize the orientation
- boolean sync, sync1;
- // a swap variable
- Vertex swap;
-
- for (int i = 0; i < numFaces; i++) {
- id = faceTable[i];
- if ((id != EMPTY) && !((Istream)strips.get(id)).fan) {
- sync = false;
- strm = (Istream)strips.get(id);
- seq = strm.istream;
- face = faces[i];
- verts = face.verts;
- len = strm.length;
-
- // a singleton strip
- if (len == 3) {
-
- // consider the three neighboring triangles
- for (int j = 0; j < 3; j++) {
- int k = face.getNeighbor(j);
- if ((k != EMPTY) &&
- ((id1 = faceTable[k]) != EMPTY) &&
- (id1 != id) &&
- (!((Istream)strips.get(id1)).fan)) {
-
- // reassign the sequence
- seq[0] = verts[j];
- seq[1] = verts[(j+1)%3];
- seq[2] = verts[(j+2)%3];
-
- // the neighboring stream
- strm1 = (Istream)strips.get(id1);
- len1 = strm1.length;
- if (k != strm1.head) {
- strm1.invert();
- if ((len1 % 2) != 0) sync = true;
- }
- seq1 = strm1.istream;
-
- // see if we can join the strips
-
- if ((len1 == 4) &&
- (((seq[1].index == seq1[2].index) &&
- (seq[2].index == seq1[0].index)) ||
- ((seq[1].index == seq1[0].index) &&
- (seq[2].index == seq1[2].index)))) {
- swap = seq1[1];
- seq1[1] = seq1[2];
- seq1[2] = swap;
- }
-
- if ((seq[1].index == seq1[0].index) &&
- (seq[2].index == seq1[1].index)) {
- // System.out.println("reduce1");
- strm.addStream(strm1);
- faceTable[k] = EMPTY;
- faceTable[strm.tail] = id;
- i--;
- break;
- }
-
- if ((seq[1].index == seq1[1].index) &&
- (seq[2].index == seq1[0].index)) {
- // System.out.println("reduce1");
- strm.append(seq1[1]);
- strm.addStream(strm1);
- faceTable[k] = EMPTY;
- faceTable[strm.tail] = id;
- i--;
- break;
- }
-
- if ((seq[1].index == seq1[0].index) &&
- (seq[2].index == seq1[2].index)) {
- // System.out.println("reduce1");
- seq1[0] = seq1[2];
- strm.append(seq1[1]);
- strm.addStream(strm1);
- faceTable[k] = EMPTY;
- faceTable[strm.tail] = id;
- i--;
- break;
- }
-
- if (sync) {
- strm1.invert();
- sync = false;
- }
- }
- }
- }
-
- // non-singleton strip
- else if ((i == strm.tail) || ((len % 2) == 0)) {
-
- // make sure the face i ends the id-th strip
- if (i != strm.tail) {
- strm.invert();
- seq = strm.istream;
- }
-
- swap = seq[len-3];
-
- // find the neighboring strip
- int m = EMPTY;
- if (verts[0].index == swap.index) m = 0;
- else if (verts[1].index == swap.index) m = 1;
- else if (verts[2].index == swap.index) m = 2;
- if (m == EMPTY) {
- if (DEBUG) System.out.println("problem finding neighbor strip");
- }
- int j = face.getNeighbor(m);
- if (j == EMPTY) id1 = j;
- else id1 = faceTable[j];
- if ((id1 != EMPTY) &&
- (((Istream)strips.get(id1)).fan != strm.fan)) {
- id1 = EMPTY;
- }
-
- // find another neighboring strip
- swap = seq[len-2];
- m = EMPTY;
- if (verts[0].index == swap.index) m = 0;
- else if (verts[1].index == swap.index) m = 1;
- else if (verts[2].index == swap.index) m = 2;
- if (m == EMPTY) {
- if (DEBUG) System.out.println("problem finding neighbor strip.");
- }
- int k = face.getNeighbor(m);
- if (k == EMPTY) id2 = k;
- else id2 = faceTable[k];
- if ((id2 != EMPTY) &&
- (((Istream)strips.get(id2)).fan != strm.fan)) {
- id2 = EMPTY;
- }
-
- // consider strip id1
- boolean success = false;
- if ((id1 != EMPTY) && (id1 != id)) {
- strm1 = (Istream)strips.get(id1);
- len1 = strm1.length;
- if (j != strm1.head) {
- strm1.invert();
- if ((len1 % 2) != 0) sync = true;
- }
- seq1 = strm1.istream;
-
- if ((len1 == 4) &&
- (((seq[len-2].index == seq1[2].index) &&
- (seq[len-1].index == seq1[0].index)) ||
- (seq[len-2].index == seq1[0].index) &&
- (seq[len-1].index == seq1[2].index))) {
- swap = seq1[1];
- seq1[1] = seq1[2];
- seq1[2] = swap;
- }
-
- // find matches
- if ((seq[len-2].index == seq1[0].index) &&
- (seq[len-1].index == seq1[1].index)) {
- // System.out.println("reduce1");
- strm.addStream(strm1);
- faceTable[i] = EMPTY;
- faceTable[strm.tail] = id;
- faceTable[j] = EMPTY;
- success = true;
- }
-
- else if ((seq[len-2].index == seq1[1].index) &&
- (seq[len-1].index == seq1[0].index)) {
- // System.out.println("reduce1");
- strm.append(seq1[1]);
- strm.addStream(strm1);
- faceTable[i] = EMPTY;
- faceTable[strm.tail] = id;
- faceTable[j] = EMPTY;
- success = true;
- }
-
- else if ((seq[len-2].index == seq1[0].index) &&
- (seq[len-1].index == seq1[2].index)) {
- // System.out.println("reduce1");
- seq1[0] = seq1[2];
- strm.append(seq1[1]);
- strm.addStream(strm1);
- faceTable[i] = EMPTY;
- faceTable[strm.tail] = id;
- faceTable[j] = EMPTY;
- success = true;
- }
- else if (sync) {
- strm1.invert();
- sync = false;
- }
- }
-
- // now consider strip id2
- if (!success &&
- (id2 != EMPTY) && (id2 != id)) {
- strm1 = (Istream)strips.get(id2);
- len1 = strm1.length;
- if (k != strm1.head) {
- strm1.invert();
- if ((len1 % 2) != 0) sync = true;
- }
- seq1 = strm1.istream;
-
- if ((len1 == 4) &&
- (seq[len-3].index == seq1[0].index) &&
- (seq[len-1].index == seq1[2].index)) {
- swap = seq1[1];
- seq1[1] = seq1[2];
- seq1[2] = swap;
- }
-
- // find matches
-
- if ((seq[len-3].index == seq1[0].index) &&
- (seq[len-1].index == seq1[1].index)) {
- // System.out.println("reduce1");
- strm.swapEnd();
- strm.addStream(strm1);
- faceTable[i] = EMPTY;
- faceTable[strm.tail] = id;
- faceTable[k] = EMPTY;
- success = true;
- }
- if (!success && sync) strm1.invert();
- }
- }
- }
- }
- }
-
- /**
- * find all the links that reduce the cost by 0
- */
- void reduceCostByZero(ArrayList strips, Face[] faces, int[] faceTable) {
- // System.out.println("reduceCostByZero");
- // number of faces in the face array
- int numFaces = faces.length;
- // possible adjacent strips
- int id, id1, id2;
- // Istreams
- Istream strm, strm1;
- // the length of the Istream
- int len, len1;
- // vertex sequences for tristrips
- Vertex[] seq, seq1;
- // a face
- Face face;
- // the list of vertices for the face
- Vertex[] verts;
- // used to synchronize the orientation
- boolean sync, sync1;
- // a swap variable
- Vertex swap;
-
- for (int i = 0; i < numFaces; i++) {
- id = faceTable[i];
- if ((id != EMPTY) && !((Istream)strips.get(id)).fan) {
- sync = false;
- strm = (Istream)strips.get(id);
- seq = strm.istream;
- len = strm.length;
- face = faces[i];
- verts = face.verts;
-
- if (len == 3) {
- for (int j = 0; j < 3; j++) {
- int k = face.getNeighbor(j);
- if ((k != EMPTY) && ((id1 = faceTable[k]) != EMPTY) &&
- (id1 != id) &&
- !((Istream)strips.get(id1)).fan) {
- // reassign the sequence
- seq[0] = verts[j];
- seq[1] = verts[(j+1)%3];
- seq[2] = verts[(j+2)%3];
-
- // the neighboring stream
- strm1 = (Istream)strips.get(id1);
- len1 = strm1.length;
- if (k != strm1.head) {
- strm1.invert();
- if ((len1 % 2) != 0) sync = true;
- }
- seq1 = strm1.istream;
-
- // see if we can join the strips
- if ((seq[1].index == seq1[2].index) &&
- (seq[2].index == seq1[0].index)) {
- // System.out.println("reduce0");
- seq1[0] = seq1[2];
- strm.append(seq1[0]);
- strm.append(seq1[1]);
- strm.addStream(strm1);
- faceTable[k] = EMPTY;
- faceTable[strm.tail] = id;
- i--;
- break;
- }
- else if (sync) {
- strm1.invert();
- sync = false;
- }
- }
- }
- }
- else if ((i == strm.tail) || ((len % 2) == 0)) {
- if (i != strm.tail) {
- strm.invert();
- seq = strm.istream;
- }
-
- swap = seq[len-3];
-
- // find neighboring strip
- int m = EMPTY;
- if (verts[0].index == swap.index) m = 0;
- else if (verts[1].index == swap.index) m = 1;
- else if (verts[2].index == swap.index) m = 2;
- if (m == EMPTY) {
- if (DEBUG) System.out.println("problem finding neighbor strip");
- }
- int j = face.getNeighbor(m);
- if (j == EMPTY) id1 = j;
- else id1 = faceTable[j];
- if ((id1 != EMPTY) &&
- (((Istream)strips.get(id1)).fan != strm.fan)) {
- id1 = EMPTY;
- }
-
- // find another neighboring strip
- swap = seq[len-2];
- m = EMPTY;
- if (verts[0].index == swap.index) m = 0;
- else if (verts[1].index == swap.index) m = 1;
- else if (verts[2].index == swap.index) m = 2;
- if (m == EMPTY) {
- if (DEBUG) System.out.println("problem finding neighbor strip.");
- }
- int k = face.getNeighbor(m);
- if (k == EMPTY) id2 = k;
- else id2 = faceTable[k];
- if ((id2 != EMPTY) &&
- (((Istream)strips.get(id2)).fan != strm.fan)) {
- id2 = EMPTY;
- }
-
- // consider strip id1
- boolean success = false;
- if ((id1 != EMPTY) && (id1 != id)) {
- strm1 = (Istream)strips.get(id1);
- len1 = strm1.length;
- if (j != strm1.head) {
- strm1.invert();
- if ((len1 % 2) != 0) sync = true;
- }
- seq1 = strm1.istream;
-
- // find matches
- if ((seq[len-2].index == seq1[2].index) &&
- (seq[len-1].index == seq1[0].index)) {
- // System.out.println("reduce0");
- seq1[0] = seq1[2];
- strm.append(seq1[0]);
- strm.append(seq1[1]);
- strm.addStream(strm1);
- faceTable[i] = EMPTY;
- faceTable[strm.tail] = id;
- faceTable[j] = EMPTY;
- success = true;
- }
- else if (sync) {
- strm1.invert();
- sync = false;
- }
- }
-
- // consider strip id2
- if (!success && (id2 != EMPTY) && (id2 != id)) {
- strm1 = (Istream)strips.get(id2);
- len1 = strm1.length;
- if (k != strm1.head) {
- strm1.invert();
- if ((len1 % 2) != 0) sync = true;
- }
- seq1 = strm1.istream;
-
- if ((len1 == 4) &&
- (((seq[len-3].index == seq1[2].index) &&
- (seq[len-1].index == seq1[0].index)) ||
- ((seq[len-3].index == seq1[0].index) &&
- (seq[len-1].index == seq1[2].index)))) {
-
- swap = seq1[1];
- seq1[1] = seq1[2];
- seq1[2] = swap;
- }
-
- // find matches
- if ((seq[len-3].index == seq1[1].index) &&
- (seq[len-1].index == seq1[0].index)) {
- // System.out.println("reduce0");
- strm.swapEnd();
- strm.append(seq1[1]);
- strm.addStream(strm1);
- faceTable[i] = EMPTY;
- faceTable[strm.tail] = id;
- faceTable[k] = EMPTY;
- }
- else if ((seq[len-3].index == seq1[0].index) &&
- (seq[len-1].index == seq1[2].index)) {
- // System.out.println("reduce0");
- seq1[0] = seq1[2];
- strm.swapEnd();
- strm.append(seq1[1]);
- strm.addStream(strm1);
- faceTable[i] = EMPTY;
- faceTable[strm.tail] = id;
- faceTable[k] = EMPTY;
- }
- else if ((seq[len-3].index == seq1[0].index) &&
- (seq[len-1].index == seq1[1].index)) {
- // System.out.println("reduce0");
- strm.swapEnd();
- strm.addStream(strm1);
- faceTable[i] = EMPTY;
- faceTable[strm.tail] = id;
- faceTable[k] = EMPTY;
- }
- else if (sync) strm1.invert();
- }
- }
- }
- }
- }
-
- /**
- * puts the stripified data back into the GeometryInfo object
- */
- void putBackData(GeometryInfo gi, ArrayList strips) {
- int[] tempStripCounts = new int[strips.size()];
- int ciSize = 0;
- int stripLength;
- for (int i = 0; i < strips.size();) {
- stripLength = ((Istream)strips.get(i)).length;
- if (stripLength != 0) {
- tempStripCounts[i] = stripLength;
- ciSize += stripLength;
- i++;
- }
- else {
- strips.remove(i);
- }
- }
- if (ciSize > 3) {
- gi.setPrimitive(gi.TRIANGLE_STRIP_ARRAY);
- int[] stripCounts = new int[strips.size()];
- System.arraycopy(tempStripCounts, 0, stripCounts, 0, strips.size());
- gi.setStripCounts(stripCounts);
-
- // create one array with all the strips
- int[] coords = new int[ciSize];
-
- // create arrays for normals, textures and colors if necessary
- int[] normals = null;
- int[][] textures = null;
- int[] colors = null;
- javax.vecmath.Color3b[] stripColors = null;
- if (hasNormals) normals = new int[ciSize];
- if (hasTextures) {
- textures = new int[texSetCount][ciSize];
- }
- if (hasColors) colors = new int[ciSize];
- if (colorStrips) {
- stripColors = new javax.vecmath.Color3b[ciSize];
- colors = new int[ciSize];
- }
- int count = 0;
- Istream currStrip;
- for (int i = 0; i < strips.size(); i++) {
- currStrip = (Istream)strips.get(i);
-
- if (currStrip.length < 3) {
- throw new RuntimeException("currStrip.length = " +
- currStrip.length);
- }
-
- java.awt.Color stripColor = null;
- if (colorStrips) {
- int r = ((int)(Math.random()*1000))%255;
- int g = ((int)(Math.random()*1000))%255;
- int b = ((int)(Math.random()*1000))%255;
- stripColor = new java.awt.Color(r, g, b);
- }
-
- for (int j = 0; j < currStrip.length; j++) {
- coords[count] = currStrip.istream[j].index;
- if (hasNormals) normals[count] = currStrip.istream[j].normal;
- if (hasTextures) {
- for (int k = 0; k < texSetCount; k++) {
- textures[k][count] =
- currStrip.istream[j].texture[k];
- }
- }
- if (hasColors) colors[count] = currStrip.istream[j].color;
- if (colorStrips) stripColors[count] =
- new javax.vecmath.Color3b(stripColor);
- count++;
- }
- }
- gi.setCoordinateIndices(coords);
- if (hasNormals) gi.setNormalIndices(normals);
- if (hasTextures) {
- for (int i = 0; i < texSetCount; i++) {
- gi.setTextureCoordinateIndices(i, textures[i]);
- }
- }
- if (hasColors) gi.setColorIndices(colors);
- if (colorStrips) {
- gi.setColors(stripColors);
- colors = gi.getListIndices(stripColors);
- gi.setColorIndices(colors);
- }
- }
- }
-
- /**
- * Stores the infomration about a vertex
- */
- class Vertex {
-
- int index;
- int normal = EMPTY;
- int numTexSets = 0;
- int[] texture = null;
- int color = EMPTY;
-
- Vertex(int vertIndex) {
- this(vertIndex, EMPTY, 0, null, EMPTY);
- }
-
- Vertex(int vertIndex, int vertNormal,
- int vertNumTexSets, int[] vertTexture, int vertColor) {
- index = vertIndex;
- normal = vertNormal;
- numTexSets = vertNumTexSets;
- if (numTexSets > 0) {
- texture = new int[numTexSets];
- System.arraycopy(vertTexture, 0, texture, 0, numTexSets);
- }
- color = vertColor;
- }
-
- boolean equals(Vertex v) {
- for (int i = 0; i < numTexSets; i++) {
- if (texture[i] != v.texture[i]) {
- return false;
- }
- }
- return ((v.index == index) &&
- (v.normal == normal) &&
- (v.color == color));
- }
-
- // will this yield same results as c code ???
- boolean lessThan(Vertex v) {
- if (index < v.index) return true;
- if (index > v.index) return false;
- if (normal < v.normal) return true;
- if (normal > v.normal) return false;
- for (int i = 0; i < numTexSets; i++) {
- if (texture[i] < v.texture[i]) return true;
- if (texture[i] > v.texture[i]) return false;
- }
- if (color < v.color) return true;
- if (color > v.color) return false;
- return false;
- }
- }
-
- /**
- * Stores the information about an edge of a triangle
- */
- class Edge {
-
- Vertex v1, v2;
- int face;
-
- Edge(Vertex vertex1, Vertex vertex2, int faceIndex) {
- face = faceIndex;
-
- // this could be causing wrapping problem
- if (vertex1.lessThan(vertex2)) {
- v1 = vertex1;
- v2 = vertex2;
- } else {
- v1 = vertex2;
- v2 = vertex1;
- }
- }
-
- /**
- * Determine whether the edges have the same vertices
- */
- boolean equals(Edge edge) {
- return ((v1.equals(edge.v1)) && (v2.equals(edge.v2)));
-
- }
-
- /**
- * Used to sort the edges. If this is less than the edge parameter,
- * return true. First check if vertex1 is less than vertex1 of the
- * edge provided. If so, return true. If the first vertices are equal
- * then check vertex2.
- */
- boolean lessThan(Edge edge) {
- if (v1.lessThan(edge.v1)) return true;
- else if (v1.equals(edge.v1)) return (v2.lessThan(edge.v2));
- else return false;
- }
- }
-
- /**
- * Stores the information about the face of a triangle
- */
- class Face {
- int key;
- int numNhbrs = 0;
- Vertex[] verts = null;
- // edges are kept in order s.t. the ith edge is the opposite
- // edge of the ith vertex
- Edge[] edges = null;
-
- /**
- * Creates a new Face with the three given vertices
- */
- Face(int index, Vertex v1, Vertex v2, Vertex v3) {
- key = index;
-
- verts = new Vertex[3];
- verts[0] = v1;
- verts[1] = v2;
- verts[2] = v3;
-
- edges = new Edge[3];
- edges[0] = null;
- edges[1] = null;
- edges[2] = null;
- numNhbrs = 3;
- }
-
- /**
- * returns the index of the face that neighbors the edge supplied
- * by the parameter
- */
- int getNeighbor(int edge) {
- return edges[edge].face;
- }
-
- /**
- * returns the index of the edge that is shared by the triangle
- * specified by the key parameter
- */
- int findSharedEdge(int key) {
- if (edges[0].face == key) return 0;
- else if (edges[1].face == key) return 1;
- else if (edges[2].face == key) return 2;
- else return -1; /* error */
- }
-
- int getEdgeIndex(Edge edge) {
- if (edges[0].equals(edge)) return 0;
- else if (edges[1].equals(edge)) return 1;
- else return 2;
- }
-
- void counterEdgeDel(Edge edge) {
- if (DEBUG) {
- System.out.println("counterEdgeDel");
- }
- if ((edges[0]).equals(edge)) {
- edges[0].face = EMPTY;
- numNhbrs--;
- }
- else if ((edges[1]).equals(edge)) {
- edges[1].face = EMPTY;
- numNhbrs--;
- }
- else if ((edges[2]).equals(edge)) {
- edges[2].face = EMPTY;
- numNhbrs--;
- }
- else {
- if (DEBUG) {
- System.out.println("error in counterEdgeDel");
- }
- }
- }
-
- void printAdjacency() {
- System.out.println("Face " + key + ": ");
- System.out.println("\t numNhbrs = " + numNhbrs);
- System.out.println("\t edge 0: Face " + edges[0].face);
- System.out.println("\t edge 1: Face " + edges[1].face);
- System.out.println("\t edge 2: Face " + edges[2].face);
- }
-
- void printVertices() {
- System.out.println("Face " + key + ": (" + verts[0].index + ", " +
- verts[1].index + ", " + verts[2].index + ")");
- }
- }
-
- /**
- * stores the information for a face node
- */
- class Node {
- Face face; // the data: the face
- Node parent; // the parent node
- Node left; // the left child
- Node right; // the right child
- int depth; // the topological distance of the node from the root
- int numChildren; // the number of children
- int attrib; // characteristic of the node eg. color
-
- // the attributes - 3 states for the Node
- static final int WHITE = 0; // not being accessed yet
- static final int GREY = 1; // being accessed but not done yet
- static final int BLACK = 2; // done
-
- Node(Face f) {
- face = f;
- }
-
- /**
- * inserts this node below the parent supplied.
- */
- void insert(Node p) {
- parent = p;
- depth = p.depth + 1;
- attrib = GREY;
-
- if (parent.left == null) parent.left = this;
- else parent.right = this;
- (parent.numChildren)++;
- }
-
- /**
- * remove this node from its parent
- */
- void remove() {
- if (parent != null) {
- if (parent.left == this) {
- parent.left = parent.right;
- parent.right = null;
- }
- else {
- parent.right = null;
- }
- (parent.numChildren)--;
- }
- }
-
-
- /**
- * sets the depth to 0 and the attrib to GREY
- */
- void setRoot() {
- depth = 0;
- attrib = GREY;
- }
-
- /**
- * returns true if the attrib is WHITE
- */
- boolean notAccessed() {
- return (attrib == WHITE);
- }
-
- /**
- * sets the color to BLACK
- */
- void processed() {
- attrib = BLACK;
- }
-
- /**
- * a node is the root if it doesn't have a parent
- */
- boolean isRoot() {
- return (parent == null);
- }
-
- /**
- * prints the information in this Node
- */
- void print() {
- System.out.println(this);
- System.out.println("Node depth: " + depth);
- face.printVertices();
- System.out.print("parent: ");
- if (parent != null) parent.face.printVertices();
- else System.out.println("null");
- System.out.print("left: ");
- if (left != null) left.face.printVertices();
- else System.out.println("null");
- System.out.print("right: ");
- if (right != null) right.face.printVertices();
- else System.out.println("null");
- System.out.println("attrib: " + attrib);
- System.out.println("");
- }
- }
-
- /**
- * sorts the Nodes by depth
- */
- class SortedList {
-
- ArrayList list;
-
- /**
- * create a new SortedList
- */
- SortedList() {
- list = new ArrayList();
- }
-
- /**
- * insert into the list sorted by depth. start looking at start
- * to save some time. Returns the index of the next item of the
- * inserted element
- */
- int sortedInsert(Node data, int start) {
- // adjust start to where insert sorted
- while ((start < list.size()) &&
- (((Node)list.get(start)).depth <= data.depth)) {
- start++;
- }
-
- // insert at start index
- list.add(start, data);
-
- // return start+1 -- the index of the next element
- return (start+1);
- }
-
- /**
- * remove and return 1st element
- */
- Node pop() {
- if (!list.isEmpty()) return (Node)list.remove(0);
- else return null;
- }
- }
-
- class Istream {
-
- // fan encoding
- boolean fan = false;
- // length of the strip
- int length = 0;
- // array that specifies triangle strip
- Vertex[] istream;
- // indices of the head and tail vertices
- int head, tail;
-
- /**
- * creates a new Istream to store the triangle strip
- */
- Istream(Vertex[] list, int size, boolean isFan) {
- if (size == 0) throw new RuntimeException("size is 0");
- fan = isFan;
- length = size;
- istream = new Vertex[length];
- int i;
- System.arraycopy(list, 0, istream, 0, length);
- }
-
- /**
- * adds a new vertex to the end of the stream
- * makes the int array bigger, if necessary
- */
- void append(Vertex vertex) {
- growArray();
- // add in new vertex
- istream[length] = vertex;
- length++;
- }
-
- /**
- * turns the encoding (..., -3, -2, -1) into (.... -3, -2, -3, -1)
- * so that zero-area triangle (-3, -2. -3) is added
- */
- void swapEnd() {
- growArray();
- istream[length] = istream[length-1];
- istream[length-1] = istream[length-3];
- length++;
- }
-
- /**
- * makes the array bigger, if necessary
- */
- void growArray() {
- if (length >= istream.length) {
- Vertex[] old = istream;
- // for now add enough space to add three more vertices
- // may change this later
- istream = new Vertex[length + 3];
- System.arraycopy(old, 0, istream, 0, length);
- }
- }
-
- /**
- * inverts the istream
- */
- void invert() {
- Vertex[] tmp = new Vertex[istream.length];
- // reverse the stream
- for (int i = 0; i < length; i++) {
- tmp[i] = istream[length - i - 1];
- }
- // copy it back
- System.arraycopy(tmp, 0, istream, 0, istream.length);
- tmp = null;
- // swap the head and the tail
- int swap = head;
- head = tail;
- tail = swap;
- }
-
- /**
- * concats two streams into one big stream
- */
- void addStream(Istream strm) {
- // System.out.println("addStream");
- int strmLen = strm.length;
- int size = strmLen + length - 2;
-
- // make the istream bigger
- if (size >= istream.length) {
- Vertex[] old = istream;
- istream = new Vertex[size];
- System.arraycopy(old, 0, istream, 0, length);
- }
-
- // add the strm to istream
- System.arraycopy(strm.istream, 2, istream, length, strmLen-2);
-
- tail = strm.tail;
- length = size;
- strm.length = 0;
- strm.istream = null;
- }
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/StripifierStats.java b/src/classes/share/com/sun/j3d/utils/geometry/StripifierStats.java
deleted file mode 100644
index 5431473..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/StripifierStats.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-import java.util.ArrayList;
-
-/**
- * This class collects statistics on the Stripifier. The statistics
- * are cumulative over all calls to stripify() until clearData() is called.
- *
- * @since Java 3D 1.2.1
- */
-
-public class StripifierStats {
-
- int numStrips = 0;
- int numVerts = 0;
- int minStripLen = 10000;
- int maxStripLen = 0;
- int totalTris = 0;
- int numFaces = 0;
- long time = 0;
- int[] counts = new int[14];
-
- boolean noData = true;
-
- /**
- * Returns the number of triangles in the original, un-stripified data.
- * @since Java 3D 1.2.1
- */
- public int getNumOrigTris() {
- return numFaces;
- }
-
- /**
- * Returns the number of vertices in the original, un-stripified data
- * @since Java 3D 1.2.1
- */
- public int getNumOrigVerts() {
- return (numFaces * 3);
- }
-
- /**
- * Returns the number of strips created by the stripifier.
- * @since Java 3D 1.2.1
- */
- public int getNumStrips() {
- return numStrips;
- }
-
- /**
- * Returns the number of vertices in the stripified data.
- * @since Java 3D 1.2.1
- */
- public int getNumVerts() {
- return numVerts;
- }
-
- /**
- * Returns the number of triangles in the stripified data.
- * @since Java 3D 1.2.1
- */
- public int getTotalTris() {
- return totalTris;
- }
-
- /**
- * Returns the length in triangles of the shortest strip
- * created by the stripifier.
- * @since Java 3D 1.2.1
- */
- public int getMinStripLength() {
- return minStripLen;
- }
-
- /**
- * Returns the length in triangles of the longest strip
- * created by the stripifier.
- * @since Java 3D 1.2.1
- */
- public int getMaxStripLength() {
- return maxStripLen;
- }
-
- /**
- * Return the average length of the strips created by the stripifier
- * @since Java 3D 1.2.1
- */
- public double getAvgStripLength() {
- return ((double)totalTris/(double)numStrips);
- }
-
- /**
- * Returns the average number of vertices per triangle in the stripified
- * data
- * @since Java 3D 1.2.1
- */
- public double getAvgNumVertsPerTri() {
- return ((double)numVerts/(double)totalTris);
- }
-
- /**
- * Returns the total time spent in the stripify() method
- * @since Java 3D 1.2.1
- */
- public long getTotalTime() {
- return time;
- }
-
- /**
- * Returns an array of length 14 that contains the number of strips of
- * a given length created by the stripifier. Spots 0-8 of the array
- * represent lengths 1-9, 9 is lengths 10-19, 10 is lengths 20-49,
- * 11 is lengths 50-99, 12 is lengths 100-999 and 13 is lengths 1000
- * or more.
- * @since Java 3D 1.2.1
- */
- public int[] getStripLengthCounts() {
- return counts;
- }
-
- /**
- * Returns a formated String that can be used to print out
- * the Stripifier stats.
- * @since Java 3D 1.2.1
- */
-
- @Override
- public String toString() {
- StringBuffer str = new StringBuffer(
- "num orig tris: " + numFaces + "\n" +
- "num orig vertices: " + (numFaces*3) + "\n" +
- "number of strips: " + numStrips + "\n" +
- "number of vertices: " + numVerts + "\n" +
- "total tris: " + totalTris + "\n" +
- "min strip length: " + minStripLen + "\n" +
- "max strip length: " + maxStripLen + "\n" +
- "avg strip length: " + ((double)totalTris/
- (double)numStrips) + "\n" +
- "avg num verts/tri: " + ((double)numVerts/
- (double)totalTris) + "\n" +
- "total time: " + time + "\n" +
- "strip length distribution:\n");
- for (int i = 0; i < 9; i++){
- str.append(" " + (i+1) + "=" + counts[i]);
- }
- str.append(" 10-19=" + counts[9]);
- str.append(" 20-49=" + counts[10]);
- str.append(" 50-99=" + counts[11]);
- str.append(" 100-999=" + counts[12]);
- str.append(" 1000 or more=" + counts[13] + "\n");
-
- return str.toString();
- }
-
- /**
- * Clears the statistical data
- */
- public void clearData() {
- noData = true;
-
- numStrips = 0;
- numVerts = 0;
- minStripLen = 10000;
- maxStripLen = 0;
- totalTris = 0;
- numFaces = 0;
- time = 0;
- counts = new int[14];
- }
-
- void updateInfo(long ntime, ArrayList strips,
- int nNumFaces) {
- noData = false;
-
- time += ntime;
- numStrips += strips.size();
- int nv = 0;
- int mnsl = 10000;
- int mxsl = 0;
- int tt = 0;
- for (int i = 0; i < strips.size(); i++) {
- Stripifier.Istream strm = (Stripifier.Istream)strips.get(i);
- int len = strm.length;
- int trilen = (len-2);
- nv += len;
- if (trilen < mnsl) mnsl = trilen;
- if (trilen > mxsl) mxsl = trilen;
- tt += trilen;
-
- // add to counts
- // how many strips are length 1-9
- if (trilen <= 9) counts[trilen-1] += 1;
- // how many strips are length 10-19
- else if (trilen < 20) counts[9] += 1;
- // how many strips are length 20-49
- else if (trilen < 50) counts[10] += 1;
- // how many strips are length 50-99
- else if (trilen < 100) counts[11] += 1;
- // how many strips are length 100-1000
- else if (trilen < 1000) counts[12] += 1;
- // how many strips are length > 1000
- else counts[13] += 1;
- }
- numVerts += nv;
- if (mnsl < minStripLen) minStripLen = mnsl;
- if (mxsl > maxStripLen) maxStripLen = mxsl;
- totalTris += tt;
- numFaces += nNumFaces;
- }
-
- void updateInfo(long ntime, int scLen, int sc[],
- int nNumFaces) {
-
- noData = false;
-
- time += ntime;
- numStrips += scLen;
- int nv = 0;
- int mnsl = 10000;
- int mxsl = 0;
- int tt = 0;
- for (int i = 0; i < scLen; i++) {
- int len = sc[i];
- int trilen = (len-2);
- numVerts += len;
- if (trilen < mnsl) mnsl = trilen;
- if (trilen > mxsl) mxsl = trilen;
- totalTris += trilen;
-
- // add to counts
- // how many strips are length 1-9
- if (trilen <= 9) counts[trilen-1] += 1;
- // how many strips are length 10-19
- else if (trilen < 20) counts[9] += 1;
- // how many strips are length 20-49
- else if (trilen < 50) counts[10] += 1;
- // how many strips are length 50-99
- else if (trilen < 100) counts[11] += 1;
- // how many strips are length 100-1000
- else if (trilen < 1000) counts[12] += 1;
- // how many strips are length > 1000
- else counts[13] += 1;
- }
- numVerts += nv;
- if (mnsl < minStripLen) minStripLen = mnsl;
- if (mxsl > maxStripLen) maxStripLen = mxsl;
- totalTris += tt;
- numFaces += nNumFaces;
- }
-
- // void printInfo() {
- // System.out.println("num orig tris: " + numFaces);
- // System.out.println("num orig vertices: " + (numFaces*3));
- // System.out.println("number of strips: " + numStrips);
- // System.out.println("number of vertices: " + numVerts);
- // System.out.println("total tris: " + totalTris);
- // System.out.println("min strip length: " + minStripLen);
- // System.out.println("max strip length: " + maxStripLen);
- // System.out.println("avg strip length: " + ((double)totalTris/
- // (double)numStrips));
- // System.out.println("avg num verts/tri: " + ((double)numVerts/
- // (double)totalTris));
- // System.out.println("total time: " + time);
- // System.out.println("strip length distribution:");
- // for (int i = 0; i < 9; i++){
- // System.out.print(" " + (i+1) + "=" + counts[i]);
- // }
- // System.out.print(" 10-19=" + counts[9]);
- // System.out.print(" 20-49=" + counts[10]);
- // System.out.print(" 50-99=" + counts[11]);
- // System.out.print(" 100-999=" + counts[12]);
- // System.out.println(" 1000 or more=" + counts[13]);
-
- // // reset info after printing data
- // numStrips = 0;
- // numVerts = 0;
- // minStripLen = 10000;
- // maxStripLen = 0;
- // totalTris = 0;
- // numFaces = 0;
- // time = 0;
- // counts = new int[14];
- // }
-
- StripifierStats() {
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Text2D.java b/src/classes/share/com/sun/j3d/utils/geometry/Text2D.java
deleted file mode 100644
index 77bb632..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Text2D.java
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Graphics2D;
-import java.awt.Image;
-import java.awt.Toolkit;
-import java.awt.image.BufferedImage;
-import java.util.Hashtable;
-
-import javax.media.j3d.Appearance;
-import javax.media.j3d.ImageComponent;
-import javax.media.j3d.ImageComponent2D;
-import javax.media.j3d.Material;
-import javax.media.j3d.Node;
-import javax.media.j3d.QuadArray;
-import javax.media.j3d.Shape3D;
-import javax.media.j3d.Texture;
-import javax.media.j3d.Texture2D;
-import javax.media.j3d.TransparencyAttributes;
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4f;
-
-/**
- * A Text2D object is a representation of a string as a texture mapped
- * rectangle. The texture for the rectangle shows the string as rendered in
- * the specified color with a transparent background. The appearance of the
- * characters is specified using the font indicated by the font name, size
- * and style (see java.awt.Font). The approximate height of the rendered
- * string will be the font size times the rectangle scale factor, which has a
- * default value of 1/256. For example, a 12 point font will produce
- * characters that are about 12/256 = 0.047 meters tall. The lower left
- * corner of the rectangle is located at (0,0,0) with the height
- * extending along the positive y-axis and the width extending along the
- * positive x-axis.
- */
-public class Text2D extends Shape3D {
-
- // This table caches FontMetrics objects to avoid the huge cost
- // of re-retrieving metrics for a font we've already seen.
- private static Hashtable metricsTable = new Hashtable();
- private float rectangleScaleFactor = 1f/256f;
-
- private boolean enableTextureWrite = false;
-
- private Color3f color = new Color3f();
- private String fontName;
- private int fontSize, fontStyle;
- private String text;
-
- // max texture dimension, as some font size can be greater than
- // video card max texture size. 2048 is a conservative value.
- private int MAX_TEXTURE_DIM = 2048;
-
- // vWidth is the virtual width texture. Value set by setupImage()
- private int vWidth;
- // vHeight is the virtual height texture. Value set by setupImage()
- private int vHeight;
-
-
- /**
- * Creates a Shape3D object which holds a
- * rectangle that is texture-mapped with an image that has
- * the specified text written with the specified font
- * parameters.
- *
- * @param text The string to be written into the texture map.
- * @param color The color of the text string.
- * @param fontName The name of the Java font to be used for
- * the text string.
- * @param fontSize The size of the Java font to be used.
- * @param fontStyle The style of the Java font to be used.
- */
- public Text2D(String text, Color3f color, String fontName,
- int fontSize, int fontStyle) {
-
- this.color.set(color);
- this.fontName = fontName;
- this.fontSize = fontSize;
- this.fontStyle = fontStyle;
- this.text = text;
- setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
- setCapability(Shape3D.ALLOW_APPEARANCE_READ);
- setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
-
- updateText2D(text, color, fontName, fontSize, fontStyle);
- }
-
- // issue 655
- private Text2D() {
-
- setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
- setCapability(Shape3D.ALLOW_APPEARANCE_READ);
- setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
- }
-
- // issue 655
- @Override
- public Node cloneNode(boolean forceDuplicate) {
- Text2D t2d = new Text2D();
-
- t2d.color.set(color);
- t2d.fontName = fontName;
- t2d.fontSize = fontSize;
- t2d.fontStyle = fontStyle;
- t2d.text = text;
-
- t2d.duplicateNode(this, forceDuplicate);
- return t2d;
- }
-
- /*
- * Changes text of this Text2D to 'text'. All other
- * parameters (color, fontName, fontSize, fontStyle
- * remain the same.
- * @param text The string to be set.
- */
- public void setString(String text){
- this.text = text;
-
- Texture tex = getAppearance().getTexture();
-
- // mcneillk: JAVA3D-657
- if (tex == null) {
- tex = getAppearance().getTextureUnitState(0).getTexture();
- }
-
- int width = tex.getWidth();
- int height = tex.getHeight();
- int oldVW = vWidth;
- int oldVH = vHeight;
-
- ImageComponent imageComponent = setupImage(text, color, fontName,
- fontSize, fontStyle);
- if ((imageComponent.getWidth() == width) &&
- (imageComponent.getHeight() == height)) {
- tex.setImage(0, imageComponent);
- } else {
- Texture2D newTex = setupTexture(imageComponent);
- // Copy texture attributes except those related to
- // mipmap since Texture only set base imageComponent.
-
- newTex.setBoundaryModeS(tex.getBoundaryModeS());
- newTex.setBoundaryModeT(tex.getBoundaryModeT());
- newTex.setMinFilter(tex.getMinFilter());
- newTex.setMagFilter(tex.getMagFilter());
- newTex.setEnable(tex.getEnable());
- newTex.setAnisotropicFilterMode(tex.getAnisotropicFilterMode());
- newTex.setAnisotropicFilterDegree(tex.getAnisotropicFilterDegree());
- int pcount = tex.getFilter4FuncPointsCount();
- if (pcount > 0) {
- float weights[] = new float[pcount];
- tex.getFilter4Func(weights);
- newTex.setFilter4Func(weights);
- }
- Color4f c = new Color4f();
- tex.getBoundaryColor(c);
- newTex.setBoundaryColor(c);
- newTex.setUserData(tex.getUserData());
-
- // mcneillk: JAVA3D-657
- if (getAppearance().getTexture() != null) {
- getAppearance().setTexture(newTex);
- } else {
- getAppearance().getTextureUnitState(0).setTexture(newTex);
- }
- }
- // Does the new text requires a new geometry ?
- if ( oldVH != vHeight || oldVW != vWidth){
- QuadArray rect = setupGeometry(vWidth, vHeight);
- setGeometry(rect);
- }
- }
-
- private void updateText2D(String text, Color3f color, String fontName,
- int fontSize, int fontStyle) {
- ImageComponent imageComponent = setupImage(text, color, fontName,
- fontSize, fontStyle);
-
- Texture2D t2d = setupTexture(imageComponent);
-
- QuadArray rect = setupGeometry(vWidth, vHeight);
- setGeometry(rect);
-
- Appearance appearance = setupAppearance(t2d);
- setAppearance(appearance);
- }
-
-
- /**
- * Sets the scale factor used in converting the image width/height
- * to width/height values in 3D.
- *
- * @param newScaleFactor The new scale factor.
- */
- public void setRectangleScaleFactor(float newScaleFactor) {
- rectangleScaleFactor = newScaleFactor;
- updateText2D(text, color, fontName, fontSize, fontStyle);
- }
-
- /**
- * Gets the current scale factor being used in converting the image
- * width/height to width/height values in 3D.
- *
- * @return The current scale factor.
- */
- public float getRectangleScaleFactor() {
- return rectangleScaleFactor;
- }
-
- /**
- * Create the ImageComponent and Texture object.
- */
- private Texture2D setupTexture(ImageComponent imageComponent) {
- Texture2D t2d = new Texture2D(Texture2D.BASE_LEVEL,
- Texture.RGBA,
- imageComponent.getWidth(),
- imageComponent.getHeight());
- t2d.setMinFilter(Texture2D.BASE_LEVEL_LINEAR);
- t2d.setMagFilter(Texture2D.BASE_LEVEL_LINEAR);
- t2d.setImage(0, imageComponent);
- t2d.setEnable(true);
- t2d.setCapability(Texture.ALLOW_IMAGE_WRITE);
- t2d.setCapability(Texture.ALLOW_SIZE_READ);
- t2d.setCapability(Texture.ALLOW_ENABLE_READ);
- t2d.setCapability(Texture.ALLOW_BOUNDARY_MODE_READ);
- t2d.setCapability(Texture.ALLOW_FILTER_READ);
- t2d.setCapability(Texture.ALLOW_BOUNDARY_COLOR_READ);
- t2d.setCapability(Texture.ALLOW_ANISOTROPIC_FILTER_READ);
- t2d.setCapability(Texture.ALLOW_FILTER4_READ);
- return t2d;
- }
-
- /**
- * Creates a ImageComponent2D of the correct dimensions for the
- * given font attributes. Draw the given text into the image in
- * the given color. The background of the image is transparent
- * (alpha = 0).
- */
- private ImageComponent setupImage(String text, Color3f color,
- String fontName,
- int fontSize, int fontStyle) {
- Toolkit toolkit = Toolkit.getDefaultToolkit();
- Font font = new java.awt.Font(fontName, fontStyle, fontSize);
-
- FontMetrics metrics;
- if ((metrics = (FontMetrics)metricsTable.get(font)) == null) {
- metrics = toolkit.getFontMetrics(font);
- metricsTable.put(font, metrics);
- }
- int width = metrics.stringWidth(text);
- int descent = metrics.getMaxDescent();
- int ascent = metrics.getMaxAscent();
- int leading = metrics.getLeading();
- int height = descent + ascent;
-
- // Need to make width/height powers of 2 because of Java3d texture
- // size restrictions
- int pow = 1;
- for (int i = 1; i < 32; ++i) {
- pow *= 2;
- if (width <= pow)
- break;
- }
- width = Math.max (width, pow);
- pow = 1;
- for (int i = 1; i < 32; ++i) {
- pow *= 2;
- if (height <= pow)
- break;
- }
- height = Math.max (height, pow);
-
- // For now, jdk 1.2 only handles ARGB format, not the RGBA we want
- BufferedImage bImage = new BufferedImage(width, height,
- BufferedImage.TYPE_INT_ARGB);
- Graphics2D offscreenGraphics = bImage.createGraphics();
-
- // First, erase the background to the text panel - set alpha to 0
- Color myFill = new Color(0f, 0f, 0f, 0f);
- offscreenGraphics.setColor(myFill);
- offscreenGraphics.fillRect(0, 0, width, height);
-
- // Next, set desired text properties (font, color) and draw String
- offscreenGraphics.setFont(font);
- Color myTextColor = new Color(color.x, color.y, color.z, 1f);
- offscreenGraphics.setColor(myTextColor);
- offscreenGraphics.drawString(text, 0, height - descent);
- offscreenGraphics.dispose();
- //store virtual size
- vWidth = width;
- vHeight = height;
- // rescale down big images
- if(width > MAX_TEXTURE_DIM || height > MAX_TEXTURE_DIM){
- bImage = rescaleImage(bImage);
- }
-
- ImageComponent imageComponent =
- new ImageComponent2D(ImageComponent.FORMAT_RGBA,
- bImage);
-
- imageComponent.setCapability(ImageComponent.ALLOW_SIZE_READ);
-
- return imageComponent;
- }
- // rescale image
- private BufferedImage rescaleImage(BufferedImage bImage){
- int width = bImage.getWidth();
- int height = bImage.getHeight();
-
- float sx = (width > MAX_TEXTURE_DIM) ? (float) MAX_TEXTURE_DIM / (float)width : 1.0f;
- float sy = (height > MAX_TEXTURE_DIM)? (float) MAX_TEXTURE_DIM / (float)height : 1.0f;
-
- width = Math.round((float) width * sx);
- height = Math.round((float)height * sy);
-
- Image scaledImage = bImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
- bImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
- Graphics2D g = bImage.createGraphics();
- g.drawImage(scaledImage, 0,0, null);
- g.dispose();
-
- return bImage;
- }
-
- /**
- * Creates a rectangle of the given width and height and sets up
- * texture coordinates to map the text image onto the whole surface
- * of the rectangle (the rectangle is the same size as the text image)
- */
- private QuadArray setupGeometry(int width, int height) {
- float zPosition = 0f;
- float rectWidth = (float)width * rectangleScaleFactor;
- float rectHeight = (float)height * rectangleScaleFactor;
- float[] verts1 = {
- rectWidth, 0f, zPosition,
- rectWidth, rectHeight, zPosition,
- 0f, rectHeight, zPosition,
- 0f, 0f, zPosition
- };
- float[] texCoords = {
- 0f, -1f,
- 0f, 0f,
- (-1f), 0f,
- (-1f), -1f
- };
-
- QuadArray rect = new QuadArray(4, QuadArray.COORDINATES |
- QuadArray.TEXTURE_COORDINATE_2);
- rect.setCoordinates(0, verts1);
- rect.setTextureCoordinates(0, 0, texCoords);
-
- return rect;
- }
-
- /**
- * Creates Appearance for this Shape3D. This sets transparency
- * for the object (we want the text to be "floating" in space,
- * so only the text itself should be non-transparent. Also, the
- * appearance disables lighting for the object; the text will
- * simply be colored, not lit.
- */
- private Appearance setupAppearance(Texture2D t2d) {
- Appearance appearance = getAppearance();
-
- if (appearance == null) {
- TransparencyAttributes transp = new TransparencyAttributes();
- transp.setTransparencyMode(TransparencyAttributes.BLENDED);
- transp.setTransparency(0f);
- appearance = new Appearance();
- appearance.setTransparencyAttributes(transp);
- appearance.setTexture(t2d);
-
- Material m = new Material();
- m.setLightingEnable(false);
- appearance.setMaterial(m);
- appearance.setCapability(Appearance.ALLOW_TEXTURE_WRITE);
- appearance.setCapability(Appearance.ALLOW_TEXTURE_READ);
- appearance.setCapabilityIsFrequent(Appearance.ALLOW_TEXTURE_READ);
- }else{
- appearance.setTexture(t2d);
- }
-
- return appearance;
- }
-
- /**
- * Returns the text string
- *
- * @since Java 3D 1.2.1
- */
- public String getString() {
- return text;
- }
-
- /**
- * Returns the color of the text
- *
- * @since Java 3D 1.2.1
- */
- public Color3f getColor() {
- return color;
- }
-
- /**
- * Returns the font
- *
- * @since Java 3D 1.2.1
- */
- public String getFontName() {
- return fontName;
- }
-
- /**
- * Returns the font size
- *
- * @since Java 3D 1.2.1
- */
- public int getFontSize() {
- return fontSize;
- }
-
- /**
- * Returns the font style
- *
- * @since Java 3D 1.2.1
- */
- public int getFontStyle() {
- return fontStyle;
- }
-
-}
-
-
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Triangle.java b/src/classes/share/com/sun/j3d/utils/geometry/Triangle.java
deleted file mode 100644
index a27ea4b..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Triangle.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-class Triangle extends Object {
- int v1, v2, v3; // This store the index into the list array.
- // Not the index into vertex pool yet!
-
- Triangle(int a, int b, int c) {
- v1=a; v2=b; v3=c;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/Triangulator.java b/src/classes/share/com/sun/j3d/utils/geometry/Triangulator.java
deleted file mode 100644
index ca4801c..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/Triangulator.java
+++ /dev/null
@@ -1,1047 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-// ----------------------------------------------------------------------
-//
-// The reference to Fast Industrial Strength Triangulation (FIST) code
-// in this release by Sun Microsystems is related to Sun's rewrite of
-// an early version of FIST. FIST was originally created by Martin
-// Held and Joseph Mitchell at Stony Brook University and is
-// incorporated by Sun under an agreement with The Research Foundation
-// of SUNY (RFSUNY). The current version of FIST is available for
-// commercial use under a license agreement with RFSUNY on behalf of
-// the authors and Stony Brook University. Please contact the Office
-// of Technology Licensing at Stony Brook, phone 631-632-9009, for
-// licensing information.
-//
-// ----------------------------------------------------------------------
-
-package com.sun.j3d.utils.geometry;
-
-import java.util.Random;
-
-import javax.vecmath.Point2f;
-import javax.vecmath.Point3f;
-import javax.vecmath.Vector3f;
-
-import com.sun.j3d.internal.J3dUtilsI18N;
-
-/**
- * Triangulator is a utility for turning arbitrary polygons into triangles
- * so they can be rendered by Java 3D.
- * Polygons can be concave, nonplanar, and can contain holes.
- * @see GeometryInfo
- */
-public class Triangulator extends Object {
-
- GeometryInfo gInfo = null;
-
- int faces[] = null;
- int loops[] = null;
- int chains[] = null;
- Point2f points[] = null;
- Triangle triangles[] = null;
- ListNode list[] = null;
-
- Random randomGen = null;
-
- int numPoints = 0;
- int maxNumPoints = 0;
- int numList = 0;
- int maxNumList = 0;
- int numLoops = 0;
- int maxNumLoops = 0;
- int numTriangles = 0;
- int maxNumTriangles = 0;
-
- int numFaces = 0;
- int numTexSets = 0;
- // int maxNumFaces = 0;
-
- int firstNode = 0;
-
- int numChains = 0;
- int maxNumChains = 0;
-
- // For Clean class.
- Point2f[] pUnsorted = null;
- int maxNumPUnsorted = 0;
-
- // For NoHash class.
- boolean noHashingEdges = false;
- boolean noHashingPnts = false;
- int loopMin, loopMax;
- PntNode vtxList[] = null;
- int numVtxList = 0;
- int numReflex = 0;
- int reflexVertices;
-
- // For Bridge class.
- Distance distances[] = null;
- int maxNumDist = 0;
- Left leftMost[] = null;
- int maxNumLeftMost = 0;
-
- // For Heap class.
- HeapNode heap[] = null;
- int numHeap = 0;
- int maxNumHeap = 0;
- int numZero = 0;
-
- // For Orientation class.
- int maxNumPolyArea = 0;
- double polyArea[] = null;
-
- int stripCounts[] = null;
- int vertexIndices[] = null;
- Point3f vertices[] = null;
- Object colors[] = null;
- Vector3f normals[] = null;
-
- boolean ccwLoop = true;
-
- boolean earsRandom = true;
- boolean earsSorted = true;
-
- int identCntr; // Not sure what is this for. (Ask Martin)
-
- // double epsilon = 1.0e-12;
- double epsilon = 1.0e-12;
-
- static final double ZERO = 1.0e-8;
- static final int EARS_SEQUENCE = 0;
- static final int EARS_RANDOM = 1;
- static final int EARS_SORTED = 2;
-
-
- static final int INC_LIST_BK = 100;
- static final int INC_LOOP_BK = 20;
- static final int INC_TRI_BK = 50;
- static final int INC_POINT_BK = 100;
- static final int INC_DIST_BK = 50;
-
- private static final int DEBUG = 0;
-
- /**
- * Creates a new instance of the Triangulator.
- * @deprecated This class is created automatically when needed in
- * GeometryInfo and never needs to be used directly. Putting data
- * into a GeometryInfo with primitive POLYGON_ARRAY automatically
- * causes the triangulator to be created and used.
- */
- public Triangulator() {
- earsRandom = false;
- earsSorted = false;
- }
-
- /**
- * Creates a new instance of a Triangulator.
- * @deprecated This class is created automatically when needed in
- * GeometryInfo and never needs to be used directly. Putting data
- * into a GeometryInfo with primitive POLYGON_ARRAY automatically
- * causes the triangulator to be created and used.
- */
- public Triangulator(int earOrder) {
- switch(earOrder) {
- case EARS_SEQUENCE:
- earsRandom = false;
- earsSorted = false;
- break;
- case EARS_RANDOM:
- randomGen = new Random();
- earsRandom = true;
- earsSorted = false;
- break;
- case EARS_SORTED:
- earsRandom = false;
- earsSorted = true;
- break;
- default:
- earsRandom = false;
- earsSorted = false;
- }
-
- }
-
- /**
- * This routine converts the GeometryInfo object from primitive type
- * POLYGON_ARRAY to primitive type TRIANGLE_ARRAY using polygon
- * decomposition techniques.
- *
- * Example of usage:
- * Triangulator tr = new Triangulator();
- * tr.triangulate(ginfo); // ginfo contains the geometry.
- * shape.setGeometry(ginfo.getGeometryArray()); // shape is a Shape3D.
- *
- * @param gi Geometry to be triangulated
- **/
- public void triangulate(GeometryInfo gi) {
- int i, j, k;
- int sIndex = 0, index, currLoop, lastInd, ind;
- boolean proceed;
- boolean reset = false, troubles = false;
-
- boolean done[] = new boolean[1];
- boolean gotIt[] = new boolean[1];
-
- if (gi.getPrimitive() != GeometryInfo.POLYGON_ARRAY){
- throw new IllegalArgumentException(J3dUtilsI18N.getString("Triangulator0"));
- }
-
- gi.indexify();
-
- vertices = gi.getCoordinates();
- if(vertices != null)
- vertexIndices = gi.getCoordinateIndices();
- else
- vertexIndices = null;
-
- colors = gi.getColors();
- normals = gi.getNormals();
- this.gInfo= gi;
-
-
- stripCounts = gi.getStripCounts();
-
- faces = gi.getContourCounts();
- if(faces == null) {
- if(stripCounts == null)
- System.out.println("StripCounts is null! Don't know what to do.");
-
- faces = new int[stripCounts.length];
- for(i=0; i
- *
- *
- * @since Java 3D 1.5
- */
-public class CompressedGeometryData extends Object {
-
- private Header cgHeader;
- private CompressedGeometryRetained retained;
-
-
- /**
- * Creates a new CompressedGeometryData object by copying
- * the specified compressed geometry data into this object.
- * If the version number of compressed geometry, as specified by
- * the Header, is incompatible with the
- * supported version of compressed geometry, then an exception
- * will be thrown.
- *
- * @param hdr the compressed geometry header. This is copied
- * into this CompressedGeometryData object.
- *
- * @param compressedGeometry the compressed geometry data. The
- * geometry must conform to the format described in Appendix B of
- * the Java 3D API Specification.
- *
- * @exception IllegalArgumentException if a problem is detected with the
- * header.
- */
- public CompressedGeometryData(Header hdr,
- byte[] compressedGeometry) {
-
- this(hdr, compressedGeometry, false);
- }
-
- /**
- * Creates a new CompressedGeometryData object. The
- * specified compressed geometry data is either copied into this
- * object or is accessed by reference.
- * If the version number of compressed geometry, as specified by
- * the Header, is incompatible with the
- * supported version of compressed geometry, then an exception
- * will be thrown.
- *
- * @param hdr the compressed geometry header. This is copied
- * into the CompressedGeometryData object.
- *
- * @param compressedGeometry the compressed geometry data. The
- * geometry must conform to the format described in Appendix B of
- * the Java 3D API Specification.
- *
- * @param byReference a flag that indicates whether the data is copied
- * into this compressed geometry object or is accessed by reference.
- *
- * @exception IllegalArgumentException if a problem is detected with the
- * header.
- */
- public CompressedGeometryData(Header hdr,
- byte[] compressedGeometry,
- boolean byReference) {
-
- if ((hdr.size + hdr.start) > compressedGeometry.length) {
- throw new IllegalArgumentException(J3dUtilsI18N.getString("CompressedGeometry0"));
- }
-
- // Create a separate copy of the given header.
- cgHeader = new Header();
- hdr.copy(cgHeader);
-
- // Create the retained object.
- retained = new CompressedGeometryRetained();
- this.retained.createCompressedGeometry(cgHeader, compressedGeometry, byReference);
-
- // This constructor is designed to accept byte arrays that may contain
- // possibly many large compressed geometry blocks interspersed with
- // non-J3D-specific metadata. Only one of these blocks is used per
- // CompressedGeometry object, so set the geometry offset to zero in
- // the header if the data itself is copied.
- if (!byReference)
- cgHeader.start = 0;
- }
-
- /**
- * Creates a new CompressedGeometryData object. The
- * specified compressed geometry data is accessed by reference
- * from the specified buffer.
- * If the version number of compressed geometry, as specified by
- * the Header, is incompatible with the
- * supported version of compressed geometry, then an exception
- * will be thrown.
- *
- * @param hdr the compressed geometry header. This is copied
- * into the CompressedGeometryData object.
- *
- * @param compressedGeometry a buffer containing an NIO byte buffer
- * of compressed geometry data. The
- * geometry must conform to the format described in Appendix B of
- * the Java 3D API Specification.
- *
- * @exception UnsupportedOperationException this method is not
- * yet implemented
- *
- * @exception IllegalArgumentException if a problem is detected with the
- * header,
- * or if the java.nio.Buffer contained in the specified J3DBuffer
- * is not a java.nio.ByteBuffer object.
- *
- * @see Header
- */
- public CompressedGeometryData(Header hdr,
- J3DBuffer compressedGeometry) {
-
- throw new UnsupportedOperationException("not implemented");
- }
-
-
- /**
- * Returns the size, in bytes, of the compressed geometry buffer.
- * The size of the compressed geometry header is not included.
- *
- * @return the size, in bytes, of the compressed geometry buffer.
- */
- public int getByteCount() {
- return cgHeader.size;
- }
-
- /**
- * Copies the compressed geometry header from the CompressedGeometryData
- * object into the passed in parameter.
- *
- * @param hdr the Header object into which to copy the
- * CompressedGeometryData object's header; the offset field may differ
- * from that which was originally specified if a copy of the original
- * compressed geometry byte array was created.
- */
- public void getCompressedGeometryHeader(Header hdr) {
- cgHeader.copy(hdr);
- }
-
- /**
- * Retrieves the compressed geometry associated with the
- * CompressedGeometryData object. Copies the compressed
- * geometry from the CompressedGeometryData node into the given array.
- * The array must be large enough to hold all of the bytes.
- * The individual array elements must be allocated by the caller.
- *
- * @param compressedGeometry the array into which to copy the compressed
- * geometry.
- *
- * @exception IllegalStateException if the data access mode for this
- * object is by-reference.
- *
- * @exception ArrayIndexOutOfBoundsException if compressedGeometry byte
- * array is not large enough to receive the compressed geometry
- */
- public void getCompressedGeometry(byte[] compressedGeometry) {
- if (isByReference()) {
- throw new IllegalStateException(
- J3dUtilsI18N.getString("CompressedGeometry7"));
- }
-
- if (cgHeader.size > compressedGeometry.length) {
- throw new ArrayIndexOutOfBoundsException(
- J3dUtilsI18N.getString("CompressedGeometry4"));
- }
-
- this.retained.copy(compressedGeometry);
- }
-
- /**
- * Decompresses the compressed geometry. Returns an array of Shape nodes
- * containing the decompressed geometry objects, or null if the version
- * number of the compressed geometry is incompatible with the decompressor
- * in the current version of Java 3D.
- *
- * @return an array of Shape nodes containing the
- * geometry decompressed from this CompressedGeometryData
- * object, or null if its version is incompatible
- */
- public Shape3D[] decompress() {
- CompressedGeometryRetained cgr = this.retained;
-
- GeometryDecompressorShape3D decompressor =
- new GeometryDecompressorShape3D();
-
- // Decompress the geometry as TriangleStripArrays. A combination of
- // TriangleStripArrays and TrianglesFanArrays is more compact but
- // requires twice as many Shape3D objects, resulting in slower
- // rendering performance.
- //
- // Using TriangleArray output is currently the fastest, given the
- // strip sizes observed from various compressed geometry objects, but
- // produces about twice as many vertices. TriangleStripArray produces
- // the same number of Shape3D objects as TriangleArray using 1/2
- // to 2/3 of the vertices, with only a marginal performance penalty.
- //
- return decompressor.toTriangleStripArrays(cgr);
- }
-
-
- /**
- * Retrieves the data access mode for this CompressedGeometryData object.
- *
- * @return byReference
flag
- * set to true
. In this mode, a reference to the input
- * data is saved, but the data itself is not necessarily copied. Note
- * that the compressed geometry header is still copied into this
- * compressed geometry object. Data referenced by a
- * CompressedGeometryData object must not be modified after the
- * CompressedGeometryData object is constructed.
- * Applications
- * must exercise care not to violate this rule. If any referenced
- * compressed geometry data is modified after construction,
- * the results are undefined.
- * true
if the data access mode for this
- * CompressedGeometryData object is by-reference;
- * false
if the data access mode is by-copying.
- */
- public boolean isByReference() {
- return this.retained.isByReference();
- }
-
-
- /**
- * Gets the compressed geometry data reference.
- *
- * @return the current compressed geometry data reference.
- *
- * @exception IllegalStateException if the data access mode for this
- * object is not by-reference.
- */
- public byte[] getCompressedGeometryRef() {
- if (!isByReference()) {
- throw new IllegalStateException(
- J3dUtilsI18N.getString("CompressedGeometry8"));
- }
-
- return this.retained.getReference();
- }
-
-
- /**
- * Gets the compressed geometry data buffer reference, which is
- * always null since NIO buffers are not supported for
- * CompressedGeometryData objects.
- *
- * @return null
- */
- public J3DBuffer getCompressedGeometryBuffer() {
- return null;
- }
-
-
- /**
- * The Header class is a data container for the header information,
- * used in conjunction with a CompressedGeometryData object.
- * This information is used to aid the decompression of the compressed geometry.
- *
- * size
bytes of compressed geometry data are copied from the
- * offset indicated by start
instead of copying the entire
- * byte array. The getCompressedGeometry() method will return only the
- * bytes used to construct the object, and the getCompressedGeometryHeader()
- * method will return a header with the start
field set to 0.
- */
- public int start;
-
- /**
- * A point that defines the lower bound of the x,
- * y, and z components for all positions in the
- * compressed geometry buffer. If null, a lower bound of
- * (-1,-1,-1) is assumed. Java 3D will use this information to
- * construct a bounding box around compressed geometry objects
- * that are used in nodes for which the auto compute bounds flag
- * is true. The default value for this point is null.
- */
- public Point3d lowerBound = null;
-
- /**
- * A point that defines the upper bound of the x,
- * y, and z components for all positions in the
- * compressed geometry buffer. If null, an upper bound of (1,1,1)
- * is assumed. Java 3D will use this information to construct a
- * bounding box around compressed geometry objects that are used
- * in nodes for which the auto compute bounds flag is true. The
- * default value for this point is null.
- */
- public Point3d upperBound = null;
-
- /**
- * Creates a new Header object used for the
- * creation of a CompressedGeometryData object.
- * All instance data is declared public and no get or set methods are
- * provided. All values are set to 0 by default and must be filled
- * in by the application.
- *
- * @see CompressedGeometryData
- */
- public Header() {
- }
-
- /**
- * Package-scoped method to copy current Header object
- * to the passed-in Header object.
- *
- * @param hdr the Header object into which to copy the
- * current Header.
- */
- void copy(Header hdr) {
- hdr.majorVersionNumber = this.majorVersionNumber;
- hdr.minorVersionNumber = this.minorVersionNumber;
- hdr.minorMinorVersionNumber = this.minorMinorVersionNumber;
- hdr.bufferType = this.bufferType;
- hdr.bufferDataPresent = this.bufferDataPresent;
- hdr.size = this.size;
- hdr.start = this.start;
- hdr.lowerBound = this.lowerBound;
- hdr.upperBound = this.upperBound;
- }
-
- /**
- * Returns a String describing the contents of the
- * Header object.
- *
- * @return a String describing contents of the compressed geometry header
- */
- @Override
- public String toString() {
- String type = "UNKNOWN";
- switch (bufferType) {
- case POINT_BUFFER: type = "POINT_BUFFER"; break;
- case LINE_BUFFER: type = "LINE_BUFFER"; break;
- case TRIANGLE_BUFFER: type = "TRIANGLE_BUFFER"; break;
- }
-
- String data = "";
- if ((bufferDataPresent & NORMAL_IN_BUFFER) != 0)
- data = data + "NORMALS ";
- if ((bufferDataPresent & COLOR_IN_BUFFER) != 0)
- data = data + "COLORS ";
- if ((bufferDataPresent & ALPHA_IN_BUFFER) != 0)
- data = data + "ALPHA ";
-
- String lbound = "null";
- if (lowerBound != null)
- lbound = lowerBound.toString();
-
- String ubound = "null";
- if (upperBound != null)
- ubound = upperBound.toString();
-
- return
- "majorVersionNumber: " + majorVersionNumber + " " +
- "minorVersionNumber: " + minorVersionNumber + " " +
- "minorMinorVersionNumber: " + minorMinorVersionNumber + "\n" +
- "bufferType: " + type + " " +
- "bufferDataPresent: " + data + "\n" +
- "size: " + size + " " +
- "start: " + start + "\n" +
- "lower bound: " + lbound + "\n" +
- "upper bound: " + ubound + " ";
- }
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryFile.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryFile.java
deleted file mode 100644
index 797c9fc..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryFile.java
+++ /dev/null
@@ -1,1009 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-import javax.media.j3d.CapabilityNotSetException;
-
-//
-// The compressed geometry file format supported by this class has a 32
-// byte header followed by multiple compressed geometry objects.
-//
-// Each object consists of a block of compressed data and an 8-byte
-// individual block header describing its contents.
-//
-// The file ends with a directory data structure used for random access,
-// containing a 64-bit offset for each object in the order in which it
-// appears in the file. This is also used to find the size of the largest
-// object in the file and must be present.
-//
-
-/**
- * This class provides methods to read and write compressed geometry resource
- * files. These files usually end with the .cg extension and support
- * sequential as well as random access to multiple compressed geometry
- * objects.
- *
- * @since Java 3D 1.5
- */
-public class CompressedGeometryFile {
- private static final boolean print = false ;
- private static final boolean benchmark = false ;
-
- /**
- * The magic number which identifies the compressed geometry file type.
- */
- static final int MAGIC_NUMBER = 0xbaddfab4 ;
-
- /**
- * Byte offset of the magic number from start of file.
- */
- static final int MAGIC_NUMBER_OFFSET = 0 ;
-
- /**
- * Byte offset of the major version number from start of file.
- */
- static final int MAJOR_VERSION_OFFSET = 4 ;
-
- /**
- * Byte offset of the minor version number from start of file.
- */
- static final int MINOR_VERSION_OFFSET = 8 ;
-
- /**
- * Byte offset of the minor minor version number from start of file.
- */
- static final int MINOR_MINOR_VERSION_OFFSET = 12 ;
-
- /**
- * Byte offset of the number of objects from start of file.
- */
- static final int OBJECT_COUNT_OFFSET = 16 ;
-
- /**
- * Byte offset of the directory offset from start of file.
- * This offset is long word aligned since the directory offset is a long.
- */
- static final int DIRECTORY_OFFSET_OFFSET = 24 ;
-
- /**
- * File header total size in bytes.
- */
- static final int HEADER_SIZE = 32 ;
-
- /**
- * Byte offset of the object size from start of individual compressed
- * geometry block.
- */
- static final int OBJECT_SIZE_OFFSET = 0 ;
-
- /**
- * Byte offset of the compressed geometry data descriptor from start of
- * individual compressed geometry block.
- */
- static final int GEOM_DATA_OFFSET = 4 ;
-
- /**
- * Bits in compressed geometry data descriptor which encode the buffer type.
- */
- static final int TYPE_MASK = 0x03 ;
-
- /**
- * Bit in compressed geometry data descriptor encoding presence of normals.
- */
- static final int NORMAL_PRESENT_MASK = 0x04 ;
-
- /**
- * Bit in compressed geometry data descriptor encoding presence of colors.
- */
- static final int COLOR_PRESENT_MASK = 0x08 ;
-
- /**
- * Bit in compressed geometry data descriptor encoding presence of alphas.
- */
- static final int ALPHA_PRESENT_MASK = 0x10 ;
-
- /**
- * Value in compressed geometry data descriptor for a point buffer type.
- */
- static final int TYPE_POINT = 1 ;
-
- /**
- * Value in compressed geometry data descriptor for a line buffer type.
- */
- static final int TYPE_LINE = 2 ;
-
- /**
- * Value in compressed geometry data descriptor for a triangle buffer type.
- */
- static final int TYPE_TRIANGLE = 3 ;
-
- /**
- * Block header total size in bytes.
- */
- static final int BLOCK_HEADER_SIZE = 8 ;
-
- // The name of the compressed geometry resource file.
- String fileName = null ;
-
- // The major, minor, and subminor version number of the most recent
- // compressor used to compress any of the objects in the compressed
- // geometry resource file.
- int majorVersionNumber ;
- int minorVersionNumber ;
- int minorMinorVersionNumber ;
-
- // The number of objects in the compressed geometry resource file.
- int objectCount ;
-
- // The index of the current object in the file.
- int objectIndex = 0 ;
-
- // The random access file associated with this instance.
- RandomAccessFile cgFile = null ;
-
- // The magic number identifying the file type.
- int magicNumber ;
-
- // These fields are set from each individual block of compressed geometry.
- byte cgBuffer[] ;
- int geomSize ;
- int geomStart ;
- int geomDataType ;
-
- // The directory of object offsets is read from the end of the file.
- long directory[] ;
- long directoryOffset ;
-
- // The object sizes are computed from the directory offsets. These are
- // used to allocate a buffer large enough to hold the largest object and
- // to determine how many consecutive objects can be read into that buffer.
- int objectSizes[] ;
- int bufferObjectStart ;
- int bufferObjectCount ;
- int bufferNextObjectCount ;
- int bufferNextObjectOffset ;
-
- // The shared compressed geometry header object.
- CompressedGeometryData.Header cgh ;
-
- // Flag indicating file update.
- boolean fileUpdate = false ;
-
- /**
- * Construct a new CompressedGeometryFile instance associated with the
- * specified file. An attempt is made to open the file with read-only
- * access; if this fails then a FileNotFoundException is thrown.
- *
- * @param file path to the compressed geometry resource file
- * @exception FileNotFoundException if file doesn't exist or
- * cannot be read
- * @exception IllegalArgumentException if the file is not a compressed
- * geometry resource file
- * @exception IOException if there is a header or directory read error
- */
- public CompressedGeometryFile(String file) throws IOException {
- this(file, false) ;
- }
-
- /**
- * Construct a new CompressedGeometryFile instance associated with the
- * specified file.
- *
- * @param file path to the compressed geometry resource file
- * @param rw if true, opens the file for read and write access or attempts
- * to create one if it doesn't exist; if false, opens the file with
- * read-only access
- * @exception FileNotFoundException if file doesn't exist or
- * access permissions disallow access
- * @exception IllegalArgumentException if the file is not a compressed
- * geometry resource file
- * @exception IOException if there is a header or directory read error
- */
- public CompressedGeometryFile(String file, boolean rw) throws IOException {
- // Open the file and read the file header.
- open(file, rw) ;
-
- // Copy the file name.
- fileName = new String(file) ;
-
- // Set up the file fields.
- initialize() ;
- }
-
- /**
- * Construct a new CompressedGeometryFile instance associated with a
- * currently open RandomAccessFile.
- *
- * @param file currently open RandomAccessFile
- * @exception IllegalArgumentException if the file is not a compressed
- * geometry resource file
- * @exception IOException if there is a header or directory read error
- */
- public CompressedGeometryFile(RandomAccessFile file) throws IOException {
- // Copy the file reference.
- cgFile = file ;
-
- // Set up the file fields.
- initialize() ;
- }
-
- /**
- * Delete all compressed objects from this instance. This method may only
- * be called after successfully creating a CompressedGeometryFile instance
- * with read-write access, so a corrupted or otherwise invalid resource
- * must be removed manually before it can be rewritten. The close()
- * method must be called sometime after invoking clear() in order to write
- * out the new directory structure.
- *
- * @exception IOException if clear fails
- */
- public void clear() throws IOException {
- // Truncate the file.
- cgFile.setLength(0) ;
-
- // Set up the file fields.
- initialize() ;
- }
-
- /**
- * Return a string containing the file name associated with this instance
- * or null if there is none.
- *
- * @return file name associated with this instance or null if there is
- * none
- */
- public String getFileName() {
- return fileName ;
- }
-
- /**
- * Return the major version number of the most recent compressor used to
- * compress any of the objects in this instance.
- *
- * @return major version number
- */
- public int getMajorVersionNumber() {
- return majorVersionNumber ;
- }
-
- /**
- * Return the minor version number of the most recent compressor used to
- * compress any of the objects in this instance.
- *
- * @return minor version number
- */
- public int getMinorVersionNumber() {
- return minorVersionNumber ;
- }
-
- /**
- * Return the subminor version number of the most recent compressor used to
- * compress any of the objects in this instance.
- *
- * @return subminor version number
- */
- public int getMinorMinorVersionNumber() {
- return minorMinorVersionNumber ;
- }
-
- /**
- * Return the number of compressed objects in this instance.
- *
- * @return number of compressed objects
- */
- public int getObjectCount() {
- return objectCount ;
- }
-
- /**
- * Return the current object index associated with this instance. This is
- * the index of the object that would be returned by an immediately
- * following call to the readNext() method. Its initial value is 0; -1
- * is returned if the last object has been read.
- *
- * @return current object index, or -1 if at end
- */
- public int getCurrentIndex() {
- if (objectIndex == objectCount)
- return -1 ;
- else
- return objectIndex ;
- }
-
- /**
- * Read the next compressed geometry object in the instance. This is
- * initially the first object (index 0) in the instance; otherwise, it is
- * whatever object is next after the last one read. The current object
- * index is incremented by 1 after the read. When the last object is read
- * the index becomes invalid and an immediately subsequent call to
- * readNext() returns null.
- *
- *
- * @return a CompressedGeometryData node component, or null if the last object
- * has been read
- * @exception IOException if read fails
- */
- public CompressedGeometryData readNext() throws IOException {
- return readNext(cgBuffer.length) ;
- }
-
- /**
- * Read all compressed geometry objects contained in the instance. The
- * current object index becomes invalid; an immediately following call
- * to readNext() will return null.
- *
- * @return an array of CompressedGeometryData node components.
- * @exception IOException if read fails
- */
- public CompressedGeometryData[] read() throws IOException {
- long startTime = 0 ;
- CompressedGeometryData cg[] = new CompressedGeometryData[objectCount] ;
-
- if (benchmark)
- startTime = System.currentTimeMillis() ;
-
- objectIndex = 0 ;
- setFilePointer(directory[0]) ;
- bufferNextObjectCount = 0 ;
-
- for (int i = 0 ; i < objectCount ; i++)
- cg[i] = readNext(cgBuffer.length) ;
-
- if (benchmark) {
- long t = System.currentTimeMillis() - startTime ;
- System.out.println("read " + objectCount +
- " objects " + cgFile.length() +
- " bytes in " + (t/1000f) + " sec.") ;
- System.out.println((cgFile.length()/(float)t) + " Kbytes/sec.") ;
- }
-
- return cg ;
- }
-
- /**
- * Read the compressed geometry object at the specified index. The
- * current object index is set to the subsequent object unless the last
- * object has been read, in which case the index becomes invalid and an
- * immediately following call to readNext() will return null.
- *
- * @param index compressed geometry object to read
- * @return a CompressedGeometryData node component
- * @exception IndexOutOfBoundsException if object index is
- * out of range
- * @exception IOException if read fails
- */
- public CompressedGeometryData read(int index) throws IOException {
- objectIndex = index ;
-
- if (objectIndex < 0) {
- throw new IndexOutOfBoundsException
- ("\nobject index must be >= 0") ;
- }
- if (objectIndex >= objectCount) {
- throw new IndexOutOfBoundsException
- ("\nobject index must be < " + objectCount) ;
- }
-
- // Check if object is in cache.
- if ((objectIndex >= bufferObjectStart) &&
- (objectIndex < bufferObjectStart + bufferObjectCount)) {
- if (print) System.out.println("\ngetting object from cache\n") ;
-
- bufferNextObjectOffset = (int)
- (directory[objectIndex] - directory[bufferObjectStart]) ;
-
- bufferNextObjectCount =
- bufferObjectCount - (objectIndex - bufferObjectStart) ;
-
- return readNext() ;
-
- } else {
- // Move file pointer to correct offset.
- setFilePointer(directory[objectIndex]) ;
-
- // Force a read from current offset. Disable cache read-ahead
- // since cache hits are unlikely with random access.
- bufferNextObjectCount = 0 ;
- return readNext(objectSizes[objectIndex]) ;
- }
- }
-
-
- /**
- * Add a compressed geometry node component to the end of the instance.
- * The current object index becomes invalid; an immediately following call
- * to readNext() will return null. The close() method must be called at
- * some later time in order to create a valid compressed geometry file.
- *
- * @param cg a compressed geometry node component
- * @exception CapabilityNotSetException if unable to get compressed
- * geometry data from the node component
- * @exception IOException if write fails
- */
- public void write(CompressedGeometryData cg) throws IOException {
- CompressedGeometryData.Header cgh = new CompressedGeometryData.Header() ;
- cg.getCompressedGeometryHeader(cgh) ;
-
- // Update the read/write buffer size if necessary.
- if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) {
- cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ;
- if (print) System.out.println("\ncgBuffer: reallocated " +
- (cgh.size+BLOCK_HEADER_SIZE) +
- " bytes") ;
- }
-
- cg.getCompressedGeometry(cgBuffer) ;
- write(cgh, cgBuffer) ;
- }
-
- /**
- * Add a buffer of compressed geometry data to the end of the
- * resource. The current object index becomes invalid; an immediately
- * following call to readNext() will return null. The close() method must
- * be called at some later time in order to create a valid compressed
- * geometry file.
- *
- * @param cgh a CompressedGeometryData.Header object describing the data.
- * @param geometry the compressed geometry data
- * @exception IOException if write fails
- */
- public void write(CompressedGeometryData.Header cgh, byte geometry[])
- throws IOException {
-
- // Update the read/write buffer size if necessary. It won't be used
- // in this method, but should be big enough to read any object in
- // the file, including the one to be written.
- if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) {
- cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ;
- if (print) System.out.println("\ncgBuffer: reallocated " +
- (cgh.size+BLOCK_HEADER_SIZE) +
- " bytes") ;
- }
-
- // Assuming backward compatibility, the version number of the file
- // should be the maximum of all individual compressed object versions.
- if ((cgh.majorVersionNumber > majorVersionNumber)
- ||
- ((cgh.majorVersionNumber == majorVersionNumber) &&
- (cgh.minorVersionNumber > minorVersionNumber))
- ||
- ((cgh.majorVersionNumber == majorVersionNumber) &&
- (cgh.minorVersionNumber == minorVersionNumber) &&
- (cgh.minorMinorVersionNumber > minorMinorVersionNumber))) {
-
- majorVersionNumber = cgh.majorVersionNumber ;
- minorVersionNumber = cgh.minorVersionNumber ;
- minorMinorVersionNumber = cgh.minorMinorVersionNumber ;
-
- this.cgh.majorVersionNumber = cgh.majorVersionNumber ;
- this.cgh.minorVersionNumber = cgh.minorVersionNumber ;
- this.cgh.minorMinorVersionNumber = cgh.minorMinorVersionNumber ;
- }
-
- // Get the buffer type and see what vertex components are present.
- int geomDataType = 0 ;
-
- switch (cgh.bufferType) {
- case CompressedGeometryData.Header.POINT_BUFFER:
- geomDataType = TYPE_POINT ;
- break ;
- case CompressedGeometryData.Header.LINE_BUFFER:
- geomDataType = TYPE_LINE ;
- break ;
- case CompressedGeometryData.Header.TRIANGLE_BUFFER:
- geomDataType = TYPE_TRIANGLE ;
- break ;
- }
-
- if ((cgh.bufferDataPresent &
- CompressedGeometryData.Header.NORMAL_IN_BUFFER) != 0)
- geomDataType |= NORMAL_PRESENT_MASK ;
-
- if ((cgh.bufferDataPresent &
- CompressedGeometryData.Header.COLOR_IN_BUFFER) != 0)
- geomDataType |= COLOR_PRESENT_MASK ;
-
- if ((cgh.bufferDataPresent &
- CompressedGeometryData.Header.ALPHA_IN_BUFFER) != 0)
- geomDataType |= ALPHA_PRESENT_MASK ;
-
- // Allocate new directory and object size arrays if necessary.
- if (objectCount == directory.length) {
- long newDirectory[] = new long[2*objectCount] ;
- int newObjectSizes[] = new int[2*objectCount] ;
-
- System.arraycopy(directory, 0,
- newDirectory, 0, objectCount) ;
- System.arraycopy(objectSizes, 0,
- newObjectSizes, 0, objectCount) ;
-
- directory = newDirectory ;
- objectSizes = newObjectSizes ;
-
- if (print)
- System.out.println("\ndirectory and size arrays: reallocated " +
- (2*objectCount) + " entries") ;
- }
-
- // Update directory and object size array.
- directory[objectCount] = directoryOffset ;
- objectSizes[objectCount] = cgh.size + BLOCK_HEADER_SIZE ;
- objectCount++ ;
-
- // Seek to the directory and overwrite from there.
- setFilePointer(directoryOffset) ;
- cgFile.writeInt(cgh.size) ;
- cgFile.writeInt(geomDataType) ;
- cgFile.write(geometry, 0, cgh.size) ;
- if (print)
- System.out.println("\nwrote " + cgh.size +
- " byte compressed object to " + fileName +
- "\nfile offset " + directoryOffset) ;
-
- // Update the directory offset.
- directoryOffset += cgh.size + BLOCK_HEADER_SIZE ;
-
- // Return end-of-file on next read.
- objectIndex = objectCount ;
-
- // Flag file update so close() will write out the directory.
- fileUpdate = true ;
- }
-
- /**
- * Release the resources associated with this instance.
- * Write out final header and directory if contents were updated.
- * This method must be called in order to create a valid compressed
- * geometry resource file if any updates were made.
- */
- public void close() {
- if (cgFile != null) {
- try {
- if (fileUpdate) {
- writeFileDirectory() ;
- writeFileHeader() ;
- }
- cgFile.close() ;
- }
- catch (IOException e) {
- // Don't propagate this exception.
- System.out.println("\nException: " + e.getMessage()) ;
- System.out.println("failed to close " + fileName) ;
- }
- }
- cgFile = null ;
- cgBuffer = null ;
- directory = null ;
- objectSizes = null ;
- }
-
-
- //
- // Open the file. Specifying a non-existent file creates a new one if
- // access permissions allow.
- //
- void open(String fname, boolean rw)
- throws FileNotFoundException, IOException {
-
- cgFile = null ;
- String mode ;
-
- if (rw)
- mode = "rw" ;
- else
- mode = "r" ;
-
- try {
- cgFile = new RandomAccessFile(fname, mode) ;
- if (print) System.out.println("\n" + fname +
- ": opened mode " + mode) ;
- }
- catch (FileNotFoundException e) {
- // N.B. this exception is also thrown on access permission errors
- throw new FileNotFoundException(e.getMessage() + "\n" + fname +
- ": open mode " + mode + " failed") ;
- }
- }
-
- //
- // Seek to the specified offset in the file.
- //
- void setFilePointer(long offset) throws IOException {
- cgFile.seek(offset) ;
-
- // Reset number of objects that can be read sequentially from cache.
- bufferNextObjectCount = 0 ;
- }
-
- //
- // Initialize directory, object size array, read/write buffer, and the
- // shared compressed geometry header.
- //
- void initialize() throws IOException {
- int maxSize = 0 ;
-
- if (cgFile.length() == 0) {
- // New file for writing: allocate nominal initial sizes for arrays.
- objectCount = 0 ;
- cgBuffer = new byte[32768] ;
- directory = new long[16] ;
- objectSizes = new int[directory.length] ;
-
- // Set fields as if they have been read.
- magicNumber = MAGIC_NUMBER ;
- majorVersionNumber = 1 ;
- minorVersionNumber = 0 ;
- minorMinorVersionNumber = 0 ;
- directoryOffset = HEADER_SIZE ;
-
- // Write the file header.
- writeFileHeader() ;
-
- } else {
- // Read the file header.
- readFileHeader() ;
-
- // Check file type.
- if (magicNumber != MAGIC_NUMBER) {
- close() ;
- throw new IllegalArgumentException
- ("\n" + fileName + " is not a compressed geometry file") ;
- }
-
- // Read the directory and determine object sizes.
- directory = new long[objectCount] ;
- readDirectory(directoryOffset, directory) ;
-
- objectSizes = new int[objectCount] ;
- for (int i = 0 ; i < objectCount-1 ; i++) {
- objectSizes[i] = (int)(directory[i+1] - directory[i]) ;
- if (objectSizes[i] > maxSize) maxSize = objectSizes[i] ;
- }
-
- if (objectCount > 0) {
- objectSizes[objectCount-1] =
- (int)(directoryOffset - directory[objectCount-1]) ;
-
- if (objectSizes[objectCount-1] > maxSize)
- maxSize = objectSizes[objectCount-1] ;
- }
-
- // Allocate a buffer big enough to read the largest object.
- cgBuffer = new byte[maxSize] ;
-
- // Move to the first object.
- setFilePointer(HEADER_SIZE) ;
- }
-
- // Set up common parts of the compressed geometry object header.
- cgh = new CompressedGeometryData.Header() ;
- cgh.majorVersionNumber = this.majorVersionNumber ;
- cgh.minorVersionNumber = this.minorVersionNumber ;
- cgh.minorMinorVersionNumber = this.minorMinorVersionNumber ;
-
- if (print) {
- System.out.println(fileName + ": " + objectCount + " objects") ;
- System.out.println("magic number 0x" +
- Integer.toHexString(magicNumber) +
- ", version number " + majorVersionNumber +
- "." + minorVersionNumber +
- "." + minorMinorVersionNumber) ;
- System.out.println("largest object is " + maxSize + " bytes") ;
- }
- }
-
- //
- // Read the file header.
- //
- void readFileHeader() throws IOException {
- byte header[] = new byte[HEADER_SIZE] ;
-
- try {
- setFilePointer(0) ;
- if (cgFile.read(header) != HEADER_SIZE) {
- close() ;
- throw new IOException("failed header read") ;
- }
- }
- catch (IOException e) {
- if (cgFile != null) {
- close() ;
- }
- throw e ;
- }
-
- magicNumber =
- ((header[MAGIC_NUMBER_OFFSET+0] & 0xff) << 24) |
- ((header[MAGIC_NUMBER_OFFSET+1] & 0xff) << 16) |
- ((header[MAGIC_NUMBER_OFFSET+2] & 0xff) << 8) |
- ((header[MAGIC_NUMBER_OFFSET+3] & 0xff)) ;
-
- majorVersionNumber =
- ((header[MAJOR_VERSION_OFFSET+0] & 0xff) << 24) |
- ((header[MAJOR_VERSION_OFFSET+1] & 0xff) << 16) |
- ((header[MAJOR_VERSION_OFFSET+2] & 0xff) << 8) |
- ((header[MAJOR_VERSION_OFFSET+3] & 0xff)) ;
-
- minorVersionNumber =
- ((header[MINOR_VERSION_OFFSET+0] & 0xff) << 24) |
- ((header[MINOR_VERSION_OFFSET+1] & 0xff) << 16) |
- ((header[MINOR_VERSION_OFFSET+2] & 0xff) << 8) |
- ((header[MINOR_VERSION_OFFSET+3] & 0xff)) ;
-
- minorMinorVersionNumber =
- ((header[MINOR_MINOR_VERSION_OFFSET+0] & 0xff) << 24) |
- ((header[MINOR_MINOR_VERSION_OFFSET+1] & 0xff) << 16) |
- ((header[MINOR_MINOR_VERSION_OFFSET+2] & 0xff) << 8) |
- ((header[MINOR_MINOR_VERSION_OFFSET+3] & 0xff)) ;
-
- objectCount =
- ((header[OBJECT_COUNT_OFFSET+0] & 0xff) << 24) |
- ((header[OBJECT_COUNT_OFFSET+1] & 0xff) << 16) |
- ((header[OBJECT_COUNT_OFFSET+2] & 0xff) << 8) |
- ((header[OBJECT_COUNT_OFFSET+3] & 0xff)) ;
-
- directoryOffset =
- ((long)(header[DIRECTORY_OFFSET_OFFSET+0] & 0xff) << 56) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+1] & 0xff) << 48) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+2] & 0xff) << 40) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+3] & 0xff) << 32) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+4] & 0xff) << 24) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+5] & 0xff) << 16) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+6] & 0xff) << 8) |
- ((long)(header[DIRECTORY_OFFSET_OFFSET+7] & 0xff)) ;
- }
-
- //
- // Write the file header based on current field values.
- //
- void writeFileHeader() throws IOException {
- setFilePointer(0) ;
- try {
- cgFile.writeInt(MAGIC_NUMBER) ;
- cgFile.writeInt(majorVersionNumber) ;
- cgFile.writeInt(minorVersionNumber) ;
- cgFile.writeInt(minorMinorVersionNumber) ;
- cgFile.writeInt(objectCount) ;
- cgFile.writeInt(0) ; // long word alignment
- cgFile.writeLong(directoryOffset) ;
- if (print)
- System.out.println("wrote file header for " + fileName) ;
- }
- catch (IOException e) {
- throw new IOException
- (e.getMessage() +
- "\ncould not write file header for " + fileName) ;
- }
- }
-
- //
- // Read the directory of compressed geometry object offsets.
- //
- void readDirectory(long offset, long[] directory)
- throws IOException {
-
- byte buff[] = new byte[directory.length * 8] ;
- setFilePointer(offset) ;
-
- try {
- cgFile.read(buff) ;
- if (print)
- System.out.println("read " + buff.length + " byte directory") ;
- }
- catch (IOException e) {
- throw new IOException
- (e.getMessage() +
- "\nfailed to read " + buff.length +
- " byte directory, offset " + offset + " in file " + fileName) ;
- }
-
- for (int i = 0 ; i < directory.length ; i++) {
- directory[i] =
- ((long)(buff[i*8+0] & 0xff) << 56) |
- ((long)(buff[i*8+1] & 0xff) << 48) |
- ((long)(buff[i*8+2] & 0xff) << 40) |
- ((long)(buff[i*8+3] & 0xff) << 32) |
- ((long)(buff[i*8+4] & 0xff) << 24) |
- ((long)(buff[i*8+5] & 0xff) << 16) |
- ((long)(buff[i*8+6] & 0xff) << 8) |
- ((long)(buff[i*8+7] & 0xff)) ;
- }
- }
-
- //
- // Write the file directory.
- //
- void writeFileDirectory() throws IOException {
- setFilePointer(directoryOffset) ;
-
- int directoryAlign = (int)(directoryOffset % 8) ;
- if (directoryAlign != 0) {
- // Align to long word before writing directory of long offsets.
- byte bytes[] = new byte[8-directoryAlign] ;
-
- try {
- cgFile.write(bytes) ;
- if (print)
- System.out.println ("wrote " + (8-directoryAlign) +
- " bytes long alignment") ;
- }
- catch (IOException e) {
- throw new IOException
- (e.getMessage() +
- "\ncould not write " + directoryAlign +
- " bytes to long word align directory for " + fileName) ;
- }
- directoryOffset += 8-directoryAlign ;
- }
-
- try {
- for (int i = 0 ; i < objectCount ; i++)
- cgFile.writeLong(directory[i]) ;
-
- if (print)
- System.out.println("wrote file directory for " + fileName) ;
- }
- catch (IOException e) {
- throw new IOException
- (e.getMessage() +
- "\ncould not write directory for " + fileName) ;
- }
- }
-
- //
- // Get the next compressed object in the file, either from the read-ahead
- // cache or from the file itself.
- //
- CompressedGeometryData readNext(int bufferReadLimit)
- throws IOException {
- if (objectIndex == objectCount)
- return null ;
-
- if (bufferNextObjectCount == 0) {
- // No valid objects are in the cache.
- int curSize = 0 ;
- bufferObjectCount = 0 ;
-
- // See how much we have room to read.
- for (int i = objectIndex ; i < objectCount ; i++) {
- if (curSize + objectSizes[i] > bufferReadLimit) break ;
- curSize += objectSizes[i] ;
- bufferObjectCount++ ;
- }
-
- // Try to read that amount.
- try {
- int n = cgFile.read(cgBuffer, 0, curSize) ;
- if (print)
- System.out.println("\nread " + n +
- " bytes from " + fileName) ;
- }
- catch (IOException e) {
- throw new IOException
- (e.getMessage() +
- "\nfailed to read " + curSize +
- " bytes, object " + objectIndex + " in file " + fileName) ;
- }
-
- // Point at the first object in the buffer.
- bufferObjectStart = objectIndex ;
- bufferNextObjectCount = bufferObjectCount ;
- bufferNextObjectOffset = 0 ;
- }
-
- // Get block header info.
- geomSize =
- ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+0]&0xff)<<24) |
- ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+1]&0xff)<<16) |
- ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+2]&0xff)<< 8) |
- ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+3]&0xff)) ;
-
- geomDataType =
- ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+0]&0xff) << 24) |
- ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+1]&0xff) << 16) |
- ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+2]&0xff) << 8) |
- ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+3]&0xff)) ;
-
- // Get offset of compressed geometry data from start of buffer.
- geomStart = bufferNextObjectOffset + BLOCK_HEADER_SIZE ;
-
- if (print) {
- System.out.println("\nobject " + objectIndex +
- "\nfile offset " + directory[objectIndex] +
- ", buffer offset " + bufferNextObjectOffset) ;
- System.out.println("size " + geomSize + " bytes, " +
- "data descriptor 0x" +
- Integer.toHexString(geomDataType)) ;
- }
-
- // Update cache info.
- bufferNextObjectOffset += objectSizes[objectIndex] ;
- bufferNextObjectCount-- ;
- objectIndex++ ;
-
- return newCG(geomSize, geomStart, geomDataType) ;
- }
-
-
- //
- // Construct and return a compressed geometry node.
- //
- CompressedGeometryData newCG(int geomSize,
- int geomStart,
- int geomDataType) {
- cgh.size = geomSize ;
- cgh.start = geomStart ;
-
- if ((geomDataType & TYPE_MASK) == TYPE_POINT)
- cgh.bufferType = CompressedGeometryData.Header.POINT_BUFFER ;
- else if ((geomDataType & TYPE_MASK) == TYPE_LINE)
- cgh.bufferType = CompressedGeometryData.Header.LINE_BUFFER ;
- else if ((geomDataType & TYPE_MASK) == TYPE_TRIANGLE)
- cgh.bufferType = CompressedGeometryData.Header.TRIANGLE_BUFFER ;
-
- cgh.bufferDataPresent = 0 ;
-
- if ((geomDataType & NORMAL_PRESENT_MASK) != 0)
- cgh.bufferDataPresent |=
- CompressedGeometryData.Header.NORMAL_IN_BUFFER ;
-
- if ((geomDataType & COLOR_PRESENT_MASK) != 0)
- cgh.bufferDataPresent |=
- CompressedGeometryData.Header.COLOR_IN_BUFFER ;
-
- if ((geomDataType & ALPHA_PRESENT_MASK) != 0)
- cgh.bufferDataPresent |=
- CompressedGeometryData.Header.ALPHA_IN_BUFFER ;
-
- return new CompressedGeometryData(cgh, cgBuffer) ;
- }
-
- /**
- * Release file resources when this object is garbage collected.
- */
- @Override
- protected void finalize() {
- close() ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryRetained.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryRetained.java
deleted file mode 100644
index 5a3b333..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressedGeometryRetained.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import javax.media.j3d.GeometryArray;
-
-/**
- * The compressed geometry object is used to store geometry in a
- * compressed format. Using compressed geometry reduces the amount
- * of memory needed by a Java 3D application and increases the speed
- * objects can be sent over the network. Once geometry decompression
- * hardware support becomes available, increased rendering performance
- * will also result from the use of compressed geometry.
- */
-class CompressedGeometryRetained extends Object {
-
- // If not in by-reference mode, a 48-byte header as defined by the
- // GL_SUNX_geometry_compression OpenGL extension is always concatenated to
- // the beginning of the compressed geometry data and copied along with the
- // it into a contiguous array. This allows hardware decompression using
- // the obsolete experimental GL_SUNX_geometry_compression extension if
- // that is all that is available.
- //
- // This is completely distinct and not to be confused with the cgHeader
- // field on the non-retained side, although much of the data is
- // essentially the same.
- private static final int HEADER_LENGTH = 48 ;
-
- // These are the header locations examined.
- private static final int HEADER_MAJOR_VERSION_OFFSET = 0 ;
- private static final int HEADER_MINOR_VERSION_OFFSET = 1 ;
- private static final int HEADER_MINOR_MINOR_VERSION_OFFSET = 2 ;
- private static final int HEADER_BUFFER_TYPE_OFFSET = 3 ;
- private static final int HEADER_BUFFER_DATA_OFFSET = 4 ;
-
- // The OpenGL compressed geometry extensions use bits instead of
- // enumerations to represent the type of compressed geometry.
- static final byte TYPE_POINT = 1 ;
- static final byte TYPE_LINE = 2 ;
- static final byte TYPE_TRIANGLE = 4 ;
-
- // Version number of this compressed geometry object.
- int majorVersionNumber ;
- int minorVersionNumber ;
- int minorMinorVersionNumber ;
-
- // These fields are used by the native execute() method.
- int packedVersion ;
- int bufferType ;
- int bufferContents ;
- int renderFlags ;
- int offset ;
- int size ;
- byte[] compressedGeometry ;
-
- // A reference to the original byte array with which this object was
- // created. If hardware decompression is available but it doesn't support
- // by-reference semantics, then an internal copy of the original byte array
- // is made even when by-reference semantics have been requested.
- private byte[] originalCompressedGeometry = null ;
-
- // True if by-reference data access mode is in effect.
- private boolean byReference = false ;
-
- /**
- * The package-scoped constructor.
- */
- CompressedGeometryRetained() {
- }
-
- /**
- * Return true if the data access mode is by-reference.
- */
- boolean isByReference() {
- return this.byReference ;
- }
-
- private void createByCopy(byte[] geometry) {
- // Always copy a header along with the compressed geometry into a
- // contiguous array in order to support hardware acceleration with the
- // GL_SUNX_geometry_compression extension. The header is unnecessary
- // if only the newer GL_SUN_geometry_compression API needs support.
- compressedGeometry = new byte[HEADER_LENGTH + this.size] ;
-
- compressedGeometry[HEADER_MAJOR_VERSION_OFFSET] =
- (byte)this.majorVersionNumber ;
-
- compressedGeometry[HEADER_MINOR_VERSION_OFFSET] =
- (byte)this.minorVersionNumber ;
-
- compressedGeometry[HEADER_MINOR_MINOR_VERSION_OFFSET] =
- (byte)this.minorMinorVersionNumber ;
-
- compressedGeometry[HEADER_BUFFER_TYPE_OFFSET] =
- (byte)this.bufferType ;
-
- compressedGeometry[HEADER_BUFFER_DATA_OFFSET] =
- (byte)this.bufferContents ;
-
- System.arraycopy(geometry, this.offset,
- compressedGeometry, HEADER_LENGTH, this.size) ;
-
- this.offset = HEADER_LENGTH ;
- }
-
- /**
- * Creates the retained compressed geometry data. Data from the header is
- * always copied; the compressed geometry is copied as well if the data
- * access mode is not by-reference.
- *
- * @param hdr the compressed geometry header
- * @param geometry the compressed geometry
- * @param byReference if true then by-reference semantics requested
- */
- void createCompressedGeometry(CompressedGeometryData.Header hdr,
- byte[] geometry, boolean byReference) {
-
- this.byReference = byReference ;
-
-//// this.centroid.set(geoBounds.getCenter());
-//// recompCentroid = false;
- this.majorVersionNumber = hdr.majorVersionNumber ;
- this.minorVersionNumber = hdr.minorVersionNumber ;
- this.minorMinorVersionNumber = hdr.minorMinorVersionNumber ;
-
- this.packedVersion =
- (hdr.majorVersionNumber << 24) |
- (hdr.minorVersionNumber << 16) |
- (hdr.minorMinorVersionNumber << 8) ;
-
- switch(hdr.bufferType) {
- case CompressedGeometryData.Header.POINT_BUFFER:
- this.bufferType = TYPE_POINT ;
- break ;
- case CompressedGeometryData.Header.LINE_BUFFER:
- this.bufferType = TYPE_LINE ;
- break ;
- case CompressedGeometryData.Header.TRIANGLE_BUFFER:
- this.bufferType = TYPE_TRIANGLE ;
- break ;
- }
-
- this.bufferContents = hdr.bufferDataPresent ;
- this.renderFlags = 0 ;
-
- this.size = hdr.size ;
- this.offset = hdr.start ;
-
- if (byReference) {
- // Assume we can use the given reference, but maintain a second
- // reference in case a copy is later needed.
- this.compressedGeometry = geometry;
- this.originalCompressedGeometry = geometry;
- } else {
- // Copy the original data into a format that can be used by both
- // the software and native hardware decompressors.
- createByCopy(geometry);
- this.originalCompressedGeometry = null;
- }
- }
-
- /**
- * Return a vertex format mask that's compatible with GeometryArray
- * objects.
- */
- int getVertexFormat() {
- int vertexFormat = GeometryArray.COORDINATES;
-
- if ((bufferContents & CompressedGeometryData.Header.NORMAL_IN_BUFFER) != 0) {
- vertexFormat |= GeometryArray.NORMALS;
- }
-
- if ((bufferContents & CompressedGeometryData.Header.COLOR_IN_BUFFER) != 0) {
- if ((bufferContents & CompressedGeometryData.Header.ALPHA_IN_BUFFER) != 0) {
- vertexFormat |= GeometryArray.COLOR_4;
- } else {
- vertexFormat |= GeometryArray.COLOR_3;
- }
- }
-
- return vertexFormat ;
- }
-
- /**
- * Return a buffer type that's compatible with CompressedGeometryData.Header.
- */
- int getBufferType() {
- switch(this.bufferType) {
- case TYPE_POINT:
- return CompressedGeometryData.Header.POINT_BUFFER ;
- case TYPE_LINE:
- return CompressedGeometryData.Header.LINE_BUFFER ;
- default:
- case TYPE_TRIANGLE:
- return CompressedGeometryData.Header.TRIANGLE_BUFFER ;
- }
- }
-
- /**
- * Copies compressed geometry data into the given array of bytes.
- * The internal header information is not copied.
- *
- * @param buff array of bytes into which to copy compressed geometry
- */
- void copy(byte[] buff) {
- System.arraycopy(compressedGeometry, offset, buff, 0, size) ;
- }
-
- /**
- * Returns a reference to the original compressed geometry byte array,
- * which may have been copied even if by-reference semantics have been
- * requested. It will be null if byCopy is in effect.
- *
- * @return reference to array of bytes containing the compressed geometry.
- */
- byte[] getReference() {
- return originalCompressedGeometry ;
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStream.java b/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStream.java
deleted file mode 100644
index f501db9..0000000
--- a/src/classes/share/com/sun/j3d/utils/geometry/compression/CompressionStream.java
+++ /dev/null
@@ -1,2338 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.geometry.compression;
-
-import java.nio.ByteBuffer;
-import java.nio.DoubleBuffer;
-import java.nio.FloatBuffer;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-
-import javax.media.j3d.Appearance;
-import javax.media.j3d.Geometry;
-import javax.media.j3d.GeometryArray;
-import javax.media.j3d.GeometryStripArray;
-import javax.media.j3d.IndexedGeometryArray;
-import javax.media.j3d.IndexedGeometryStripArray;
-import javax.media.j3d.IndexedLineArray;
-import javax.media.j3d.IndexedLineStripArray;
-import javax.media.j3d.IndexedQuadArray;
-import javax.media.j3d.IndexedTriangleArray;
-import javax.media.j3d.IndexedTriangleFanArray;
-import javax.media.j3d.IndexedTriangleStripArray;
-import javax.media.j3d.J3DBuffer;
-import javax.media.j3d.LineArray;
-import javax.media.j3d.LineStripArray;
-import javax.media.j3d.Material;
-import javax.media.j3d.QuadArray;
-import javax.media.j3d.Shape3D;
-import javax.media.j3d.TriangleArray;
-import javax.media.j3d.TriangleFanArray;
-import javax.media.j3d.TriangleStripArray;
-import javax.vecmath.Color3f;
-import javax.vecmath.Color4f;
-import javax.vecmath.Point3d;
-import javax.vecmath.Point3f;
-import javax.vecmath.Point3i;
-import javax.vecmath.Vector3f;
-
-import com.sun.j3d.internal.BufferWrapper;
-import com.sun.j3d.utils.geometry.GeometryInfo;
-
-/**
- * This class is used as input to a geometry compressor. It collects elements
- * such as vertices, normals, colors, mesh references, and quantization
- * parameters in an ordered stream. This stream is then traversed during
- * the compression process and used to build the compressed output buffer.
- *
- * @see GeometryCompressor
- *
- * @since Java 3D 1.5
- */
-public class CompressionStream {
- //
- // NOTE: For now, copies are made of all GeometryArray vertex components
- // even when by-reference access is available.
- //
- // TODO: Retrofit all CompressionStreamElements and MeshBuffer to handle
- // offsets to vertex data array references so that vertex components don't
- // have to be copied. New CompressionStreamElements could be defined to
- // set the current array reference during the quantization pass, or the
- // reference could be included in every CompressionStreamElement along
- // with the data offsets.
- //
- // TODO: Quantize on-the-fly when adding GeometryArray vertex data so that
- // CompressionStreamElements don't need references to the original float,
- // double, or byte data. Quantization is currently a separate pass since
- // the 1st pass adds vertex data and gets the total object bounds, but
- // this can be computed by merging the bounds of each GeometryArray
- // compressed into a single object. The 2nd pass quantization is still
- // needed for vertex data which isn't retrieved from a GeometryArray; for
- // example, apps that might use the addVertex() methods directly instead
- // of addGeometryArray().
- //
- // TODO: To further optimize memory, create new subclasses of
- // CompressionStream{Color, Normal} for bundled attributes and add them as
- // explicit stream elements. Then CompressionStreamVertex won't need to
- // carry references to them. This memory savings might be negated by the
- // extra overhead of adding more elements to the stream, however.
- //
- // TODO: Keep the absolute quantized values in the mesh buffer mirror so
- // that unmeshed CompressionStreamElements don't need to carry them.
- //
- // TODO: Support texture coordinate compression even though Level II is
- // not supported by any hardware decompressor on any graphics card.
- // Software decompression is still useful for applications interested in
- // minimizing file space, transmission time, and object loading time.
- //
- private static final boolean debug = false ;
- private static final boolean benchmark = false ;
-
- // Mesh buffer normal substitution is unavailable in Level I.
- private static final boolean noMeshNormalSubstitution = true ;
-
- /**
- * This flag indicates that a vertex starts a new triangle or line strip.
- */
- static final int RESTART = 1 ;
-
- /**
- * This flag indicates that the next triangle in the strip is defined by
- * replacing the middle vertex of the previous triangle in the strip.
- * Equivalent to REPLACE_OLDEST for line strips.
- */
- static final int REPLACE_MIDDLE = 2 ;
-
- /**
- * This flag indicates that the next triangle in the strip is defined by
- * replacing the oldest vertex of the previous triangle in the strip.
- * Equivalent to REPLACE_MIDDLE for line strips.
- */
- static final int REPLACE_OLDEST = 3 ;
-
- /**
- * This flag indicates that a vertex is to be pushed into the mesh buffer.
- */
- static final int MESH_PUSH = 1 ;
-
- /**
- * This flag indicates that a vertex does not use the mesh buffer.
- */
- static final int NO_MESH_PUSH = 0 ;
-
- /**
- * Byte to float scale factor for scaling byte color components.
- */
- static final float ByteToFloatScale = 1.0f/255.0f;
-
- /**
- * Type of this stream, either CompressedGeometryData.Header.POINT_BUFFER,
- * CompressedGeometryData.Header.LINE_BUFFER, or
- * CompressedGeometryData.Header.TRIANGLE_BUFFER
- */
- int streamType ;
-
- /**
- * A mask indicating which components are present in each vertex, as
- * defined by GeometryArray.
- */
- int vertexComponents ;
-
- /**
- * Boolean indicating colors are bundled with the vertices.
- */
- boolean vertexColors ;
-
- /**
- * Boolean indicating RGB colors are bundled with the vertices.
- */
- boolean vertexColor3 ;
-
- /**
- * Boolean indicating RGBA colors are bundled with the vertices.
- */
- boolean vertexColor4 ;
-
- /**
- * Boolean indicating normals are bundled with the vertices.
- */
- boolean vertexNormals ;
-
- /**
- * Boolean indicating texture coordinates are present.
- */
- boolean vertexTextures ;
-
- /**
- * Boolean indicating that 2D texture coordinates are used.
- * Currently only used to skip over textures in interleaved data.
- */
- boolean vertexTexture2 ;
-
- /**
- * Boolean indicating that 3D texture coordinates are used.
- * Currently only used to skip over textures in interleaved data.
- */
- boolean vertexTexture3 ;
-
- /**
- * Boolean indicating that 4D texture coordinates are used.
- * Currently only used to skip over textures in interleaved data.
- */
- boolean vertexTexture4 ;
-
- /**
- * Axes-aligned box enclosing all vertices in model coordinates.
- */
- Point3d mcBounds[] = new Point3d[2] ;
-
- /**
- * Axes-aligned box enclosing all vertices in normalized coordinates.
- */
- Point3d ncBounds[] = new Point3d[2] ;
-
- /**
- * Axes-aligned box enclosing all vertices in quantized coordinates.
- */
- Point3i qcBounds[] = new Point3i[2] ;
-
- /**
- * Center for normalizing positions to the unit cube.
- */
- double center[] = new double[3] ;
-
- /**
- * Maximum position range along the 3 axes.
- */
- double positionRangeMaximum ;
-
- /**
- * Scale for normalizing positions to the unit cube.
- */
- double scale ;
-
- /**
- * Current position component (X, Y, and Z) quantization value. This can
- * range from 1 to 16 bits and has a default of 16.textureNonPowerOfTwoAvailable
property is set to true.
- *
- * @since Java 3D 1.5
- */
- public static final int ALLOW_NON_POWER_OF_TWO = 0x08;
-
- /*
- * Private declaration for BufferedImage allocation
- */
- private static ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
- private static int[] nBits = {8, 8, 8, 8};
- private static int[] bandOffset = { 0, 1, 2, 3};
- private static ComponentColorModel colorModel = new ComponentColorModel(cs, nBits, true, false, Transparency.TRANSLUCENT, 0);
-
- private Texture2D tex = null;
- private BufferedImage bufferedImage = null;
- private ImageComponent2D imageComponent = null;
- private int textureFormat = Texture.RGBA;
- private int imageComponentFormat = ImageComponent.FORMAT_RGBA;
- private int flags;
- private boolean byRef = false;
- private boolean yUp = false;
- private boolean forcePowerOfTwo = true;
-
- /**
- * Contructs a TextureLoader object using the specified BufferedImage
- * and default format RGBA
- * @param bImage The BufferedImage used for loading the texture
- *
- * @exception NullPointerException if bImage is null
- */
- public TextureLoader(BufferedImage bImage) {
- this(bImage, null, 0);
- }
-
- /**
- * Contructs a TextureLoader object using the specified BufferedImage
- * and format
- * @param bImage The BufferedImage used for loading the texture
- * @param format The format specifies which channels to use
- *
- * @exception NullPointerException if bImage is null
- */
- public TextureLoader(BufferedImage bImage, String format) {
- this(bImage, format, 0);
- }
-
- /**
- * Contructs a TextureLoader object using the specified BufferedImage,
- * option flags and default format RGBA
- * @param bImage The BufferedImage used for loading the texture
- * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
- *
- * @exception NullPointerException if bImage is null
- */
- public TextureLoader(BufferedImage bImage, int flags) {
- this(bImage, null, flags);
- }
-
- /**
- * Contructs a TextureLoader object using the specified BufferedImage,
- * format and option flags
- * @param bImage The BufferedImage used for loading the texture
- * @param format The format specifies which channels to use
- * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
- *
- * @exception NullPointerException if bImage is null
- */
- public TextureLoader(BufferedImage bImage, String format, int flags) {
- if (bImage == null) {
- throw new NullPointerException();
- }
-
- parseFormat(format);
- this.flags = flags;
- bufferedImage = bImage;
- if (format==null)
- chooseFormat(bufferedImage);
-
- if ((flags & BY_REFERENCE) != 0) {
- byRef = true;
- }
- if ((flags & Y_UP) != 0) {
- yUp = true;
- }
- if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) {
- forcePowerOfTwo = false;
- }
- }
-
- /**
- * Contructs a TextureLoader object using the specified Image
- * and default format RGBA
- * @param image The Image used for loading the texture
- * @param observer The associated image observer
- *
- * @exception NullPointerException if image is null
- * @exception ImageException if there is a problem loading the image
- */
- public TextureLoader(Image image, Component observer) {
- this(image, null, 0, observer);
- }
-
- /**
- * Contructs a TextureLoader object using the specified Image
- * and format
- * @param image The Image used for loading the texture
- * @param format The format specifies which channels to use
- * @param observer The associated image observer
- *
- * @exception NullPointerException if image is null
- * @exception ImageException if there is a problem loading the image
- */
- public TextureLoader(Image image, String format, Component observer) {
- this(image, format, 0, observer);
- }
-
- /**
- * Contructs a TextureLoader object using the specified Image
- * flags and default format RGBA
- * @param image The Image used for loading the texture
- * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
- * @param observer The associated image observer
- *
- * @exception NullPointerException if image is null
- * @exception ImageException if there is a problem loading the image
- */
- public TextureLoader(Image image, int flags, Component observer) {
- this(image, null, flags, observer);
- }
-
- /**
- * Contructs a TextureLoader object using the specified Image
- * format and option flags
- * @param image The Image used for loading the texture
- * @param format The format specifies which channels to use
- * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
- * @param observer The associated image observer
- *
- * @exception NullPointerException if image is null
- * @exception ImageException if there is a problem loading the image
- */
- public TextureLoader(Image image, String format, int flags,
- Component observer) {
-
- if (image == null) {
- throw new NullPointerException();
- }
-
- if (observer == null) {
- observer = new java.awt.Container();
- }
-
- parseFormat(format);
- this.flags = flags;
- bufferedImage = createBufferedImage(image, observer);
-
- if (bufferedImage==null) {
- throw new ImageException("Error loading image: " + image.toString());
- }
-
- if (format==null)
- chooseFormat(bufferedImage);
-
- if ((flags & BY_REFERENCE) != 0) {
- byRef = true;
- }
- if ((flags & Y_UP) != 0) {
- yUp = true;
- }
- if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) {
- forcePowerOfTwo = false;
- }
- }
-
- /**
- * Contructs a TextureLoader object using the specified file
- * and default format RGBA
- * @param fname The file that specifies an Image to load the texture with
- * @param observer The associated image observer
- *
- * @exception ImageException if there is a problem reading the image
- */
- public TextureLoader(String fname, Component observer) {
- this(fname, null, 0, observer);
- }
-
- /**
- * Contructs a TextureLoader object using the specified file,
- * and format
- * @param fname The file that specifies an Image to load the texture with
- * @param format The format specifies which channels to use
- * @param observer The associated image observer
- *
- * @exception ImageException if there is a problem reading the image
- */
- public TextureLoader(String fname, String format, Component observer) {
- this(fname, format, 0, observer);
- }
-
- /**
- * Contructs a TextureLoader object using the specified file,
- * option flags and default format RGBA
- * @param fname The file that specifies an Image to load the texture with
- * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
- * @param observer The associated image observer
- *
- * @exception ImageException if there is a problem reading the image
- */
- public TextureLoader(String fname, int flags, Component observer) {
- this(fname, null, flags, observer);
- }
-
- /**
- * Contructs a TextureLoader object using the specified file,
- * format and option flags
- * @param fname The file that specifies an Image to load the texture with
- * @param format The format specifies which channels to use
- * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
- * @param observer The associated image observer
- *
- * @exception ImageException if there is a problem reading the image
- */
- public TextureLoader(final String fname, String format, int flags,
- Component observer) {
-
- if (observer == null) {
- observer = new java.awt.Container();
- }
-
- bufferedImage = (BufferedImage)
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- @Override
- public Object run() {
- try {
- return ImageIO.read(new File(fname));
- } catch (IOException e) {
- throw new ImageException(e);
- }
- }
- }
- );
-
- if (bufferedImage==null) {
- throw new ImageException("Error loading image: " + fname);
- }
-
- parseFormat(format);
- this.flags = flags;
-
- if (format==null)
- chooseFormat(bufferedImage);
-
- if ((flags & BY_REFERENCE) != 0) {
- byRef = true;
- }
- if ((flags & Y_UP) != 0) {
- yUp = true;
- }
- if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) {
- forcePowerOfTwo = false;
- }
- }
-
- /**
- * Contructs a TextureLoader object using the specified URL
- * and default format RGBA
- * @param url The URL that specifies an Image to load the texture with
- * @param observer The associated image observer
- *
- * @exception ImageException if there is a problem reading the image
- */
- public TextureLoader(URL url, Component observer) {
- this(url, null, 0, observer);
- }
-
- /**
- * Contructs a TextureLoader object using the specified URL,
- * and format
- * @param url The URL that specifies an Image to load the texture with
- * @param format The format specifies which channels to use
- * @param observer The associated image observer
- *
- * @exception ImageException if there is a problem reading the image
- */
- public TextureLoader(URL url, String format, Component observer) {
- this(url, format, 0, observer);
- }
-
- /**
- * Contructs a TextureLoader object using the specified URL,
- * option flags and default format RGBA
- * @param url The URL that specifies an Image to load the texture with
- * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
- * @param observer The associated image observer
- *
- * @exception ImageException if there is a problem reading the image
- */
- public TextureLoader(URL url, int flags, Component observer) {
- this(url, null, flags, observer);
- }
- /**
- * Contructs a TextureLoader object using the specified URL,
- * format and option flags
- * @param url The url that specifies an Image to load the texture with
- * @param format The format specifies which channels to use
- * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
- * @param observer The associated image observer
- *
- * @exception ImageException if there is a problem reading the image
- */
- public TextureLoader(final URL url, String format, int flags,
- Component observer) {
-
- if (observer == null) {
- observer = new java.awt.Container();
- }
-
- bufferedImage = (BufferedImage)
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- @Override
- public Object run() {
- try {
- return ImageIO.read(url);
- } catch (IOException e) {
- throw new ImageException(e);
- }
- }
- }
- );
-
- if (bufferedImage==null) {
- throw new ImageException("Error loading image: " + url.toString());
- }
-
- parseFormat(format);
- this.flags = flags;
-
- if (format==null)
- chooseFormat(bufferedImage);
-
- if ((flags & BY_REFERENCE) != 0) {
- byRef = true;
- }
- if ((flags & Y_UP) != 0) {
- yUp = true;
- }
- if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) {
- forcePowerOfTwo = false;
- }
- }
-
-
- /**
- * Returns the associated ImageComponent2D object
- *
- * @return The associated ImageComponent2D object
- */
- public ImageComponent2D getImage() {
- if (imageComponent == null)
- imageComponent = new ImageComponent2D(imageComponentFormat,
- bufferedImage, byRef, yUp);
- return imageComponent;
- }
-
- /**
- * Returns the scaled ImageComponent2D object
- *
- * @param xScale The X scaling factor
- * @param yScale The Y scaling factor
- *
- * @return The scaled ImageComponent2D object
- */
- public ImageComponent2D getScaledImage(float xScale, float yScale) {
- if (xScale == 1.0f && yScale == 1.0f)
- return getImage();
- else
- return(new ImageComponent2D(imageComponentFormat,
- getScaledImage(bufferedImage,
- xScale, yScale),
- byRef, yUp));
- }
-
- /**
- * Returns the scaled ImageComponent2D object
- *
- * @param width The desired width
- * @param height The desired height
- *
- * @return The scaled ImageComponent2D object
- */
- public ImageComponent2D getScaledImage(int width, int height) {
-
- if (bufferedImage.getWidth() == width &&
- bufferedImage.getHeight() == height)
- return getImage();
- else
- return(new ImageComponent2D(imageComponentFormat,
- getScaledImage(bufferedImage,
- width, height),
- byRef, yUp));
- }
-
- /**
- * Returns the associated Texture object.
- *
- * @return The associated Texture object
- */
- public Texture getTexture() {
- ImageComponent2D[] scaledImageComponents = null;
- BufferedImage[] scaledBufferedImages = null;
- if (tex == null) {
-
- int width;
- int height;
-
- if (forcePowerOfTwo) {
- width = getClosestPowerOf2(bufferedImage.getWidth());
- height = getClosestPowerOf2(bufferedImage.getHeight());
- } else {
- width = bufferedImage.getWidth();
- height = bufferedImage.getHeight();
- }
-
- if ((flags & GENERATE_MIPMAP) != 0) {
-
- BufferedImage origImage = bufferedImage;
- int newW = width;
- int newH = height;
- int level = Math.max(computeLog(width), computeLog(height)) + 1;
- scaledImageComponents = new ImageComponent2D[level];
- scaledBufferedImages = new BufferedImage[level];
- tex = new Texture2D(tex.MULTI_LEVEL_MIPMAP, textureFormat,
- width, height);
-
- for (int i = 0; i < level; i++) {
- scaledBufferedImages[i] = getScaledImage(origImage, newW, newH);
- scaledImageComponents[i] = new ImageComponent2D(
- imageComponentFormat, scaledBufferedImages[i],
- byRef, yUp);
-
- tex.setImage(i, scaledImageComponents[i]);
- if (forcePowerOfTwo) {
- if (newW > 1) newW >>= 1;
- if (newH > 1) newH >>= 1;
- } else {
- if (newW > 1) {
- newW = (int) Math.floor(newW / 2.0);
- }
- if (newH > 1) {
- newH = (int) Math.floor(newH / 2.0);
- }
- }
- origImage = scaledBufferedImages[i];
- }
-
- } else {
- scaledImageComponents = new ImageComponent2D[1];
- scaledBufferedImages = new BufferedImage[1];
-
- // Create texture from image
- scaledBufferedImages[0] = getScaledImage(bufferedImage,
- width, height);
- scaledImageComponents[0] = new ImageComponent2D(
- imageComponentFormat, scaledBufferedImages[0],
- byRef, yUp);
-
- tex = new Texture2D(tex.BASE_LEVEL, textureFormat, width, height);
-
- tex.setImage(0, scaledImageComponents[0]);
- }
- tex.setMinFilter(tex.BASE_LEVEL_LINEAR);
- tex.setMagFilter(tex.BASE_LEVEL_LINEAR);
- }
-
- return tex;
- }
-
- // create a BufferedImage from an Image object
- private BufferedImage createBufferedImage(Image image,
- Component observer) {
-
- int status;
-
- observer.prepareImage(image, null);
- while(true) {
- status = observer.checkImage(image, null);
- if ((status & ImageObserver.ERROR) != 0) {
- return null;
- } else if ((status & ImageObserver.ALLBITS) != 0) {
- break;
- }
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {}
- }
-
- int width = image.getWidth(observer);
- int height = image.getHeight(observer);
-
- WritableRaster wr =
- java.awt.image.Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
- width, height,
- width * 4, 4,
- bandOffset, null);
- BufferedImage bImage = new BufferedImage(colorModel, wr, false, null);
-
- java.awt.Graphics g = bImage.getGraphics();
- g.drawImage(image, 0, 0, observer);
-
- return bImage;
- }
-
- /**
- * Choose the correct ImageComponent and Texture format for the given
- * image
- */
- private void chooseFormat(BufferedImage image) {
- switch (image.getType()) {
- case BufferedImage.TYPE_4BYTE_ABGR :
- case BufferedImage.TYPE_INT_ARGB :
- imageComponentFormat = ImageComponent.FORMAT_RGBA;
- textureFormat = Texture.RGBA;
- break;
- case BufferedImage.TYPE_3BYTE_BGR :
- case BufferedImage.TYPE_INT_BGR:
- case BufferedImage.TYPE_INT_RGB:
- imageComponentFormat = ImageComponent.FORMAT_RGB;
- textureFormat = Texture.RGB;
- break;
- case BufferedImage.TYPE_CUSTOM:
- if (is4ByteRGBAOr3ByteRGB(image)) {
- SampleModel sm = image.getSampleModel();
- if (sm.getNumBands() == 3) {
- //System.out.println("ChooseFormat Custom:TYPE_4BYTE_ABGR");
- imageComponentFormat = ImageComponent.FORMAT_RGB;
- textureFormat = Texture.RGB;
- }
- else {
- imageComponentFormat = ImageComponent.FORMAT_RGBA;
- //System.out.println("ChooseFormat Custom:TYPE_3BYTE_BGR");
- textureFormat = Texture.RGBA;
- }
- }
- break;
- default :
- // System.err.println("Unoptimized Image Type "+image.getType());
- imageComponentFormat = ImageComponent.FORMAT_RGBA;
- textureFormat = Texture.RGBA;
- break;
- }
- }
-
- private boolean is4ByteRGBAOr3ByteRGB(RenderedImage ri) {
- boolean value = false;
- int i;
- int biType = getImageType(ri);
- if (biType != BufferedImage.TYPE_CUSTOM)
- return false;
- ColorModel cm = ri.getColorModel();
- ColorSpace cs = cm.getColorSpace();
- SampleModel sm = ri.getSampleModel();
- boolean isAlphaPre = cm.isAlphaPremultiplied();
- int csType = cs.getType();
- if ( csType == ColorSpace.TYPE_RGB) {
- int numBands = sm.getNumBands();
- if (sm.getDataType() == DataBuffer.TYPE_BYTE) {
- if (cm instanceof ComponentColorModel &&
- sm instanceof PixelInterleavedSampleModel) {
- PixelInterleavedSampleModel csm =
- (PixelInterleavedSampleModel) sm;
- int[] offs = csm.getBandOffsets();
- ComponentColorModel ccm = (ComponentColorModel)cm;
- int[] nBits = ccm.getComponentSize();
- boolean is8Bit = true;
- for (i=0; i < numBands; i++) {
- if (nBits[i] != 8) {
- is8Bit = false;
- break;
- }
- }
- if (is8Bit &&
- offs[0] == 0 &&
- offs[1] == 1 &&
- offs[2] == 2) {
- if (numBands == 3) {
- value = true;
- }
- else if (offs[3] == 3 && !isAlphaPre) {
- value = true;
- }
- }
- }
- }
- }
- return value;
- }
-
- private int getImageType(RenderedImage ri) {
- int imageType = BufferedImage.TYPE_CUSTOM;
- int i;
-
- if (ri instanceof BufferedImage) {
- return ((BufferedImage)ri).getType();
- }
- ColorModel cm = ri.getColorModel();
- ColorSpace cs = cm.getColorSpace();
- SampleModel sm = ri.getSampleModel();
- int csType = cs.getType();
- boolean isAlphaPre = cm.isAlphaPremultiplied();
- if ( csType != ColorSpace.TYPE_RGB) {
- if (csType == ColorSpace.TYPE_GRAY &&
- cm instanceof ComponentColorModel) {
- if (sm.getDataType() == DataBuffer.TYPE_BYTE) {
- imageType = BufferedImage.TYPE_BYTE_GRAY;
- } else if (sm.getDataType() == DataBuffer.TYPE_USHORT) {
- imageType = BufferedImage.TYPE_USHORT_GRAY;
- }
- }
- }
- // RGB , only interested in BYTE ABGR and BGR for now
- // all others will be copied to a buffered image
- else {
- int numBands = sm.getNumBands();
- if (sm.getDataType() == DataBuffer.TYPE_BYTE) {
- if (cm instanceof ComponentColorModel &&
- sm instanceof PixelInterleavedSampleModel) {
- PixelInterleavedSampleModel csm =
- (PixelInterleavedSampleModel) sm;
- int[] offs = csm.getBandOffsets();
- ComponentColorModel ccm = (ComponentColorModel)cm;
- int[] nBits = ccm.getComponentSize();
- boolean is8Bit = true;
- for (i=0; i < numBands; i++) {
- if (nBits[i] != 8) {
- is8Bit = false;
- break;
- }
- }
- if (is8Bit &&
- offs[0] == numBands-1 &&
- offs[1] == numBands-2 &&
- offs[2] == numBands-3) {
- if (numBands == 3) {
- imageType = BufferedImage.TYPE_3BYTE_BGR;
- }
- else if (offs[3] == 0) {
- imageType = (isAlphaPre
- ? BufferedImage.TYPE_4BYTE_ABGR_PRE
- : BufferedImage.TYPE_4BYTE_ABGR);
- }
- }
- }
- }
- }
- return imageType;
- }
-
- // initialize appropriate format for ImageComponent and Texture
- private void parseFormat(String format) {
- if (format==null)
- return;
-
- if (format.equals("RGBA")) {
- imageComponentFormat = ImageComponent.FORMAT_RGBA;
- textureFormat = Texture.RGBA;
-
- } else if (format.equals("RGBA4")) {
- imageComponentFormat = ImageComponent.FORMAT_RGBA4;
- textureFormat = Texture.RGBA;
-
- } else if (format.equals("RGB5_A1")) {
- imageComponentFormat = ImageComponent.FORMAT_RGB5_A1;
- textureFormat = Texture.RGBA;
-
- } else if (format.equals("RGB")) {
- imageComponentFormat = ImageComponent.FORMAT_RGB;
- textureFormat = Texture.RGB;
-
- } else if (format.equals("RGB4")) {
- imageComponentFormat = ImageComponent.FORMAT_RGB4;
- textureFormat = Texture.RGB;
-
- } else if (format.equals("RGB5")) {
- imageComponentFormat = ImageComponent.FORMAT_RGB5;
- textureFormat = Texture.RGB;
-
- } else if (format.equals("R3_G3_B2")) {
- imageComponentFormat = ImageComponent.FORMAT_R3_G3_B2;
- textureFormat = Texture.RGB;
-
- } else if (format.equals("LUM8_ALPHA8")) {
- imageComponentFormat = ImageComponent.FORMAT_LUM8_ALPHA8;
- textureFormat = Texture.LUMINANCE_ALPHA;
-
- } else if (format.equals("LUM4_ALPHA4")) {
- imageComponentFormat = ImageComponent.FORMAT_LUM4_ALPHA4;
- textureFormat = Texture.LUMINANCE_ALPHA;
-
- } else if (format.equals("LUMINANCE")) {
- imageComponentFormat = ImageComponent.FORMAT_CHANNEL8;
- textureFormat = Texture.LUMINANCE;
-
- } else if (format.equals("ALPHA")) {
- imageComponentFormat = ImageComponent.FORMAT_CHANNEL8;
- textureFormat = Texture.ALPHA;
- }
- }
-
- // return a scaled image of given width and height
- private BufferedImage getScaledImage(BufferedImage origImage,
- int width, int height) {
-
- int origW = origImage.getWidth();
- int origH = origImage.getHeight();
- float xScale = (float)width/(float)origW;
- float yScale = (float)height/(float)origH;
-
- return (getScaledImage(origImage, xScale, yScale));
- }
-
- // return a scaled image of given x and y scale
- private BufferedImage getScaledImage(BufferedImage origImage,
- float xScale, float yScale) {
-
-
- // System.err.println("(1) origImage " + origImage);
- // If the image is already the requested size, no need to scale
- if (xScale == 1.0f && yScale == 1.0f)
- return origImage;
- else {
- int scaleW = (int)(origImage.getWidth() * xScale + 0.5);
- int scaleH = (int)(origImage.getHeight() * yScale + 0.5);
-
- int origImageType = origImage.getType();
- BufferedImage scaledImage;
- WritableRaster wr;
-
- if (origImageType != BufferedImage.TYPE_CUSTOM) {
- WritableRaster origWr = origImage.getRaster();
- wr = origWr.createCompatibleWritableRaster(0, 0, scaleW, scaleH);
- scaledImage = new BufferedImage(scaleW, scaleH, origImageType);
- } else {
- int numComponents = origImage.getSampleModel().getNumBands();
- int[] bandOffset = new int[numComponents];
- int[] nBits = new int[numComponents];
- for (int ii=0; ii < numComponents; ii++) {
- bandOffset[ii] = ii;
- nBits[ii] = 8;
- }
-
- wr = java.awt.image.Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
- scaleW, scaleH,
- scaleW * numComponents, numComponents,
- bandOffset, null);
-
- int imageType;
-
- switch (numComponents) {
- case 1:
- imageType = BufferedImage.TYPE_BYTE_GRAY;
- break;
- case 3:
- imageType = BufferedImage.TYPE_3BYTE_BGR;
- break;
- case 4:
- imageType = BufferedImage.TYPE_4BYTE_ABGR;
- break;
- default:
- throw new ImageException("Illegal number of bands : " + numComponents);
-
- }
-
- scaledImage = new BufferedImage(scaleW, scaleH, imageType);
- }
-
- scaledImage.setData(wr);
- java.awt.Graphics2D g2 = scaledImage.createGraphics();
- AffineTransform at = AffineTransform.getScaleInstance(xScale,
- yScale);
- g2.transform(at);
- g2.drawImage(origImage, 0, 0, null);
-
- return scaledImage;
- }
- }
-
- private int computeLog(int value) {
- int i = 0;
-
- if (value == 0) return -1;
- for (;;) {
- if (value == 1)
- return i;
- value >>= 1;
- i++;
- }
- }
-
- private int getClosestPowerOf2(int value) {
-
- if (value < 1)
- return value;
-
- int powerValue = 1;
- for (;;) {
- powerValue *= 2;
- if (value < powerValue) {
- // Found max bound of power, determine which is closest
- int minBound = powerValue/2;
- if ((powerValue - value) >
- (value - minBound))
- return minBound;
- else
- return powerValue;
- }
- }
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/image/package.html b/src/classes/share/com/sun/j3d/utils/image/package.html
deleted file mode 100644
index e32c5d8..0000000
--- a/src/classes/share/com/sun/j3d/utils/image/package.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- *
- * PickCanvas pickCanvas = new PickCanvas(canvas, scene);
- * pickCanvas.setMode(PickInfo.PICK_GEOMETRY);
- * pickCanvas.setFlags(PickInfo.NODE | PickInfo.CLOSEST_INTERSECTION_POINT);
- * pickCanvas.setTolerance(4.0f);
- *
- *
- * pickCanvas.setShapeLocation(mouseEvent);
- * PickInfo[] pickInfos = pickCanvas.pickAll();
- *
com.sun.j3d.utils.geometry.Primitive)
.
- * For example, the intersection would indicate which triangle out of a
- * triangle strip was intersected.
- * The methods which return primitive data will have one value if the primitive
- * is
- * a point, two values if the primitive is a line, three values if the primitive
- * is a triangle and four values if the primitive is quad.
- *
- *
- * Vector3f getNormal(PickIntersection pi, int vertexIndex) {
- * int index;
- * Vector3d normal = new Vector3f();
- * GeometryArray ga = pickIntersection.getGeometryArray();
- * if (pickIntersection.geometryIsIndexed()) {
- * index = ga.getNormalIndex(vertexIndex);
- * } else {
- * index = vertexIndex;
- * }
- * ga.getNormal(index, normal);
- * return normal;
- * }
- *
- *
- *
- *
- * PickInfo.SCENEGRAPHPATH
- request for computed SceneGraphPath.
- * PickInfo.NODE
- request for computed intersected Node.
- * PickInfo.LOCAL_TO_VWORLD
- request for computed local to virtual world transform.
- * PickInfo.CLOSEST_INTERSECTION_POINT
- request for closest intersection point.
- * PickInfo.CLOSEST_DISTANCE
- request for the distance of closest intersection.
- * PickInfo.CLOSEST_GEOM_INFO
- request for only the closest intersection geometry information.
- * PickInfo.ALL_GEOM_INFO
- request for all intersection geometry information.
- * getNode(int)
- * to return a
- * Shape3D
node from
- * the SceneGraphPath
.
- */
- public static final int TYPE_SHAPE3D = 0x1;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * Morph
node from
- * the SceneGraphPath
.
- */
- public static final int TYPE_MORPH = 0x2;
-
- /**
- * Flag to pass to
- * getNode(int)
-
- * to return a
- * Primitive
node from
- * the SceneGraphPath
.
- */
- public static final int TYPE_PRIMITIVE = 0x4;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * Link
node from
- * the SceneGraphPath
.
- */
- public static final int TYPE_LINK = 0x8;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * Group
node from
- * the SceneGraphPath
.
- */
- public static final int TYPE_GROUP = 0x10;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * TransformGroup
node from
- * the SceneGraphPath
.
- */
- public static final int TYPE_TRANSFORM_GROUP = 0x20;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * BranchGroup
node from
- * the SceneGraphPath
.
- */
- public static final int TYPE_BRANCH_GROUP = 0x40;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * Switch
node from
- * the SceneGraphPath
.
- */
- public static final int TYPE_SWITCH = 0x80;
-
-
- private static final int ALL_FLAGS =
- PickInfo.SCENEGRAPHPATH |
- PickInfo.NODE |
- PickInfo.LOCAL_TO_VWORLD |
- PickInfo.CLOSEST_INTERSECTION_POINT |
- PickInfo.CLOSEST_DISTANCE |
- PickInfo.CLOSEST_GEOM_INFO |
- PickInfo.ALL_GEOM_INFO;
-
- private final boolean debug = false;
- protected boolean userDefineShape = false;
-
- PickShape pickShape;
-
- /** Used to store the BranchGroup used for picking */
- BranchGroup pickRootBG = null;
- /** Used to store the Locale used for picking */
- Locale pickRootL = null;
-
- /** Used to store a reference point used in determining how "close" points
- are.
- */
- Point3d start = null;
-
- int mode = PickInfo.PICK_BOUNDS;
- int flags = PickInfo.NODE;
-
- /* ============================ METHODS ============================ */
-
- /**
- * Constructor with BranchGroup to be picked.
- */
- public PickTool (BranchGroup b) {
- pickRootBG = b;
- }
-
- /**
- * Constructor with the Locale to be picked.
- */
- public PickTool (Locale l) {
- pickRootL = l;
- }
-
- /** Returns the BranchGroup to be picked if the tool was initialized
- with a BranchGroup, null otherwise.
- */
- public BranchGroup getBranchGroup() {
- return pickRootBG;
- }
-
- /**
- * Returns the Locale to be picked if the tool was initialized with
- * a Locale, null otherwise.
- */
- public Locale getLocale () {
- return pickRootL;
- }
-
- // Methods used to define the pick shape
-
- /** Sets the pick shape to a user-provided PickShape object
- * @param ps The pick shape to pick against.
- * @param startPt The start point to use for distance calculations
- */
- public void setShape (PickShape ps, Point3d startPt) {
- this.pickShape = ps;
- this.start = startPt;
- userDefineShape = (ps != null);
- }
-
- /** Sets the pick shape to use a user-provided Bounds object
- * @param bounds The bounds to pick against.
- * @param startPt The start point to use for distance calculations
- */
- public void setShapeBounds (Bounds bounds, Point3d startPt) {
- this.pickShape = (PickShape) new PickBounds (bounds);
- this.start = startPt;
- userDefineShape = true;
- }
-
- /** Sets the picking detail mode. The default is PickInfo.PICK_BOUNDS.
- * @param mode One of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY.
- * @exception IllegalArgumentException if mode is not a legal value
- */
- public void setMode (int mode) {
- if ((mode != PickInfo.PICK_BOUNDS) && (mode != PickInfo.PICK_GEOMETRY)) {
- throw new java.lang.IllegalArgumentException();
- }
- this.mode = mode;
- }
-
- /** Gets the picking detail mode.
- */
- public int getMode () {
- return mode;
- }
-
- /** Sets the PickInfo content flags. The default is PickInfo.NODE.
- * @param flags specified as one or more individual bits that are
- * bitwise "OR"ed together :
- *
- *
- * @exception IllegalArgumentException if any other bits besides the above are set.
- */
- public void setFlags (int flags) {
- if ((flags & ~ALL_FLAGS) != 0) {
- throw new java.lang.IllegalArgumentException();
- }
- this.flags = flags;
- }
-
- /** Gets the PickInfo content flags.
- */
- public int getFlags () {
- return flags;
- }
-
- /** Sets the pick shape to a PickRay.
- * @param start The start of the ray
- * @param dir The direction of the ray
- */
- public void setShapeRay (Point3d start, Vector3d dir) {
- this.pickShape = (PickShape) new PickRay (start, dir);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Sets the pick shape to a PickSegment.
- @param start The start of the segment
- @param end The end of the segment
- */
- public void setShapeSegment (Point3d start, Point3d end) {
- this.pickShape = (PickShape) new PickSegment (start, end);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Sets the pick shape to a capped PickCylinder
- * @param start The start of axis of the cylinder
- * @param end The end of the axis of the cylinder
- * @param radius The radius of the cylinder
- */
- public void setShapeCylinderSegment (Point3d start, Point3d end,
- double radius) {
- this.pickShape = (PickShape)
- new PickCylinderSegment (start, end, radius);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Sets the pick shape to an infinite PickCylinder.
- * @param start The start of axis of the cylinder
- * @param dir The direction of the axis of the cylinder
- * @param radius The radius of the cylinder
- */
- public void setShapeCylinderRay (Point3d start, Vector3d dir,
- double radius) {
- this.pickShape = (PickShape) new PickCylinderRay (start, dir, radius);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Sets the pick shape to a capped PickCone
- * @param start The start of axis of the cone
- * @param end The end of the axis of the cone
- * @param angle The angle of the cone
- */
- public void setShapeConeSegment (Point3d start, Point3d end,
- double angle) {
- this.pickShape = (PickShape) new PickConeSegment (start, end, angle);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Sets the pick shape to an infinite PickCone.
- * @param start The start of axis of the cone
- * @param dir The direction of the axis of the cone
- * @param angle The angle of the cone
- */
- public void setShapeConeRay (Point3d start, Vector3d dir,
- double angle) {
- this.pickShape = (PickShape) new PickConeRay (start, dir, angle);
- this.start = start;
- userDefineShape = true;
- }
-
- /** Returns the PickShape for this object. */
- public PickShape getPickShape () {
- return pickShape;
- }
-
- /** Returns the start postion used for distance measurement. */
- public Point3d getStartPosition () {
- return start;
- }
-
- /** Selects all the nodes that intersect the PickShape.
- @return An array of PickInfo.SCENEGRAPHPATH
- request for computed SceneGraphPath.
- * PickInfo.NODE
- request for computed intersected Node.
- * PickInfo.LOCAL_TO_VWORLD
- request for computed local to virtual world transform.
- * PickInfo.CLOSEST_INTERSECTION_POINT
- request for closest intersection point.
- * PickInfo.CLOSEST_DISTANCE
- request for the distance of closest intersection.
- * PickInfo.CLOSEST_GEOM_INFO
- request for only the closest intersection geometry information.
- * PickInfo.ALL_GEOM_INFO
- request for all intersection geometry information.
- * PickInfo
objects which will contain
- information about the picked instances. null
if nothing was
- picked.
- */
- public PickInfo[] pickAll () {
- PickInfo[] pickInfos = null;
- if (pickRootBG != null) {
- pickInfos = pickRootBG.pickAll(mode, flags, pickShape);
- } else if (pickRootL != null) {
- pickInfos = pickRootL.pickAll(mode, flags, pickShape);
- }
- return pickInfos;
- }
-
- /** Select one of the nodes that intersect the PickShape
- @return A PickInfo
object which will contain
- information about the picked instance. null
if nothing
- was picked.
- */
- public PickInfo pickAny () {
- PickInfo pickInfo = null;
- if (pickRootBG != null) {
- pickInfo = pickRootBG.pickAny(mode, flags, pickShape);
- } else if (pickRootL != null) {
- pickInfo = pickRootL.pickAny(mode, flags, pickShape);
- }
- return pickInfo;
- }
-
- /** Select all the nodes that intersect the
- PickShape, returned sorted. The "closest" object will be returned first.
- See note above to see how "closest" is determined.
- PickInfo
objects which will contain
- information
- about the picked instances. null
if nothing was picked.
- */
- public PickInfo[] pickAllSorted () {
- PickInfo[] pickInfos = null;
- if (pickRootBG != null) {
- pickInfos = pickRootBG.pickAllSorted(mode, flags, pickShape);
- } else if (pickRootL != null) {
- pickInfos = pickRootL.pickAllSorted(mode, flags, pickShape);
- }
- return pickInfos;
- }
-
- /** Select the closest node that
- intersects the PickShape. See note above to see how "closest" is
- determined.
- PickInfo
object which will contain
- information about the picked instance. null
if nothing
- was picked.
- */
- public PickInfo pickClosest () {
- // System.out.println("PickTool : pickClosest ...");
- PickInfo pickInfo = null;
- if (pickRootBG != null) {
- pickInfo = pickRootBG.pickClosest(mode, flags, pickShape);
- } else if (pickRootL != null) {
- pickInfo = pickRootL.pickClosest(mode, flags, pickShape);
- }
- // System.out.println(" -- pickInfo is " + pickInfo);
-
- return pickInfo;
- }
-
- /** Get the first node of a certain type up the SceneGraphPath
- *@param type the type of node we are interested in
- *@return a Node object
- *
- * @exception NullPointerException if pickInfo does not contain a
- * Scenegraphpath or a picked node
- */
-
- public Node getNode (PickInfo pickInfo, int type) {
-
- // System.out.println("pickInfo is " + pickInfo);
-
- if (pickInfo == null) {
- return null;
- }
-
- SceneGraphPath sgp = pickInfo.getSceneGraphPath();
- Node pickedNode = pickInfo.getNode();
- // System.out.println("sgp = " + sgp + " pickedNode = " + pickedNode);
-
-
- /*
- * Do not check for null for pickNode and sgp.
- * Will throw NPE if pickedNode or sgp isn't set in pickInfo
- */
-
- if ((pickedNode instanceof Shape3D) && ((type & TYPE_SHAPE3D) != 0)){
- if (debug) System.out.println("Shape3D found");
- return pickedNode;
- }
- else if ((pickedNode instanceof Morph) && ((type & TYPE_MORPH) != 0)){
- if (debug) System.out.println("Morph found");
- return pickedNode;
- }
- else {
- for (int j=sgp.nodeCount()-1; j>=0; j--){
- Node pNode = sgp.getNode(j);
- if (debug) System.out.println("looking at node " + pNode);
-
- if ((pNode instanceof Primitive) &&
- ((type & TYPE_PRIMITIVE) != 0)){
- if (debug) System.out.println("Primitive found");
- return pNode;
- }
- else if ((pNode instanceof Link) && ((type & TYPE_LINK) != 0)){
- if (debug) System.out.println("Link found");
- return pNode;
- }
- else if ((pNode instanceof Switch) && ((type & TYPE_SWITCH) != 0)){
- if (debug) System.out.println("Switch found");
- return pNode;
- }
- else if ((pNode instanceof TransformGroup) &&
- ((type & TYPE_TRANSFORM_GROUP) != 0)){
- if (debug) System.out.println("xform group found");
- return pNode;
- }
- else if ((pNode instanceof BranchGroup) &&
- ((type & TYPE_BRANCH_GROUP) != 0)){
- if (debug) System.out.println("Branch group found");
- return pNode;
- }
- else if ((pNode instanceof Group) && ((type & TYPE_GROUP) != 0)){
- if (debug) System.out.println("Group found");
- return pNode;
- }
- }
- }
- return null; // should not be reached
- }
-
-
-} // PickTool
-
-
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickMouseBehavior.java b/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickMouseBehavior.java
deleted file mode 100644
index 4cfdaa8..0000000
--- a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickMouseBehavior.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.pickfast.behaviors;
-
-import java.awt.AWTEvent;
-import java.awt.Event;
-import java.awt.event.MouseEvent;
-import java.util.Enumeration;
-
-import javax.media.j3d.Behavior;
-import javax.media.j3d.Bounds;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.TransformGroup;
-import javax.media.j3d.WakeupCriterion;
-import javax.media.j3d.WakeupOnAWTEvent;
-import javax.media.j3d.WakeupOr;
-
-import com.sun.j3d.utils.pickfast.PickCanvas;
-import com.sun.j3d.utils.pickfast.PickTool;
-
-
-/**
- * Base class that allows users to adding picking and mouse manipulation to
- * the scene graph (see PickDragBehavior for an example of how to extend
- * this base class). This class is useful for interactive apps.
- */
-
-public abstract class PickMouseBehavior extends Behavior {
-
- protected PickCanvas pickCanvas;
-
- protected WakeupCriterion[] conditions;
- protected WakeupOr wakeupCondition;
- protected boolean buttonPress = false;
-
- protected TransformGroup currGrp;
- protected static final boolean debug = false;
- protected MouseEvent mevent;
-
- /**
- * Creates a PickMouseBehavior given current canvas, root of the tree to
- * operate on, and the bounds.
- */
- public PickMouseBehavior(Canvas3D canvas, BranchGroup root, Bounds bounds){
- super();
- currGrp = new TransformGroup();
- currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
- currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
- root.addChild(currGrp);
- pickCanvas = new PickCanvas(canvas, root);
- }
-
- /**
- * Sets the pick mode
- * @see PickTool#setMode
- **/
- public void setMode(int pickMode) {
- pickCanvas.setMode(pickMode);
- }
-
- /**
- * Returns the pickMode
- * @see PickTool#getMode
- */
-
- public int getMode() {
- return pickCanvas.getMode();
- }
-
- /**
- * Sets the pick tolerance
- * @see PickCanvas#setTolerance
- */
- public void setTolerance(float tolerance) {
- pickCanvas.setTolerance(tolerance);
- }
-
- /**
- * Returns the pick tolerance
- * @see PickCanvas#getTolerance
- */
- public float getTolerance() {
- return pickCanvas.getTolerance();
- }
-
- @Override
- public void initialize() {
-
- conditions = new WakeupCriterion[2];
- conditions[0] = new WakeupOnAWTEvent(Event.MOUSE_MOVE);
- conditions[1] = new WakeupOnAWTEvent(Event.MOUSE_DOWN);
- wakeupCondition = new WakeupOr(conditions);
-
- wakeupOn(wakeupCondition);
- }
-
- private void processMouseEvent(MouseEvent evt) {
- buttonPress = false;
-
- if (evt.getID()==MouseEvent.MOUSE_PRESSED |
- evt.getID()==MouseEvent.MOUSE_CLICKED) {
- buttonPress = true;
- return;
- }
- else if (evt.getID() == MouseEvent.MOUSE_MOVED) {
- // Process mouse move event
- }
- }
-
- @Override
- public void processStimulus (Enumeration criteria) {
- WakeupCriterion wakeup;
- AWTEvent[] evt = null;
- int xpos = 0, ypos = 0;
-
- while(criteria.hasMoreElements()) {
- wakeup = (WakeupCriterion)criteria.nextElement();
- if (wakeup instanceof WakeupOnAWTEvent)
- evt = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
- }
-
- if (evt[0] instanceof MouseEvent){
- mevent = (MouseEvent) evt[0];
-
- if (debug)
- System.out.println("got mouse event");
- processMouseEvent((MouseEvent)evt[0]);
- xpos = mevent.getPoint().x;
- ypos = mevent.getPoint().y;
- }
-
- if (debug)
- System.out.println("mouse position " + xpos + " " + ypos);
-
- if (buttonPress){
- updateScene(xpos, ypos);
- }
- wakeupOn (wakeupCondition);
- }
-
-
- /** Subclasses shall implement this update function
- */
- public abstract void updateScene(int xpos, int ypos);
-
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickRotateBehavior.java b/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickRotateBehavior.java
deleted file mode 100644
index 62ad8e4..0000000
--- a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/PickRotateBehavior.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.pickfast.behaviors;
-
-import javax.media.j3d.Bounds;
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.PickInfo;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.TransformGroup;
-
-import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
-import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
-import com.sun.j3d.utils.pickfast.PickTool;
-
-/**
- * A mouse behavior that allows user to pick and rotate scene graph objects.
- * Common usage:
- *
- *
- * PickRotateBehavior behavior = new PickRotateBehavior(canvas, root, bounds);
- * root.addChild(behavior);
- *
setupCallback
method.
- * When the picked object moves, the registered object's
- * transformChanged
method is invoked.
- */
-
-public interface PickingCallback {
-
- public final static int ROTATE=0;
- public final static int TRANSLATE=1;
- public final static int ZOOM=2;
-
- /**
- * The user made a selection but nothing was
- * actually picked
- */
- public final static int NO_PICK=3;
-
- /**
- * Called by the Pick Behavior with which this callback
- * is registered each time the Picked object is moved
- */
- public void transformChanged( int type, TransformGroup tg );
-}
diff --git a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/package.html b/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/package.html
deleted file mode 100644
index c401786..0000000
--- a/src/classes/share/com/sun/j3d/utils/pickfast/behaviors/package.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- *
- * PickCanvas pickCanvas = new PickCanvas(canvas, scene);
- * pickCanvas.setMode(PickTool.GEOMETRY_INTERSECT_INFO);
- * pickCanvas.setTolerance(4.0f);
- *
- *
- * pickCanvas.setShapeLocation(mouseEvent);
- * PickResult[] results = pickCanvas.pickAll();
- *
com.sun.j3d.utils.geometry.Primitive)
.
- * For example, the intersection would indicate which triangle out of a
- * triangle strip was intersected.
- * The methods which return primitive data will have one value if the primitive
- * is
- * a point, two values if the primitive is a line, three values if the primitive
- * is a triangle and four values if the primitive is quad.
- *
- *
- * Vector3f getNormal(PickIntersection pi, int vertexIndex) {
- * int index;
- * Vector3d normal = new Vector3f();
- * GeometryArray ga = pickIntersection.getGeometryArray();
- * if (pickIntersection.geometryIsIndexed()) {
- * index = ga.getNormalIndex(vertexIndex);
- * } else {
- * index = vertexIndex;
- * }
- * ga.getNormal(index, normal);
- * return normal;
- * }
- *
PickTool.setCapabilties(Node, int)
- * can be used to set the capability bits
- * to allow this data to be inquired.
- */
-public class PickIntersection {
-
- /* OPEN ISSUES:
- -- Tex coordinates always use texCoordSet == 0.
- */
-
- /* =================== ATTRIBUTES ======================= */
-
-
- // init by constructor:
-
- /** PickResult for intersection is part of */
- PickResult pickResult = null;
-
- // init by intersection:
- /** Distance between start point and intersection point (see comment above)*/
- double distance = -1;
-
- /** index of GeometryArray in PickResult */
- int geomIndex = 0;
-
- /** Indices of the intersected primitive */
- int[] primitiveVertexIndices = null;
-
- /** VWorld coordinates of intersected primitive */
- Point3d[] primitiveCoordinatesVW = null;
-
- /** VWorld Coordinates of the intersection point */
- Point3d pointCoordinatesVW = null;
-
- // Derived data
-
- // Geometry
- GeometryArray geom = null;
- IndexedGeometryArray iGeom = null;
- boolean hasNormals = false;
- boolean hasColors = false;
- boolean hasTexCoords = false;
-
- // Primitive
- /* indices for the different data types */
- int[] primitiveCoordinateIndices;
- int[] primitiveNormalIndices;
- int[] primitiveColorIndices;
- int[] primitiveTexCoordIndices;
-
-
- /* Local coordinates of the intersected primitive */
- Point3d[] primitiveCoordinates = null;
-
- /* Normals of the intersected primitive */
- Vector3f[] primitiveNormals = null;
-
- /* Colors of the intersected primitive */
- Color4f[] primitiveColors = null;
-
- /* TextureCoordinates of the intersected primitive */
- TexCoord3f[] primitiveTexCoords = null;
-
- // Intersection point
-
- /** Local Coordinates of the intersection point */
- Point3d pointCoordinates = null;
-
- /** Normal at the intersection point */
- Vector3f pointNormal = null;
-
- /** Color at the intersection point */
- Color4f pointColor = null;
-
- /** TexCoord at the intersection point */
- TexCoord3f pointTexCoord = null;
-
- // Closest Vertex
- /** Index of the closest vertex */
- int closestVertexIndex = -1;
-
- /** Coordinates of the closest vertex */
- Point3d closestVertexCoordinates = null;
-
- /** Coordinates of the closest vertex (World coordinates) */
- Point3d closestVertexCoordinatesVW = null;
-
- /** Weight factors for interpolation, values correspond to vertex indices,
- * sum == 1
- */
- double[] interpWeights;
-
- static final boolean debug = false;
-
- // Axis constants
- static final int X_AXIS = 1;
- static final int Y_AXIS = 2;
- static final int Z_AXIS = 3;
-
- // Tolerance for numerical stability
- static final double TOL = 1.0e-5;
-
- /* =================== METHODS ======================= */
-
- /** Constructor
- @param pickResult The pickResult this intersection is part of.
- */
- PickIntersection (PickResult pr, GeometryArray geomArr) {
-
- // pr can't be null.
- pickResult = pr;
- geom = geomArr;
- if (geom == null) {
- GeometryArray[] ga = pickResult.getGeometryArrays();
- geom = ga[geomIndex];
-
- }
-
- if (geom instanceof IndexedGeometryArray) {
- iGeom = (IndexedGeometryArray)geom;
- }
- int vertexFormat = geom.getVertexFormat();
- hasColors = (0 != (vertexFormat &
- (GeometryArray.COLOR_3 | GeometryArray.COLOR_4)));
- hasNormals = (0 != (vertexFormat & GeometryArray.NORMALS));
- hasTexCoords = (0 != (vertexFormat &
- (GeometryArray.TEXTURE_COORDINATE_2 |
- GeometryArray.TEXTURE_COORDINATE_3)));
- }
-
- /**
- String representation of this object
- */
- @Override
- public String toString () {
- String rt = new String ("PickIntersection: ");
- rt += " pickResult = "+pickResult + "\n";
- rt += " geomIndex = "+geomIndex + "\n";
- if (distance != -1) rt += " dist:"+distance + "\n";
- if (pointCoordinates != null) rt += " pt:" + pointCoordinates + "\n";
- if (pointCoordinatesVW != null) rt += " ptVW:" + pointCoordinatesVW + "\n";
-
- if (primitiveCoordinateIndices != null) {
- rt += " prim coordinate ind:" + "\n";
- for (int i=0;iPickTool.setCapabilties(Node, int)
- * can
- * be used to ensure correct capabilites are set. Inquiring data which is not
- * available due to capabilties not being set will generate a
- * CapabilityNotSet
exception.
- * getNode(int)
- * to return a
- * Shape3D
node from
- * the SceneGraphPath
.
- */
- public static final int SHAPE3D = 0x1;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * Morph
node from
- * the SceneGraphPath
.
- */
- public static final int MORPH = 0x2;
-
- /**
- * Flag to pass to
- * getNode(int)
-
- * to return a
- * Primitive
node from
- * the SceneGraphPath
.
- */
- public static final int PRIMITIVE = 0x4;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * Link
node from
- * the SceneGraphPath
.
- */
- public static final int LINK = 0x8;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * Group
node from
- * the SceneGraphPath
.
- */
- public static final int GROUP = 0x10;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * TransformGroup
node from
- * the SceneGraphPath
.
- */
- public static final int TRANSFORM_GROUP = 0x20;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * BranchGroup
node from
- * the SceneGraphPath
.
- */
- public static final int BRANCH_GROUP = 0x40;
-
- /**
- * Flag to pass to
- * getNode(int)
- * to return a
- * Switch
node from
- * the SceneGraphPath
.
- */
- public static final int SWITCH = 0x80;
-
-
-
- /* =================== ATTRIBUTES ======================= */
- static boolean debug = false;
-
- /** if true, find only the first intersection */
- private boolean firstIntersectOnly = false;
-
- /** Stored SceneGraphPath */
- private SceneGraphPath pickedSceneGraphPath = null;
-
- /** Picked node: shape3d, text3d, etc. */
- private Node pickedNode = null;
-
- /** GeometryArray(s) of the picked node */
- private GeometryArray[] geometryArrays = null;
-
- /** Shape3Ds from CompressedGeometry on the picked node */
- private Shape3D[] compressGeomShape3Ds = null;
-
- /** Transform to World Coordinates */
- private Transform3D localToVWorld = null;
-
- /** the pick shape to use for intersections */
- private PickShape pickShape = null;
- /* data derived from the pick shape */
- private int pickShapeType = -1;
- private Vector3d pickShapeDir = null;
- private Point3d pickShapeStart = null;
- private Point3d pickShapeEnd = null;
- private Bounds pickShapeBounds = null;
-
- static final Point3d zeroPnt = new Point3d();
-
- /** ArrayList to store intersection results
- * Used in PickTool
- */
- ArrayList intersections = null;
-
- // internal constants used for intersections
- static final double FUZZ = 1E-6; /* fuzziness factor used to determine
- if two lines are parallel */
- static final int PICK_SHAPE_RAY = 1;
- static final int PICK_SHAPE_SEGMENT = 2;
- static final int PICK_SHAPE_POINT = 3;
- static final int PICK_SHAPE_BOUNDING_BOX = 4;
- static final int PICK_SHAPE_BOUNDING_SPHERE = 5;
- static final int PICK_SHAPE_BOUNDING_POLYTOPE = 6;
- static final int PICK_SHAPE_CYLINDER = 7;
- static final int PICK_SHAPE_CONE = 8;
-
- static final double EPS = 1.0e-13;
-
-
- /* =================== METHODS ======================= */
-
- /** Default constructor. */
- PickResult () { }
-
- /** Construct a PickResult using a SceneGraphPath
- @param sgp SceneGraphPath associated with this PickResult
- @param ps The pickShape to intersect against
- */
- public PickResult (SceneGraphPath sgp, PickShape ps) {
- pickedSceneGraphPath = sgp;
- pickedNode = sgp.getObject();
- localToVWorld = sgp.getTransform();
- pickShape = ps;
- initPickShape();
- }
-
-
- /** Construct a PickResult using the Node and localToVWorld transform
- @param pn The picked node.
- @param l2vw The local to VWorld transformation for the node
- @param ps The PickShape to intersect against
- @throws IllegalArgumentException If the node is not a Morph or Shape3D.
- */
- public PickResult (Node pn, Transform3D l2vw, PickShape ps) {
- if ((pn instanceof Shape3D) || (pn instanceof Morph)) {
- pickedNode = pn;
- localToVWorld = l2vw;
- pickShape = ps;
- initPickShape();
- } else {
- throw new IllegalArgumentException();
- }
- }
-
- void initPickShape() {
- if(pickShape instanceof PickRay) {
- if (pickShapeStart == null) pickShapeStart = new Point3d();
- if (pickShapeDir == null) pickShapeDir = new Vector3d();
- ((PickRay) pickShape).get (pickShapeStart, pickShapeDir);
- pickShapeType = PICK_SHAPE_RAY;
- } else if (pickShape instanceof PickSegment) {
- if (pickShapeStart == null) pickShapeStart = new Point3d();
- if (pickShapeEnd == null) pickShapeEnd = new Point3d();
- if (pickShapeDir == null) pickShapeDir = new Vector3d();
- ((PickSegment)pickShape).get(pickShapeStart, pickShapeEnd);
- pickShapeDir.set (pickShapeEnd.x - pickShapeStart.x,
- pickShapeEnd.y - pickShapeStart.y,
- pickShapeEnd.z - pickShapeStart.z);
- pickShapeType = PICK_SHAPE_SEGMENT;
- } else if (pickShape instanceof PickBounds) {
- pickShapeBounds = ((PickBounds) pickShape).get();
- if ( pickShapeBounds instanceof BoundingBox )
- pickShapeType = PICK_SHAPE_BOUNDING_BOX;
- else if( pickShapeBounds instanceof BoundingSphere )
- pickShapeType = PICK_SHAPE_BOUNDING_SPHERE;
- else if( pickShapeBounds instanceof BoundingPolytope )
- pickShapeType = PICK_SHAPE_BOUNDING_POLYTOPE;
- } else if(pickShape instanceof PickPoint) {
- throw new RuntimeException ("PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance.");
- } else if (pickShape instanceof PickCylinder) {
- pickShapeType = PICK_SHAPE_CYLINDER;
- } else if (pickShape instanceof PickCone) {
- pickShapeType = PICK_SHAPE_CONE;
- } else {
- throw new
- RuntimeException("PickShape not supported for intersection");
- }
- }
-
- /** Get the SceneGraphPath. This will be null if the non SceneGraphPath
- * constructor was used.
- */
- public SceneGraphPath getSceneGraphPath() {
- /* Q: should this return a copy */
- return pickedSceneGraphPath;
- }
-
-
- /** Get the localToVworld transform for the Node
- */
- public Transform3D getLocalToVworld() {
- return localToVWorld;
- }
-
- /** Get the GeometryArray at index 0 for the picked node
- */
- public GeometryArray getGeometryArray() {
- if (geometryArrays == null) {
- storeGeometry();
- }
- return geometryArrays[0];
- }
-
- /** Get the array of GeometryArrays for the picked node
- */
- public GeometryArray[] getGeometryArrays() {
- if (geometryArrays == null) {
- storeGeometry();
- }
- return geometryArrays;
- }
-
- /** Get the number of GeometryArrays for the picked node
- */
- public int numGeometryArrays() {
- if (geometryArrays == null) {
- storeGeometry();
- }
- return geometryArrays.length;
- }
-
- /** Get the number of Shape3Ds that came from decompressing a
- CompressedGeometry on the picked node.
- */
- public int numCompressedGeometryShape3Ds() {
- if (geometryArrays == null) {
- storeGeometry();
- }
- if (compressGeomShape3Ds == null) {
- return 0;
- } else {
- return compressGeomShape3Ds.length;
- }
- }
-
- /** Get the array of Shape3Ds that came from decompressing a
- CompressedGeometry on the picked node.
- */
- public Shape3D[] getCompressedGeometryShape3Ds() {
- if (geometryArrays == null) {
- storeGeometry();
- }
- if (compressGeomShape3Ds == null) {
- return null;
- } else {
- return compressGeomShape3Ds;
- }
- }
-
- /** Get the PickShape used for intersections
- */
- public PickShape getPickShape() {
- return pickShape;
- }
-
- /** Set the PickResult to find only the first intersection of the PickShape
- * with the Node. The default is false
(all intersections are
- * found)
- */
- public void setFirstIntersectOnly(boolean flag) {
- firstIntersectOnly = flag;
- }
-
- /** Return the "first intersection only" value. */
- public boolean getFirstPickEnable() {
- return firstIntersectOnly;
- }
-
- /** Returns the number of PickIntersections in the PickResult.
- @return the number of intersections
- */
- public int numIntersections () {
- if (intersections == null) {
- generateIntersections();
- }
- return intersections.size();
- }
-
- /** Returns a specific PickIntersection object
- @param index the index number
- @return the PickIntersection referenced by the index number
- */
- public PickIntersection getIntersection (int index) {
- if (intersections == null) {
- generateIntersections();
- }
- return (PickIntersection) intersections.get (index);
- }
-
- /** Gets the PickIntersection in this PickResult that is closest to a point
- @param pt the point to use for distance calculations
- @return the closest PickIntersection object
- */
- public PickIntersection getClosestIntersection (Point3d pt) {
- PickIntersection pi = null;
- PickIntersection curPi = null;
- Point3d curPt = null;
- double minDist = Double.MAX_VALUE;
- double curDist = 0.0;
-
- if (pt == null) return null;
-
- if (intersections == null) {
- generateIntersections();
- }
-
- for (int i=0;i
- *
- * PickTool.setCapabilities(Node, int)
- * can be used before the scene graph is
- * made live to set the
- * capabilities of Shape3D, Morph or Geometry
- * nodes to allow picking.
- * setCapabilities(Node, int)
to set
- * the Node's capabilities to allow intersection tests, but not
- * inquire information about the intersections (use for GEOMETRY mode).
- * @see PickTool#setCapabilities
- */
- public static final int INTERSECT_TEST = 0x1001;
-
- /**
- * Flag to pass to
setCapabilities(Node, int)
to set
- * the Node's capabilities to allow inquiry of the intersection
- * coordinate information.
- * @see PickTool#setCapabilities
- */
- public static final int INTERSECT_COORD = 0x1002;
-
- /**
- * Flag to pass to
setCapabilities(Node, int)
- *
- * Only nodes (not nodeComponents) affect intergraph dependencies
- */
- private void addInterGraphDependency( SymbolTableData symbol ) {
- HashSet set = (HashSet)branchGraphDependencies.get( currentBranchGraphID );
- if (set==null) {
- set = new HashSet();
- branchGraphDependencies.set( currentBranchGraphID, set );
- }
-
- set.add(symbol);
- }
-
- /**
- * Update the reference count for the node component.
- *
- * Called during NodeComponentState.addSubReference()
- */
- public void incNodeComponentRefCount( int nodeID ) {
- if (nodeID==0) return;
-
- SymbolTableData symbol = getSymbol( nodeID );
-
- ((NodeComponentState)symbol.nodeState).addSubReference();
-
- if (symbol.referenceCount==1)
- sharedNodes.add( symbol );
- symbol.referenceCount++;
- }
-
- /**
- * Add a refernce to the specified node
- * Also returns the nodes id
- */
- @Override
- public int addReference( SceneGraphObject node ) {
- if (node==null) return 0;
-
- SymbolTableData symbol = getSymbol( node );
-
- if (symbol==null) {
- if (node instanceof javax.media.j3d.Node) {
- symbol = createDanglingSymbol( node );
- if (symbol.branchGraphID != currentBranchGraphID ) {
- //System.out.println("------------- Adding Reference "+symbol.nodeID+" "+node ); // TODO - remove
- addInterGraphDependency( symbol );
- sharedNodes.add( symbol );
- }
- } else {
- symbol = createNodeComponentSymbol( node );
- }
- return symbol.nodeID;
- } else {
- return addReference( symbol );
- }
- }
-
- /**
- * Add a refernce to the specified node
- * Also returns the nodes id
- */
- public int addReference( SymbolTableData symbol ) {
-
- if (symbol!=null) {
- if (symbol.referenceCount==1)
- sharedNodes.add( symbol );
- symbol.referenceCount++;
-
- if (symbol.j3dNode instanceof javax.media.j3d.NodeComponent && symbol.referenceCount>1) {
- ((NodeComponentState)symbol.nodeState).addSubReference();
- }
-
- if (symbol.branchGraphID != currentBranchGraphID &&
- symbol.j3dNode instanceof javax.media.j3d.Node ) {
- // System.out.println("------------- Adding Reference "+symbol.nodeID+" "+symbol.j3dNode ); // TODO - remove
- addInterGraphDependency( symbol );
- }
- } else {
- throw new SGIORuntimeException("Null Symbol");
- }
-
- return symbol.nodeID;
- }
-
- /**
- * Add a refernce to the BranchGraph root
- * Also returns the nodes id
- *
- * Used to associate graphs with a locale without storing the graph at the
- * current time.
- */
- public int addBranchGraphReference( SceneGraphObject node, int branchGraphID ) {
- if (node==null) return 0;
-
- SymbolTableData symbol = getSymbol( node );
-
- if (symbol!=null) {
- if (symbol.referenceCount==1)
- sharedNodes.add( symbol );
- symbol.referenceCount++;
- } else {
- symbol = new SymbolTableData( nodeID++, node, null, -3 );
- j3dNodeIndex.put( node, symbol );
- nodeIDIndex.add( symbol );
- danglingReferences.put( node, symbol );
- }
-
- symbol.branchGraphID = branchGraphID;
- for(int i=branchGraphs.size(); i to set
- * the Node's capabilities to allow inquiry of all intersection
- * information.
- * @see PickTool#setCapabilities
- */
- public static final int INTERSECT_FULL = 0x1004;
-
- /* ============================ METHODS ============================ */
-
- /**
- * Constructor with BranchGroup to be picked.
- */
- public PickTool (BranchGroup b) {
- pickRootBG = b;
- }
-
- /** Returns the BranchGroup to be picked if the tool was initialized
- with a BranchGroup, null otherwise.
- */
- public BranchGroup getBranchGroup() {
- return pickRootBG;
- }
-
- /**
- * Constructor with the Locale to be picked.
- */
- public PickTool (Locale l) {
- pickRootL = l;
- }
-
- /**
- * Returns the Locale to be picked if the tool was initialized with
- * a Locale, null otherwise.
- */
- public Locale getLocale () {
- return pickRootL;
- }
-
-
- /**
- * @deprecated This method does nothing other than return its
- * input parameter.
- */
- public Locale setBranchGroup (Locale l) {
- return l;
- }
-
- /**
- * Sets the capabilities on the Node and it's components to allow
- * picking at the specified detail level.
- *
- * without a detail message.
- */
- public SGIORuntimeException() {
- }
-
-
- /**
- * Constructs an instance of PickResult
objects which will contain
- information about the picked instances. null
if nothing was
- picked.
- */
- public PickResult[] pickAll () {
- PickResult[] retval = null;
- switch (mode) {
- case BOUNDS:
- retval = pickAll(pickShape);
- break;
- case GEOMETRY:
- retval = pickGeomAll(pickShape);
- break;
- case GEOMETRY_INTERSECT_INFO:
- retval = pickGeomAllIntersect(pickShape);
- break;
- default:
- throw new RuntimeException("Invalid pick mode");
- }
- return retval;
- }
-
- /** Select one of the nodes that intersect the PickShape
- @return A PickResult
object which will contain
- information about the picked instance. null
if nothing
- was picked.
- */
- public PickResult pickAny () {
- PickResult retval = null;
- switch (mode) {
- case BOUNDS:
- retval = pickAny(pickShape);
- break;
- case GEOMETRY:
- retval = pickGeomAny(pickShape);
- break;
- case GEOMETRY_INTERSECT_INFO:
- retval = pickGeomAnyIntersect(pickShape);
- break;
- default:
- throw new RuntimeException("Invalid pick mode");
- }
- return retval;
- }
-
- /** Select all the nodes that intersect the
- PickShape, returned sorted. The "closest" object will be returned first.
- See note above to see how "closest" is determined.
- PickResult
objects which will contain
- information
- about the picked instances. null
if nothing was picked.
- */
- public PickResult[] pickAllSorted () {
- PickResult[] retval = null;
-
- // System.out.println ("PickTool.pickAllSorted.");
-
- switch (mode) {
- case BOUNDS:
- // System.out.println ("PickTool.pickAllSorted : Bounds");
- retval = pickAllSorted(pickShape);
- break;
- case GEOMETRY:
- // System.out.println ("PickTool.pickAllSorted : Geometry");
- // TODO - BugId 4351050.
- // pickGeomAllSorted is broken for PickCone and PickCylinder :
- // The current Shape3D.intersect() API doesn't return the distance for
- // PickCone and PickCylinder.
- // 2) TODO - BugId 4351579.
- // pickGeomClosest is broken for multi-geometry Shape3D node :
- // The current Shape3D.intersect() API does't return the closest intersected
- // geometry.
- retval = pickGeomAllSorted(pickShape);
-
- break;
- case GEOMETRY_INTERSECT_INFO:
- // System.out.println ("PickShape " + pickShape);
- // System.out.println ("PickTool.pickAllSorted : GEOMETRY_INTERSECT_INFO");
- retval = pickGeomAllSortedIntersect(pickShape);
- break;
- default:
- throw new RuntimeException("Invalid pick mode");
- }
- return retval;
- }
-
- /** Select the closest node that
- intersects the PickShape. See note above to see how "closest" is
- determined.
- PickResult
object which will contain
- information about the picked instance. null
if nothing
- was picked.
- */
- public PickResult pickClosest () {
- PickResult retval = null;
- switch (mode) {
- case BOUNDS:
- retval = pickClosest(pickShape);
- break;
- case GEOMETRY:
- // System.out.println("pickCloset -- Geometry based picking");
- // 1) TODO - BugId 4351050.
- // pickGeomClosest is broken for PickCone and PickCylinder :
- // The current Shape3D.intersect() API doesn't return the distance for
- // PickCone and PickCylinder.
- // 2) TODO - BugId 4351579.
- // pickGeomClosest is broken for multi-geometry Shape3D node :
- // The current Shape3D.intersect() API does't return the closest intersected
- // geometry.
- retval = pickGeomClosest(pickShape);
-
- break;
- case GEOMETRY_INTERSECT_INFO:
- // System.out.println ("PickShape " + pickShape);
- // System.out.println ("PickTool.pickClosest : GEOMETRY_INTERSECT_INFO");
- retval = pickGeomClosestIntersect(pickShape);
- break;
- default:
- throw new RuntimeException("Invalid pick mode");
- }
- return retval;
- }
-
- private PickResult[] pickAll (PickShape pickShape) {
- PickResult[] pr = null;
- SceneGraphPath[] sgp = null;
-
- if (pickRootBG != null) {
- sgp = pickRootBG.pickAll (pickShape);
- } else if (pickRootL != null) {
- sgp = pickRootL.pickAll (pickShape);
- }
- if (sgp == null) return null; // no match
-
- // Create PickResult array
- pr = new PickResult [sgp.length];
- for (int i=0;i
- *
- * PickRotateBehavior behavior = new PickRotateBehavior(canvas, root, bounds);
- * root.addChild(behavior);
- *
setupCallback
method.
- * When the picked object moves, the registered object's
- * transformChanged
method is invoked.
- */
-
-public interface PickingCallback {
-
- public final static int ROTATE=0;
- public final static int TRANSLATE=1;
- public final static int ZOOM=2;
-
- /**
- * The user made a selection but nothing was
- * actually picked
- */
- public final static int NO_PICK=3;
-
- /**
- * Called by the Pick Behavior with which this callback
- * is registered each time the Picked object is moved
- */
- public void transformChanged( int type, TransformGroup tg );
-}
diff --git a/src/classes/share/com/sun/j3d/utils/picking/behaviors/package.html b/src/classes/share/com/sun/j3d/utils/picking/behaviors/package.html
deleted file mode 100644
index 21ef9e7..0000000
--- a/src/classes/share/com/sun/j3d/utils/picking/behaviors/package.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-NoSuchNameException
without detail message.
- */
- public NamedObjectException() {
- }
-
-
- /**
- * Constructs an NoSuchNameException
with the specified detail message.
- * @param msg the detail message.
- */
- public NamedObjectException(String msg) {
- super(msg);
- }
-}
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/ObjectNotLoadedException.java b/src/classes/share/com/sun/j3d/utils/scenegraph/io/ObjectNotLoadedException.java
deleted file mode 100644
index 6fb363a..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/ObjectNotLoadedException.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.scenegraph.io;
-
-/**
- * The named object has not been loaded so it's instance can not be returned
- */
-public class ObjectNotLoadedException extends java.lang.Exception {
-
- /**
- * Creates new ObjectNotLoadedException
without detail message.
- */
- public ObjectNotLoadedException() {
- }
-
-
- /**
- * Constructs an ObjectNotLoadedException
with the specified detail message.
- * @param msg the detail message.
- */
- public ObjectNotLoadedException(String msg) {
- super(msg);
- }
-}
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileReader.java b/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileReader.java
deleted file mode 100644
index b389e12..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphFileReader.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.scenegraph.io;
-
-import java.io.IOException;
-
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.SceneGraphObject;
-
-import com.sun.j3d.utils.scenegraph.io.retained.RandomAccessFileControl;
-import com.sun.j3d.utils.universe.ConfiguredUniverse;
-
-/**
- * Read Java3D BranchGraphs and/or Universe from a file. Individual branchgraphs or an
- * entire Universe can be read and references (shared nodes and components)
- * between the graphs are handled correctly.
- */
-public class SceneGraphFileReader extends java.lang.Object {
-
- private RandomAccessFileControl fileControl;
-
- /**
- * Creates new SceneGraphFileReader.
- */
- public SceneGraphFileReader( java.io.File file ) throws IOException {
- fileControl = new RandomAccessFileControl();
- fileControl.openFile( file );
- }
-
- /**
- * Create and return a ConfiguredUniverse with the PlatformGeometry, ViewerAvatar,
- * and Locales saved in the file. The MultiTransformGroup between the ViewingPlatform
- * and the View is also restored. Universe configuration information is retrieved
- * via ConfiguredUniverse.getConfigURL()
.getBranchGraphPosition
.index
universe
may be null.
- * This call will overwrite any existing universe, fileDescription and
- * userData in the file.universe
is not
- * a supported universe class. Currently SimpleUniverse and ConfiguredUniverse
- * are supported.
- */
- public SceneGraphFileWriter( java.io.File file,
- SimpleUniverse universe,
- boolean writeUniverseContent,
- String fileDescription,
- java.io.Serializable fileUserData) throws IOException, UnsupportedUniverseException {
- fileControl = new RandomAccessFileControl();
- this.file = file;
- file.createNewFile();
-
- if (!file.canWrite())
- throw new IOException( "Can not Write to File" );
-
- fileControl.createFile( file, universe, writeUniverseContent, fileDescription, fileUserData );
- }
-
- /**
- * Write the graph to the end of the file.
- *
- * close() MUST be called when IO is complete. If close() is not called
- * the file contents will be undefined.
- */
- public void writeBranchGraph( BranchGroup graph ) throws IOException {
- writeBranchGraph( graph, null );
- }
-
- /**
- * Write a branch graph and some user associated data to the
- * end of the file.
- *
- * close() MUST be called when IO is complete. If close() is not called
- * the file contents will be undefined.
- */
- public void writeBranchGraph( BranchGroup graph,
- java.io.Serializable data ) throws IOException {
- fileControl.writeBranchGraph( graph, data );
- }
-
- /**
- * Add a named reference to a SceneGraphObject in the file.
- *
- * object
must have been written to the file before this method is
- * called. If the object is not in the file a NamedObjectException will be thrown.
- *
- * Adding duplicate names will result in the old name being overwritten.
- * Different names can reference the same object
- */
- public void addObjectName( String name, SceneGraphObject object ) throws NamedObjectException {
- fileControl.addNamedObject( name, object );
- }
-
- /**
- * Close the file and cleanup internal data structures.
- */
- public void close() throws IOException {
- fileControl.close();
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphIO.java b/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphIO.java
deleted file mode 100644
index 58dee3d..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphIO.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.scenegraph.io;
-
-/**
- * Implement this interface in any classes that subclass a Java3D SceneGraphObject
- * in order to have your class handled correctly by scenegraph.io.
- *
- * More information and example code is provided here.
- *
- * Classes that implement this interface MUST have a no-arg constructor
- */
-public interface SceneGraphIO {
-
- /**
- * The method is called before writeSGObject and gives the user the chance
- * to create references to other Nodes and NodeComponents.
- *
- * References take the form of a nodeID, of type integer. Every SceneGraphObject
- * is assigned a unique ID.
- *
- * The user must save the reference information in writeSGObject
- *
- * @param ref provides methods to create references to a SceneGraphObject
- */
- public void createSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref );
-
- /**
- * Within this method the user should restore references to the SceneGraphObjects
- * whose nodeID's were created with createSceneGraphObjectReferences
- * This method is called once the all objects in the scenegraph have been loaded.
- *
- *
- * @param ref provides methods to resolve references to a SceneGraphObject
- */
- public void restoreSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref );
-
- /**
- * This method should store all the local state of the object and any references
- * to other SceneGraphObjects into out
.
- *
- * This is called after data for the parent SceneGraphObject has been written to
- * the out
.
- *
- * @param out the output stream
- */
- public void writeSceneGraphObject( java.io.DataOutput out ) throws java.io.IOException;
-
- /**
- * This is called after the object has been constructed and the superclass SceneGraphObject
- * data has been read from in
.
- *
- * The user should restore all state infomation written in writeSGObject
- *
- * @param in the input stream
- */
- public void readSceneGraphObject( java.io.DataInput in ) throws java.io.IOException;
-
- /**
- * Flag indicating for children of this object should be saved
- *
- * This method only has an effect if this is a subclass of Group.
- *
- * If this returns true then all children of this Group will be saved.
- *
- * If it returns false then the children are not saved.
- */
- public boolean saveChildren();
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphObjectReferenceControl.java b/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphObjectReferenceControl.java
deleted file mode 100644
index 6002ecf..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphObjectReferenceControl.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.scenegraph.io;
-
-/**
- * Provides and resolves references to SceneGraphObjects to enable
- * persistant references in user defined SceneGraphObjects implementing
- * the SceneGraphIO interface.
- */
-public interface SceneGraphObjectReferenceControl {
-
- /**
- * Add a reference to the scenegraph object specified and return
- * the nodeID for the object
- *
- * Use only during the save cycle
- */
- public int addReference( javax.media.j3d.SceneGraphObject object );
-
- /**
- * Given a nodeID return the corresponding scene graph object.
- *
- * Use only during the load cycle
- */
- public javax.media.j3d.SceneGraphObject resolveReference( int nodeID );
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStateProvider.java b/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStateProvider.java
deleted file mode 100644
index 77daed3..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStateProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.scenegraph.io;
-
-import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.SceneGraphObjectState;
-
-/**
- * This interface allows developers to provide their own custom IO control for
- * subclasses of SceneGraphObjects. As the Scene Graph is being saved any
- * SceneGraphObject in the graph that implements this interface must provide
- * it's state class which is responsible for saving the entire state of
- * that object.
- */
-public interface SceneGraphStateProvider {
-
- /**
- * Returns the State class
- *
- * @return Class that will perform the IO for the SceneGraphObject
- */
- public Class extends SceneGraphObjectState> getStateClass();
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamReader.java b/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamReader.java
deleted file mode 100644
index 2faee62..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamReader.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.scenegraph.io;
-
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.Canvas3D;
-
-import com.sun.j3d.utils.scenegraph.io.retained.StreamControl;
-import com.sun.j3d.utils.universe.ConfiguredUniverse;
-
-/**
- * Read and create a (set) of Java3D BranchGraphs or Universe from a Java Stream.
- */
-public class SceneGraphStreamReader extends java.lang.Object {
-
- private StreamControl control;
- private DataInputStream in;
-
- /** Creates new SceneGraphStreamReader and reads the file header information */
- public SceneGraphStreamReader( InputStream stream ) throws IOException {
- in = new DataInputStream( stream );
- control = new StreamControl( in );
- control.readStreamHeader();
- }
-
- /**
- * Read and create the universe. If the BranchGraphs were written then
- * they will be added to the universe before it is returned.
- */
- public ConfiguredUniverse readUniverse() throws IOException {
- return control.readUniverse(in, true, null);
- }
-
- /**
- * Read and create the universe. If the BranchGraphs were written then
- * they will be added to the universe before it is returned.
- * @param canvas The Canvas3D to associate with the universe.
- */
- public ConfiguredUniverse readUniverse(Canvas3D canvas) throws IOException {
- return control.readUniverse(in, true, canvas);
- }
-
- /**
- * Read and return the graph from the stream.
- * namedObjects
map will be updated with any objects that
- * were named during the write process
- */
- public BranchGroup readBranchGraph( HashMap namedObjects ) throws IOException {
- return control.readBranchGraph( namedObjects );
- }
-
- /**
- * Set the ClassLoader used to load the scene graph objects and
- * deserialize user data
- */
- public void setClassLoader( ClassLoader classLoader ) {
- control.setClassLoader( classLoader );
- }
-
- /**
- * Get the ClassLoader used to load the scene graph objects and
- * deserialize user data
- */
- public ClassLoader getClassLoader() {
- return control.getClassLoader();
- }
-
- /**
- * Close the SceneGraphStreamReader stream
- *
- * @since Java 3D 1.5.1
- */
- public void close() throws IOException {
- in.close();
- control.close();
- }
-
-}
-
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamWriter.java b/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamWriter.java
deleted file mode 100644
index 3f6564c..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/SceneGraphStreamWriter.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.scenegraph.io;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.HashMap;
-
-import javax.media.j3d.BranchGroup;
-import javax.media.j3d.DanglingReferenceException;
-
-import com.sun.j3d.utils.scenegraph.io.retained.StreamControl;
-import com.sun.j3d.utils.universe.SimpleUniverse;
-
-/**
- * Writes a Java3D SceneGraph to a Java OutputStream.universe
to the Stream.writeContent
is true then all BranchGraphs attached to the
- * universe will be saved. If it is false then only the universe
- * data structures will be output (PlatformGeometry, ViewerAvatar, Locales,
- * and the MultiTransformGroup between the ViewingPlatform and the View).writeContent
is true then all the BranchGraphs
- * attached to the Locales of the universe must have the
- * ALLOW_DETACH capability set. If they do not, a CapabilityNotSetException
- * will be thrownnamedObjects
can contain a mapping between a key and a SceneGraphObject
- * in the graph. During the read process this can be used to locate nodes
- * in the graph.
- */
- public void writeBranchGraph( BranchGroup graph, HashMap namedObjects ) throws IOException, DanglingReferenceException, NamedObjectException {
- // TODO Add namedObjects to SymbolTable
- control.addNamedObjects( namedObjects );
- control.writeBranchGraph( graph, null );
- }
-
- /**
- * Close the SceneGraphStreamWriter and the associated stream
- */
- public void close() throws IOException {
- control.close();
- out.close();
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnresolvedBehavior.java b/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnresolvedBehavior.java
deleted file mode 100644
index 1ad2553..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnresolvedBehavior.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.scenegraph.io;
-
-/**
- * This Behavior is used in place of any behaviors which can not
- * be instantiated when a scene graph is read. This behavior is
- * always disabled when it initalizes. It just provides an indicator
- * in the scene graph that a Behavior is missing.
- *
- * This normally means the Behavior is not present in the classpath.
- */
-public class UnresolvedBehavior extends javax.media.j3d.Behavior {
-
- @Override
- public void initialize() {
- setEnable(false);
- }
-
- @Override
- public void processStimulus(java.util.Enumeration enumeration) {
- }
-
-}
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnsupportedUniverseException.java b/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnsupportedUniverseException.java
deleted file mode 100644
index a18902d..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/UnsupportedUniverseException.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.scenegraph.io;
-
-/**
- * Thrown if the VirtualUniverse subclass is not supported
- * by the writeUniverse calls.
- *
- * Currently only com.sun.j3d.utils.universe.SimpleUniverse is supported
- */
-public class UnsupportedUniverseException extends java.lang.Exception {
-
- /**
- * Creates new UnsupportedUniverseException
without detail message.
- */
- public UnsupportedUniverseException() {
- }
-
-
- /**
- * Constructs an UnsupportedUniverseException
with the specified detail message.
- * @param msg the detail message.
- */
- public UnsupportedUniverseException(String msg) {
- super(msg);
- }
-}
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/doc-files/extensibility.html b/src/classes/share/com/sun/j3d/utils/scenegraph/io/doc-files/extensibility.html
deleted file mode 100644
index 113cd9b..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/doc-files/extensibility.html
+++ /dev/null
@@ -1,189 +0,0 @@
-
-
-
-
-
-
-Using your own Classes with scenegraph.io
-
-
-public class MyBranchGroup extends javax.media.j3d.BranchGroup {
- private int myData;
- ....
-}
-
-
-
-
-
-
-
-Behavior Example
-
-
-public class BehaviorIO extends javax.media.j3d.Behavior implements SceneGraphIO
- private TransformGroup target; // The TG on which this behavior acts
- private int targetRef; // Object Reference for target
-
- public void createSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
- targetRef = ref.addReference( target );
- }
-
- public void restoreSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
- target = (TransformGroup)ref.resolveReference( targetRef );
- }
-
- public void writeSceneGraphObject( java.io.DataOutput out ) throws IOException {
- out.writeInt( targetRef );
- }
-
- public void readSceneGraphObject( java.io.DataInput in ) throws IOException {
- targetRef = in.readInt();
- }
-
- // This has no effect as this is not a subclass of Group
- public boolean saveChildren() {
- return true;
- }
-
-`BlackBox' Group Example
-
-This example is a Group node that creates its subgraph during
-its instantiation. An example where you might use this is to
-represent some geometry that is loaded from an external file format
-such a OpenFLT.
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/package.html b/src/classes/share/com/sun/j3d/utils/scenegraph/io/package.html
deleted file mode 100644
index 73e795c..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/package.html
+++ /dev/null
@@ -1,105 +0,0 @@
-
-
-
-
-
-
-
-
-public class House extends Group implements SceneGraphIO {
- public House() {
- super();
- this.addChild( OpenFlightLoader.load( "/dir/house.flt" );
- }
-
- public void createSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
- // No references
- }
-
- public void restoreSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
- // No references
- }
-
- public void writeSceneGraphObject( java.io.DataOutput out ) throws IOException {
- // No local state
- }
-
- public void readSceneGraphObject( java.io.DataInput in ) throws IOException {
- // No local state
- }
-
- public boolean saveChildren() {
- // Don't save the children as they will be restored by the openflightloader
- return false;
- }
-
-j3d.io.UseSuperClassIfNoChildClass when this property is present the load
-operation will attempt to avoid failure if Scene Graph nodes are not present
-in the classpath. For example if a developer has subclassed BranchGroup with a
-class called MyBG but has not
-implemented the SceneGraphIO interface when the API saves the graph the
-superclass (ie BranchGroup) data will be stored. When the scene is loaded
-normally MyBG must be in the classpath otherwise the load will fail. If this
-property is set then the superclass node (ie BranchGroup) will be instantiated
-when MyBG is missing. Obviously, if MyBG contained any state information
-then this will be lost.
-SGIORuntimeException
- * with the specified detail message.
- *
- * @param msg the detail message.
- */
- public SGIORuntimeException(String msg) {
- super(msg);
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/StreamControl.java b/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/StreamControl.java
deleted file mode 100644
index 8b1dc00..0000000
--- a/src/classes/share/com/sun/j3d/utils/scenegraph/io/retained/StreamControl.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.scenegraph.io.retained;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.HashMap;
-
-import javax.media.j3d.BranchGroup;
-
-import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.SceneGraphObjectState;
-
-/**
- * Provides the infrastructure for ScenGraphStream Reader and Writer
- */
-public class StreamControl extends Controller {
-
- protected String FILE_IDENT = new String( "j3dsf" );
-
- private DataInputStream inputStream;
- private DataOutputStream outputStream;
-
- public StreamControl( DataOutputStream out ) {
- super();
- outputStream = out;
- symbolTable = new SymbolTable( this );
- }
-
- public StreamControl( DataInputStream in ) {
- super();
- inputStream = in;
- symbolTable = new SymbolTable( this );
- }
-
- /**
- * Prepare the Stream for writing, by sending header information
- */
- public void writeStreamHeader() throws IOException {
- outputStream.writeUTF( FILE_IDENT );
- outputStream.writeInt( outputFileVersion );
- }
-
- public void readStreamHeader() throws IOException {
- String ident = inputStream.readUTF();
- if ( ident.equals("demo_j3s") )
- throw new IOException( "Use Java 3D Fly Through I/O instead of Java 3D Scenegraph I/O" );
-
- if ( !ident.equals("j3dsf") )
- throw new IOException(
- "This is a File - use SceneGraphFileReader instead");
-
- currentFileVersion = inputStream.readInt();
-
- if (currentFileVersion > outputFileVersion ) {
- throw new IOException("Unsupported file version. This file was written using a new version of the SceneGraph IO API, please update your installtion to the latest version");
- }
- }
-
- /**
- * Add the named objects to the symbol table
- */
- public void addNamedObjects( HashMap namedObjects ) {
- symbolTable.addNamedObjects( namedObjects );
- }
-
- /**
- * The BranchGraph userData is not supported in a stream and will be
- * ignored.
- *
- * However the data in the userData field of the BranchGroup will be
- * stored in the stream
- */
- @Override
- public void writeBranchGraph( BranchGroup bg, java.io.Serializable userData ) throws IOException {
- try {
- SymbolTableData symbol = symbolTable.getSymbol( bg );
-
- if (symbol==null) {
- symbol = symbolTable.createSymbol( bg );
- symbol.branchGraphID = -1; // This is a new BranchGraph so set the ID to -1
- } // which will cause setBranchGraphRoot to assign a new ID.
-
- symbolTable.setBranchGraphRoot( symbol, 0 );
- symbolTable.startUnsavedNodeComponentFrame();
- SceneGraphObjectState state = createState( bg, symbol );
- writeObject( outputStream, state );
- writeNodeComponents( outputStream );
- symbolTable.endUnsavedNodeComponentFrame();
-
- if (symbolTable.branchGraphHasDependencies( symbol.branchGraphID ))
- throw new javax.media.j3d.DanglingReferenceException();
-
- symbolTable.clearUnshared();
- symbolTable.writeTable( outputStream );
- } catch( SGIORuntimeException e ) {
- throw new IOException( e.getMessage() );
- }
- }
-
- public BranchGroup readBranchGraph( HashMap namedObjects ) throws IOException {
- try {
- SceneGraphObjectState state = readObject( inputStream );
- readNodeComponents( inputStream );
- symbolTable.readTable( inputStream, true );
-
- symbolTable.setBranchGraphRoot( state.getSymbol(), 0 );
-
- state.buildGraph();
-
- if (namedObjects!=null)
- symbolTable.getNamedObjectMap( namedObjects );
-
- return (BranchGroup)state.getNode();
- } catch( SGIORuntimeException e ) {
- throw new IOException( e.getMessage() );
- }
- }
-
- /**
- * Read the set of branchgraps.
- *
- * Used by readUniverse
- *
- * RandomAccessFileControl will read the graphs in the array,
- * StreamControl expects the graphs to follow the universe in the
- * stream so it will read graphs.length branchgraphs.
- */
- @Override
- protected void readBranchGraphs( int[] graphs ) throws IOException {
- for(int i=0; imap
- */
- public void addNamedObjects( HashMap map ) {
- if (map!=null)
- namedObjects.putAll( map );
- }
-
- /**
- * Return the SceneGraphObject associated with the name
- */
- public SceneGraphObject getNamedObject( String name ) throws NamedObjectException, ObjectNotLoadedException {
- Object obj = namedObjects.get( name );
- if (obj==null)
- throw new NamedObjectException( "Unknown name :"+name );
-
- if (obj instanceof SceneGraphObject)
- return (SceneGraphObject)obj;
- else {
- SymbolTableData symbol = getSymbol( ((Integer)obj).intValue() );
- if (symbol==null || symbol.j3dNode==null)
- throw new ObjectNotLoadedException( ((Integer)obj).toString() );
- return symbol.j3dNode;
- }
- }
-
- /**
- * Get all the names of the named objects
- */
- public String[] getNames() {
- return (String[])namedObjects.keySet().toArray( new String[] {} );
- }
-
- /**
- * Add the namedObject mappings to map
- */
- public void getNamedObjectMap( HashMap map ) {
- map.putAll( namedObjects );
- }
-
- @Override
- public String toString() {
- StringBuffer buf = new StringBuffer();
-
- for(int i=0; iformatMatrixRows(3, 3, m)
, where m
is a
- * an array of doubles retrieved from the given Matrix3d.
- *
- * @param m3 matrix to be formatted
- * @return matrix rows formatted into strings
- */
- static String[] formatMatrixRows(Matrix3d m3) {
- double[] m = new double[9] ;
- m[0] = m3.m00 ; m[1] = m3.m01 ; m[2] = m3.m02 ;
- m[3] = m3.m10 ; m[4] = m3.m11 ; m[5] = m3.m12 ;
- m[6] = m3.m20 ; m[7] = m3.m21 ; m[8] = m3.m22 ;
-
- return formatMatrixRows(3, 3, m) ;
- }
-
- /**
- * Calls formatMatrixRows(4, 4, m)
, where m
is a
- * an array of doubles retrieved from the given Matrix4d.
- *
- * @param m4 matrix to be formatted
- * @return matrix rows formatted into strings
- */
- static String[] formatMatrixRows(Matrix4d m4) {
- double[] m = new double[16] ;
- m[0] = m4.m00 ; m[1] = m4.m01 ; m[2] = m4.m02 ; m[3] = m4.m03 ;
- m[4] = m4.m10 ; m[5] = m4.m11 ; m[6] = m4.m12 ; m[7] = m4.m13 ;
- m[8] = m4.m20 ; m[9] = m4.m21 ; m[10] = m4.m22 ; m[11] = m4.m23 ;
- m[12] = m4.m30 ; m[13] = m4.m31 ; m[14] = m4.m32 ; m[15] = m4.m33 ;
-
- return formatMatrixRows(4, 4, m) ;
- }
-
- /**
- * Formats a matrix with fixed fractional digits and integer padding to
- * align the decimal points in columns. Non-negative numbers print up to
- * 7 integer digits, while negative numbers print up to 6 integer digits
- * to account for the negative sign. 6 fractional digits are printed.
- *
- * @param rowCount number of rows in the matrix
- * @param colCount number of columns in the matrix
- * @param m matrix to be formatted
- * @return matrix rows formatted into strings
- */
- static String[] formatMatrixRows(int rowCount, int colCount, double[] m) {
- DecimalFormat df = new DecimalFormat("0.000000") ;
- FieldPosition fp = new FieldPosition(DecimalFormat.INTEGER_FIELD) ;
- StringBuffer sb0 = new StringBuffer() ;
- StringBuffer sb1 = new StringBuffer() ;
- String[] rows = new String[rowCount] ;
-
- for (int i = 0 ; i < rowCount ; i++) {
- sb0.setLength(0) ;
- for (int j = 0 ; j < colCount ; j++) {
- sb1.setLength(0) ;
- df.format(m[i*colCount+j], sb1, fp) ;
- int pad = 8 - fp.getEndIndex() ;
- for (int k = 0 ; k < pad ; k++) {
- sb1.insert(0, " ") ;
- }
- sb0.append(sb1) ;
- }
- rows[i] = sb0.toString() ;
- }
- return rows ;
- }
-
- /**
- * Returns the String representation of this command.
- *
- * @return string representing this command
- */
- @Override
- public String toString() {
- String[] lines = null ;
- StringBuffer sb = new StringBuffer("(") ;
-
- for (int i = 0 ; i < argc ; i++) {
- if (argv[i] instanceof Matrix3d) {
- lines = formatMatrixRows((Matrix3d)argv[i]) ;
- sb.append("\n ((" + lines[0] + ")\n") ;
- sb.append(" (" + lines[1] + ")\n") ;
- sb.append(" (" + lines[2] + "))") ;
- if (i != (argc - 1)) sb.append("\n") ;
- }
- else if (argv[i] instanceof Matrix4d) {
- lines = formatMatrixRows((Matrix4d)argv[i]) ;
- sb.append("\n ((" + lines[0] + ")\n") ;
- sb.append(" (" + lines[1] + ")\n") ;
- sb.append(" (" + lines[2] + ")\n") ;
- sb.append(" (" + lines[3] + "))") ;
- if (i != (argc - 1)) sb.append("\n") ;
- }
- else {
- if (i > 0) sb.append(" ") ;
- sb.append(argv[i].toString()) ;
- }
- }
-
- sb.append(")") ;
- return sb.toString() ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfigContainer.java b/src/classes/share/com/sun/j3d/utils/universe/ConfigContainer.java
deleted file mode 100644
index 7e61bfa..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfigContainer.java
+++ /dev/null
@@ -1,1544 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe ;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StreamTokenizer;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Loads a Java 3D configuration file and creates a container of named objects
- * that will effect the viewing configuration specified in the file. These
- * can include Viewers, ViewingPlatforms, ViewPlatformBehaviors, InputDevices,
- * Sensors, and other objects.NewObject
and ObjectProperty
configuration
- * commands.
- *
- * @see ConfiguredUniverse
- * @see
- * The Java 3D Configuration File
- * @see
- * Example Configuration Files
- *
- * @since Java 3D 1.3.1
- */
-public class ConfigContainer {
- //
- // The configuration object database is implemented with a HashMap which
- // maps their class names to ArrayList objects which contain the actual
- // instances. The latter are used since the instances of a given class
- // must be evaluated in the order in which they were created.
- // LinkedHashMap is available in JDK 1.4 but currently this code must run
- // under JDK 1.3.1 as well.
- //
- private Map baseNameMap = new HashMap() ;
-
- // Map containing named canvases for each view.
- private Map viewCanvasMap = new HashMap() ;
-
- // Read-only Maps for the public interface to the configuration database.
- private ReadOnlyMap bodyMap = null ;
- private ReadOnlyMap environmentMap = null ;
- private ReadOnlyMap viewerMap = null ;
- private ReadOnlyMap deviceMap = null ;
- private ReadOnlyMap sensorMap = null ;
- private ReadOnlyMap behaviorMap = null ;
- private ReadOnlyMap platformMap = null ;
- private ReadOnlyMap genericObjectMap = null ;
-
- // Read-only Sets for the public interface to the configuration database.
- private ReadOnlySet bodies = null ;
- private ReadOnlySet environments = null ;
- private ReadOnlySet viewers = null ;
- private ReadOnlySet devices = null ;
- private ReadOnlySet sensors = null ;
- private ReadOnlySet behaviors = null ;
- private ReadOnlySet platforms = null ;
- private ReadOnlySet genericObjects = null ;
-
- // The number of TransformGroups to include in ViewingPlatforms.
- private int transformCount = 1 ;
-
- // The visibility status of Viewer AWT components.
- private boolean setVisible = false ;
-
- private ClassLoader classLoader = ClassLoader.getSystemClassLoader();
-
- /**
- * The name of the file this ConfigContainer is currently loading.
- */
- String currentFileName = null ;
-
- /**
- * Creates a new ConfigContainer and loads the configuration file at the
- * specified URL. All ViewingPlatform instances are created with a single
- * TransformGroup and all Viewer components are initially invisible.
- *
- * @param userConfig URL of the configuration file to load
- */
- public ConfigContainer(URL userConfig) {
- this(userConfig, false, 1, true) ;
- }
-
- /**
- * Creates a new ConfigContainer and loads the configuration file at the
- * specified URL. All ViewingPlatform instances are created with a single
- * TransformGroup and all Viewer components are initially invisible.
- *
- * @param userConfig URL of the configuration file to load
- * @param classLoader the class loader to use to load classes specified
- * in the config file.
- */
- public ConfigContainer(URL userConfig, ClassLoader classLoader) {
- this(userConfig, false, 1, true, classLoader) ;
- }
-
- /**
- * Creates a new ConfigContainer and loads the configuration file at the
- * specified URL. Any ViewingPlatform instantiated by the configuration
- * file will be created with the specified number of transforms. Viewer
- * components may be set initially visible or invisible with the
- * setVisible
flag.
- *
- * @param userConfig URL of the configuration file to load
- * @param setVisible if true, setVisible(true)
is called on
- * all Viewers
- * @param transformCount number of transforms to be included in any
- * ViewingPlatform created; must be greater than 0
- */
- public ConfigContainer(URL userConfig,
- boolean setVisible, int transformCount) {
-
- this(userConfig, setVisible, transformCount, true) ;
- }
-
- /**
- * Creates a new ConfigContainer and loads the configuration file at the
- * specified URL. Any ViewingPlatform instantiated by the configuration
- * file will be created with the specified number of transforms. Viewer
- * components may be set initially visible or invisible with the
- * setVisible
flag.
- *
- * @param userConfig URL of the configuration file to load
- * @param setVisible if true, setVisible(true)
is called on
- * all Viewers
- * @param transformCount number of transforms to be included in any
- * ViewingPlatform created; must be greater than 0
- * @param classLoader the class loader to use to load classes specified
- * in the config file.
- */
- public ConfigContainer(URL userConfig,
- boolean setVisible, int transformCount,
- ClassLoader classLoader) {
-
- this(userConfig, setVisible, transformCount, true, classLoader) ;
- }
-
- /**
- * Package-scoped constructor for ConfigContainer. This provides an
- * additional flag, attachBehaviors
, which indicates whether
- * or not ViewPlatformBehaviors should be attached to the ViewingPlatforms
- * specified for them.setViewingPlatform
in order to look up the actual Sensor,
- * Viewer, Behavior, etc., instances associated with the names provided
- * them from the configuration file.initialize
method is called,
- * or to 2) define properties that accept object instances directly, and
- * then use the newer Device, Sensor, ViewPlatform, etc., built-in
- * commands in the configuration file. These built-ins will return an
- * object instance from a name.
- *
- * @param userConfig URL of the configuration file to load
- * @param setVisible if true, setVisible(true)
is called on
- * all Viewers
- * @param transformCount number of transforms to be included in any
- * ViewingPlatform created; must be greater than 0
- * @param attachBehaviors if true, attach ViewPlatformBehaviors to the
- * appropriate ViewingPlatforms
- */
- ConfigContainer(URL userConfig, boolean setVisible,
- int transformCount, boolean attachBehaviors) {
-
- if (transformCount < 1)
- throw new IllegalArgumentException
- ("transformCount must be greater than 0") ;
-
- loadConfig(userConfig) ;
- processConfig(setVisible, transformCount, attachBehaviors) ;
- }
-
- /**
- * Package scoped constructor that adds the ability to set the ClassLoader
- * which will be used to load any app specific classes specified in the
- * configuration file. By default SystemClassLoader is used.
- */
- ConfigContainer(URL userConfig, boolean setVisible,
- int transformCount, boolean attachBehaviors,
- ClassLoader classLoader) {
- this(userConfig, setVisible, transformCount, attachBehaviors);
- this.classLoader = classLoader;
- }
-
- /**
- * Open, parse, and load the contents of a configuration file.
- *
- * @param userConfig location of the configuration file
- */
- private void loadConfig(URL userConfig) {
- InputStream inputStream = null ;
- StreamTokenizer streamTokenizer = null ;
- String lastFileName = currentFileName ;
-
- currentFileName = userConfig.toString() ;
- try {
- inputStream = userConfig.openStream() ;
- Reader r = new BufferedReader(new InputStreamReader(inputStream)) ;
- streamTokenizer = new StreamTokenizer(r) ;
- }
- catch (IOException e) {
- throw new IllegalArgumentException(
- e + "\nUnable to open " + currentFileName) ;
- }
-
- //
- // Set up syntax tables for the tokenizer.
- //
- // It would be nice to allow '/' as a word constituent for URL strings
- // and Unix paths, but then the scanner won't ignore "//" and "/* */"
- // comment style syntax. Treating '/' as an ordinary character will
- // allow comments to work, but then '/' becomes a single token which
- // has to be concatenated with subsequent tokens to reconstruct the
- // original word string.
- //
- // It is cleaner to just require quoting for forward slashes. '/'
- // should still be treated as an ordinary character however, so that a
- // non-quoted URL string or Unix path will be treated as a syntax
- // error instead of a comment.
- //
- streamTokenizer.ordinaryChar('/') ;
- streamTokenizer.wordChars('_', '_') ;
- streamTokenizer.wordChars('$', '$') ; // for ${...} Java property
- streamTokenizer.wordChars('{', '}') ; // substitution in word tokens
- streamTokenizer.slashSlashComments(true) ;
- streamTokenizer.slashStarComments(true) ;
-
- // Create an s-expression parser to use for all top-level (0) commands.
- ConfigSexpression sexp = new ConfigSexpression() ;
-
- // Loop through all top-level commands. Boolean.FALSE is returned
- // after the last one is evaluated.
- while (sexp.parseAndEval(this, streamTokenizer, 0) != Boolean.FALSE) ;
-
- // Close the input stream.
- try {
- inputStream.close() ;
- }
- catch (IOException e) {
- throw new IllegalArgumentException(
- e + "\nUnable to close " + currentFileName) ;
- }
-
- // Restore current file name.
- currentFileName = lastFileName ;
- }
-
- /**
- * This method gets called from the s-expression parser to process a
- * configuration command.
- *
- * @param elements tokenized list of sexp elements
- * @param lineNumber command line number
- */
- void evaluateCommand(ArrayList elements, int lineNumber) {
- ConfigObject co ;
- ConfigCommand cmd ;
-
- // Create a command object.
- cmd = new ConfigCommand(elements, currentFileName, lineNumber) ;
-
- // Process the command according to its type.
- switch (cmd.type) {
- case ConfigCommand.CREATE:
- co = createConfigObject(cmd) ;
- addConfigObject(co) ;
- break ;
- case ConfigCommand.ALIAS:
- co = createConfigAlias(cmd) ;
- addConfigObject(co) ;
- break ;
- case ConfigCommand.PROPERTY:
- co = findConfigObject(cmd.baseName, cmd.instanceName) ;
- co.setProperty(cmd) ;
- break ;
- case ConfigCommand.INCLUDE:
- if (! (cmd.argv[1] instanceof String)) {
- throw new IllegalArgumentException
- ("Include file must be a URL string") ;
- }
- URL url = null ;
- String urlString = (String)cmd.argv[1] ;
- try {
- url = new URL(urlString) ;
- }
- catch (MalformedURLException e) {
- throw new IllegalArgumentException(e.toString()) ;
- }
- loadConfig(url) ;
- break ;
- case ConfigCommand.IGNORE:
- break ;
- default:
- throw new IllegalArgumentException
- ("Unknown command \"" + cmd.commandName + "\"") ;
- }
- }
-
- /**
- * Instantiates and initializes an object that extends the ConfigObject
- * base class. The class name of the object is derived from the
- * command, which is of the following form:findConfigObjects(baseName, true)
.
- * Aliases are filtered out so that all returned instances are unique.
- *
- * @param baseName base name of desired config object class
- * @return ArrayList of config object instances of the desired base
- * class, or null if instances of the base class don't exist
- */
- Collection findConfigObjects(String baseName) {
- return findConfigObjects(baseName, true) ;
- }
-
-
- /**
- * Find instances of config objects with the given base name.
- *
- * @param baseName base name of desired config object class
- * @param filterAlias if true, aliases are filtered out so that all
- * returned instances are unique
- * @return ArrayList of config object instances of the desired base
- * class, or null if instances of the base class don't exist
- */
- Collection findConfigObjects(String baseName, boolean filterAlias) {
- ArrayList instances ;
-
- instances = (ArrayList)baseNameMap.get(baseName) ;
- if (instances == null || instances.size() == 0) {
- return null ; // This is not an error.
- }
-
- if (filterAlias) {
- ArrayList output = new ArrayList() ;
- for (int i = 0 ; i < instances.size() ; i++) {
- ConfigObject configObject = (ConfigObject)instances.get(i) ;
-
- if (! configObject.isAlias) {
- output.add(configObject) ;
- }
- }
- return output ;
- }
- else {
- return instances ;
- }
- }
-
- /**
- * Returns the ConfigObject associated with the name in the given
- * ConfigCommand. This is used for evaluating retained built-in commands
- * after the config file has already been parsed. The parser won't catch
- * any of the exceptions generated by this method, so the error messages
- * are wrapped accordingly.
- *
- * @param basename base name of the config object
- * @param cmd command containing the name in argv[1]
- * @return the found ConfigObject
- */
- private ConfigObject findConfigObject(String baseName, ConfigCommand cmd) {
- if (cmd.argc != 2 || !(cmd.argv[1] instanceof String))
- throw new IllegalArgumentException
- (ConfigObject.errorMessage
- (cmd, "Parameter must be a single string")) ;
- try {
- return findConfigObject(baseName, (String)cmd.argv[1]) ;
- }
- catch (IllegalArgumentException e) {
- throw new IllegalArgumentException
- (ConfigObject.errorMessage(cmd, e.getMessage())) ;
- }
- }
-
- /**
- * This method gets called from a ConfigObject to evaluate a retained
- * built-in command nested within a property command. These are commands
- * that can't be evaluated until the entire config file is parsed.
- *
- * @param cmd the built-in command
- * @return object representing result of evaluation
- */
- Object evaluateBuiltIn(ConfigCommand cmd) {
- int argc = cmd.argc ;
- Object[] argv = cmd.argv ;
-
- if (cmd.commandName.equals("ConfigContainer")) {
- // return a reference to this ConfigContainer
- return this ;
- }
- else if (cmd.commandName.equals("Canvas3D")) {
- // Look for canvases in the screen database.
- return ((ConfigScreen)findConfigObject("Screen", cmd)).j3dCanvas ;
- }
- else if (baseNameMap.get(cmd.commandName) != null) {
- // Handle commands of the form ({objectType} name) that return the
- // object associated with the name.
- return findConfigObject(cmd.commandName, cmd).targetObject ;
- }
- else {
- // So far no other retained built-in commands.
- throw new IllegalArgumentException
- (ConfigObject.errorMessage(cmd, "Unknown built-in command \"" +
- cmd.commandName + "\"")) ;
- }
- }
-
- /**
- * Process the configuration after parsing the configuration file.
- * Note: the processing order of the various config objects is
- * significant.
- *
- * @param setVisible true if Viewer components should be visible
- * @param transformCount number of TransformGroups with which
- * ViewingPlatforms should be created
- * @param attachBehaviors true if behaviors should be attached to
- * ViewingPlatforms
- */
- private void processConfig(boolean setVisible,
- int transformCount, boolean attachBehaviors) {
-
- Collection c, s, pe, vp ;
- this.setVisible = setVisible ;
- this.transformCount = transformCount ;
-
- c = findConfigObjects("PhysicalBody") ;
- if (c != null) {
- processPhysicalBodies(c) ;
- }
-
- pe = findConfigObjects("PhysicalEnvironment") ;
- if (pe != null) {
- processPhysicalEnvironments(pe) ;
- }
-
- c = findConfigObjects("View") ;
- if (c != null) {
- processViews(c, setVisible) ;
- }
-
- c = findConfigObjects("Device") ;
- s = findConfigObjects("Sensor") ;
- if (c != null) {
- processDevices(c, s, pe) ;
- }
-
- vp = findConfigObjects("ViewPlatform") ;
- if (vp != null) {
- processViewPlatforms(vp, transformCount) ;
- }
-
- c = findConfigObjects("ViewPlatformBehavior") ;
- if (c != null) {
- processViewPlatformBehaviors(c, vp, attachBehaviors) ;
- }
-
- c = findConfigObjects("Object") ;
- if (c != null) {
- processGenericObjects(c) ;
- }
- }
-
- // Process config physical environments into Java 3D physical
- // environments.
- private void processPhysicalEnvironments(Collection c) {
- Iterator i = c.iterator() ;
- while (i.hasNext()) {
- ConfigPhysicalEnvironment e = (ConfigPhysicalEnvironment)i.next() ;
- e.targetObject = e.createJ3dPhysicalEnvironment() ;
- }
- }
-
- // Process config physical bodys into Java 3D physical bodies.
- private void processPhysicalBodies(Collection c) {
- Iterator i = c.iterator() ;
- while (i.hasNext()) {
- ConfigPhysicalBody b = (ConfigPhysicalBody)i.next() ;
- b.targetObject = b.createJ3dPhysicalBody() ;
- }
- }
-
- // Process config views into Java 3D Views and then create Viewer objects
- // for them. This should only be called after all physical bodies and
- // physical environments have been processed.
- private void processViews(Collection c, boolean setVisible) {
- Iterator i = c.iterator() ;
- while (i.hasNext()) {
- ConfigView v = (ConfigView)i.next() ;
- v.targetObject = v.createViewer(setVisible) ;
- }
- }
-
- // Process config devices into Java 3D input devices. This should be done
- // only after all views have been processed, as some InputDevice
- // implementations require the AWT components associated with a view.
- private void processDevices(Collection c, Collection s, Collection p) {
- ConfigDevice cd = null ;
- Iterator i = c.iterator() ;
- while (i.hasNext()) {
- cd = (ConfigDevice)i.next() ;
- cd.targetObject = cd.createInputDevice() ;
- }
-
- // Process device properties only after all InputDevices have been
- // instantiated. Some InputDevice properties require references
- // to other InputDevice implementations.
- i = c.iterator() ;
- while (i.hasNext()) ((ConfigDevice)i.next()).processProperties() ;
-
- // Initialize the devices only after all have been instantiated, as
- // some InputDevices implementations are slaved to the first one
- // created and will not initialize otherwise (e.g. LogitechTracker).
- i = c.iterator() ;
- while (i.hasNext()) {
- cd = (ConfigDevice)i.next() ;
- if (! cd.j3dInputDevice.initialize())
- throw new RuntimeException
- (cd.errorMessage(cd.creatingCommand,
- "could not initialize device \"" +
- cd.instanceName + "\"")) ;
- }
-
- // An InputDevice implementation will have created all its Sensors by
- // the time initialize() returns. Retrieve and configure them here.
- if (s != null) {
- i = s.iterator() ;
- while (i.hasNext()) {
- ConfigSensor cs = (ConfigSensor)i.next() ;
- cs.configureSensor() ;
- cs.targetObject = cs.j3dSensor ;
- }
- }
-
- // Iterate through the PhysicalEnvironments and process the devices.
- if (p != null) {
- i = p.iterator() ;
- while (i.hasNext())
- ((ConfigPhysicalEnvironment)i.next()).processDevices() ;
- }
- }
-
- // Process config view platforms into Java 3D viewing platforms.
- private void processViewPlatforms(Collection c, int numTransforms) {
- Iterator i = c.iterator() ;
- while (i.hasNext()) {
- ConfigViewPlatform cvp = (ConfigViewPlatform)i.next() ;
- cvp.targetObject = cvp.createViewingPlatform(numTransforms) ;
- }
- }
-
- // Process the configured view platform behaviors.
- private void processViewPlatformBehaviors(Collection behaviors,
- Collection viewPlatforms,
- boolean attach) {
- Iterator i = behaviors.iterator() ;
- while (i.hasNext()) {
- ConfigViewPlatformBehavior b =
- (ConfigViewPlatformBehavior)i.next() ;
- b.targetObject = b.createViewPlatformBehavior() ;
- }
-
- // Process properties only after all behaviors are instantiated.
- i = behaviors.iterator() ;
- while (i.hasNext())
- ((ConfigViewPlatformBehavior)i.next()).processProperties() ;
-
- // Attach behaviors to platforms after properties processed.
- if (attach && viewPlatforms != null) {
- i = viewPlatforms.iterator() ;
- while (i.hasNext())
- ((ConfigViewPlatform)i.next()).processBehavior() ;
- }
- }
-
- // Process generic objects.
- private void processGenericObjects(Collection objects) {
- Iterator i = objects.iterator() ;
- while (i.hasNext()) {
- ConfigObject o = (ConfigObject)i.next() ;
- o.targetObject = o.createTargetObject() ;
- }
-
- // Process properties only after all target objects are instantiated.
- i = objects.iterator() ;
- while (i.hasNext()) ((ConfigObject)i.next()).processProperties() ;
- }
-
- // Returns a read-only Set containing all unique Java 3D objects of the
- // specified base class.
- private ReadOnlySet createSet(String baseName) {
- Collection c = findConfigObjects(baseName, true) ;
- if (c == null || c.size() == 0)
- return null ;
-
- Iterator i = c.iterator() ;
- ArrayList l = new ArrayList() ;
- while (i.hasNext()) l.add(((ConfigObject)i.next()).targetObject) ;
-
- return new ReadOnlySet(l) ;
- }
-
- // Returns a read-only Map that maps all names in the specified base
- // class, including aliases, to their corresponding Java 3D objects.
- private ReadOnlyMap createMap(String baseName) {
- Collection c = findConfigObjects(baseName, false) ;
- if (c == null || c.size() == 0)
- return null ;
-
- Iterator i = c.iterator() ;
- HashMap m = new HashMap() ;
- while (i.hasNext()) {
- ConfigObject co = (ConfigObject)i.next() ;
- if (co.isAlias)
- m.put(co.instanceName, co.original.targetObject) ;
- else
- m.put(co.instanceName, co.targetObject) ;
- }
-
- return new ReadOnlyMap(m) ;
- }
-
- /**
- * Returns a read-only Set of all configured PhysicalBody instances in the
- * order they were defined in the configuration file.
- *
- * PhysicalBody instances are created with the following command:
- * (NewPhysicalBody <instance name>
- * [Alias <alias name>])
- *
- *
- * The PhysicalBody is configured through the following command:
- * (PhysicalBodyProperty <instance name>
- * <property name> <property value>)
- *
- *
- * @return read-only Set of all unique instances, or null
- */
- public Set getPhysicalBodies() {
- if (bodies != null) return bodies ;
- bodies = createSet("PhysicalBody") ;
- return bodies ;
- }
-
- /**
- * Returns a read-only Map that maps PhysicalBody names to instances.
- * Names may be aliases and if so will map to the original instances.
- *
- * @return read-only Map from names to PhysicalBody instances, or null if
- * no instances
- */
- public Map getNamedPhysicalBodies() {
- if (bodyMap != null) return bodyMap ;
- bodyMap = createMap("PhysicalBody") ;
- return bodyMap ;
- }
-
- /**
- * Returns a read-only Set of all configured PhysicalEnvironment instances
- * in the order they were defined in the configuration file.
- * (NewPhysicalEnvironment <instance name>
- * [Alias <alias name>])
- *
- *
- * The PhysicalEnvironment is configured through the following command:
- * (PhysicalEnvironmentProperty <instance name>
- * <property name> <property value>)
- *
- *
- * @return read-only Set of all unique instances, or null
- */
- public Set getPhysicalEnvironments() {
- if (environments != null) return environments ;
- environments = createSet("PhysicalEnvironment") ;
- return environments ;
- }
-
- /**
- * Returns a read-only Map that maps PhysicalEnvironment names to
- * instances. Names may be aliases and if so will map to the original
- * instances.
- *
- * @return read-only Map from names to PhysicalEnvironment instances, or
- * null if no instances
- */
- public Map getNamedPhysicalEnvironments() {
- if (environmentMap != null) return environmentMap ;
- environmentMap = createMap("PhysicalEnvironment") ;
- return environmentMap ;
- }
-
- /**
- * Returns a read-only Set of all configured Viewer instances in the order
- * they were defined in the configuration file. The Viewers will have
- * incorporated any PhysicalEnvironment and PhysicalBody objects specfied
- * for them in the configuration file, and will be attached to any
- * ViewingPlatforms specified for them.
- * (NewView <instance name> [Alias <alias name>])
- *
- *
- * The Viewer is configured through the following command:
- * (ViewProperty <instance name>
- * <property name> <property value>)
- *
- *
- * @return read-only Set of all unique instances, or null
- */
- public Set getViewers() {
- if (viewers != null) return viewers ;
- viewers = createSet("View") ;
- return viewers ;
- }
-
- /**
- * Returns a read-only Map that maps Viewer names to instances.
- * Names may be aliases and if so will map to the original instances.
- * The Viewers will have incorporated any PhysicalEnvironment and
- * PhysicalBody objects specfied for them in the configuration file, and
- * will be attached to any ViewingPlatforms specified for them.
- * (NewDevice <instanceName> <className>
- * [Alias <alias name>])
- *
- *
- * className must be the fully-qualified name of a class that
- * implements the InputDevice interface. The implementation
- * must provide a parameterless constructor.
- * (DeviceProperty <instanceName> <propertyName>
- * <arg0> ... <argn>)
- *
- *
- * propertyName must be the name of a input device method that
- * takes an array of Objects as its only parameter; the array is populated
- * with the values of arg0 through argn when the method is
- * invoked to set the property. These additional requirements for
- * configurable input devices can usually be fulfilled by extending or
- * wrapping available InputDevice implementations.
- *
- * @return read-only Set of all unique instances, or null
- */
- public Set getInputDevices() {
- if (devices != null) return devices ;
- devices = createSet("Device") ;
- return devices ;
- }
-
- /**
- * Returns a read-only Map that maps InputDevice names to instances.
- * Names may be aliases and if so will map to the original instances. All
- * InputDevice instances in the map are initialized and registered with
- * any PhysicalEnvironments that reference them.
- *
- * @return read-only Map from names to InputDevice instances, or
- * null if no instances
- * @see #getInputDevices
- */
- public Map getNamedInputDevices() {
- if (deviceMap != null) return deviceMap ;
- deviceMap = createMap("Device") ;
- return deviceMap ;
- }
-
- /**
- * Returns a read-only Set of all configured Sensor instances in the order
- * they were defined in the configuration file. The associated
- * InputDevices are all initialized and registered with any
- * PhysicalEnvironments that reference them.
- * (NewSensor <instance name> <device name>
- * <sensor index> [Alias <alias name>])
- *
- *
- * device name is the instance name of a previously defined
- * InputDevice, and sensor index is the index of the Sensor to be
- * bound to instance name. The InputDevice implementation is
- * responsible for creating its own Sensor objects, so this command does
- * not create any new instances.
- * (SensorProperty <instance name> <property name>
- * <property value>)
- *
- *
- * With the sole exception of the Sensor assigned to the head tracker,
- * none of the Sensors defined in the configuration file are placed into
- * the Sensor array maintained by a PhysicalEnvironment.
- *
- * @return read-only Set of all unique instances, or null
- */
- public Set getSensors() {
- if (sensors != null) return sensors ;
- sensors = createSet("Sensor") ;
- return sensors ;
- }
-
- /**
- * Returns a read-only Map that maps Sensor names to instances. Names may
- * be aliases and if so will map to the original instances. The
- * associated InputDevices are all initialized and registered with any
- * PhysicalEnvironments that reference them.
- * (NewViewPlatform <instance name>
- * [Alias <alias name>])
- *
- *
- * The ViewingPlatform is configured through the following command:
- * (ViewPlatformProperty <instance name> <property name>
- * <property value>)
- *
- *
- * @return read-only Set of all unique instances, or null
- */
- public Set getViewingPlatforms() {
- if (platforms != null) return platforms ;
- platforms = createSet("ViewPlatform") ;
- return platforms ;
- }
-
- /**
- * Returns a read-only Map that maps ViewingPlatform names to instances.
- * Names may be aliases and if so will map to the original instances. The
- * ConfigContainer class itself does not attach the ViewingPlatform
- * instances to any scengraph components or universe Locales; they are not
- * "live" until made so by a separate client such as ConfiguredUniverse.
- *
- * @return read-only Map from names to ViewingPlatform instances, or
- * null if no instances
- */
- public Map getNamedViewingPlatforms() {
- if (platformMap != null) return platformMap ;
- platformMap = createMap("ViewPlatform") ;
- return platformMap ;
- }
-
- /**
- * Returns a read-only Set of all configured ViewPlatformBehavior
- * instances in the order they were defined in the configuration file.setViewPlatformBehavior
and
- * setViewingPlatform
methods of ViewingPlatform and
- * ViewPlatformBehavior have been called if appropriate. However, a
- * behavior's initialize
method is not called until the
- * ViewingPlatform to which it is attached is made live.
- * (NewViewPlatformBehavior <instanceName> <className>)
- *
- *
- * className must be the fully qualified name of a concrete class
- * that extends the abstract ViewPlatformBehavior class. The
- * implementation must provide a parameterless constructor.
- * (ViewPlatformBehaviorProperty <instanceName>
- * <propertyName> <arg0> ... <argn>)
- *
- *
- * ViewPlatformBehavior subclasses inherit a number of pre-defined
- * properties that can be directly specified with the propertyName
- * string; see the configuration file documentation for details.setViewPlatformBehavior
and
- * setViewingPlatform
methods of ViewingPlatform and
- * ViewPlatformBehavior have been called if appropriate. However, a
- * behavior's initialize
method is not called until the
- * ViewingPlatform to which it is attached is made live.
- * (ViewProperty <view> Screen <screenName>)
- *
- * view is the name of a Viewer created with the NewView command.
- * The screenName and windowName parameters of the above
- * commands are the keys to use when looking up the associated Canvas3D
- * instances in the Map returned by this method. Note: the
- * NewScreen and NewWindow commands do not create Canvas3D
- * instances themselves; they are created only by the above configuration
- * commands.
- *
- * @param viewName the name of the Viewer
- * @return read-only Map containing the Viewer's named Canvas3D instances
- */
- public Map getNamedCanvases(String viewName) {
- Map m = (Map)viewCanvasMap.get(viewName) ;
- if (m != null) return m ;
-
- m = new HashMap() ;
- ConfigView cv = (ConfigView)findConfigObject("View", viewName) ;
- Iterator i = cv.screens.iterator() ;
- while (i.hasNext()) {
- ConfigScreen cs = (ConfigScreen)i.next() ;
- m.put(cs.instanceName, cs.j3dCanvas) ;
-
- // The aliases list contains all alias strings for the canvas.
- Iterator j = cs.aliases.iterator() ;
- while (j.hasNext()) m.put(j.next(), cs.j3dCanvas) ;
- }
- m = new ReadOnlyMap(m) ;
- viewCanvasMap.put(viewName, m) ;
- return m ;
- }
-
- /**
- * Returns a read-only Set of all generic configuration object
- * instances in the order they were defined in the configuration file.
- * (ViewProperty <view> Window <windowName>)
- *
- * (NewObject <instanceName> <className>)
- *
- *
- * className must be the fully-qualified name of a class that
- * provides a parameterless constructor.
- * (ObjectProperty <instanceName> <propertyName>
- * <arg0> ... <argn>)
- *
- *
- * propertyName must be the name of a method provided by object
- * instanceName. It must take an array of Objects as its only
- * parameter; the array is populated with the values of arg0
- * through argn when the method is invoked to set the property.
- * These additional requirements for configurable objects can usually be
- * fulfilled by extending or wrapping available object classes.
- *
- * @return read-only Set of all unique instances, or null
- */
- public Set getGenericObjects() {
- if (genericObjects != null) return genericObjects ;
- genericObjects = createSet("Object") ;
- return genericObjects ;
- }
-
- /**
- * Returns a read-only Map that maps generic object names to
- * instances. Names may be aliases and if so will map to the original
- * instances.
- *
- * @return read-only Map from names to generic object instances, or
- * null if no instances
- * @see #getGenericObjects
- */
- public Map getNamedGenericObjects() {
- if (genericObjectMap != null) return genericObjectMap ;
- genericObjectMap = createMap("Object") ;
- return genericObjectMap ;
- }
-
- /**
- * Returns the number of TransformGroups with which ViewingPlatforms
- * should be created. This is useful for clients that wish to provide a
- * default ViewingPlatform if the configuration file doesn't specify one.
- *
- * @return the number of TransformGroups
- */
- public int getViewPlatformTransformCount() {
- return transformCount ;
- }
-
- /**
- * Returns whether Viewers should be created with their AWT components
- * initially visible or invisible. This is useful for clients that wish
- * to provide a default Viewer if the configuration file doesn't specify
- * one.
- *
- * @return true if Viewer components should be initially visible; false
- * otherwise
- */
- public boolean getViewerVisibility() {
- return setVisible ;
- }
-
- /**
- * Release memory references used by this ConfigContainer. All Sets and
- * Maps obtained from this ConfigContainer are cleared.
- */
- public void clear() {
- // Clear baseNameList.
- Iterator i = baseNameMap.values().iterator() ;
- while (i.hasNext()) ((Collection)i.next()).clear() ;
- baseNameMap.clear() ;
-
- // Clear viewCanvasMap.
- i = viewCanvasMap.values().iterator() ;
- while (i.hasNext()) ((ReadOnlyMap)i.next()).map.clear() ;
- viewCanvasMap.clear() ;
-
- // Release reference to file name.
- currentFileName = null ;
-
- // Clear and release sets.
- if (bodies != null) {
- bodies.collection.clear() ;
- bodies = null ;
- }
- if (environments != null) {
- environments.collection.clear() ;
- environments = null ;
- }
- if (devices != null) {
- devices.collection.clear() ;
- devices = null ;
- }
- if (sensors != null) {
- sensors.collection.clear() ;
- sensors = null ;
- }
- if (behaviors != null) {
- behaviors.collection.clear() ;
- behaviors = null ;
- }
- if (platforms != null) {
- platforms.collection.clear() ;
- platforms = null ;
- }
- if (viewers != null) {
- viewers.collection.clear() ;
- viewers = null ;
- }
- if (genericObjects != null) {
- genericObjects.collection.clear() ;
- genericObjects = null ;
- }
-
- // Clear and release maps.
- if (bodyMap != null) {
- bodyMap.map.clear() ;
- bodyMap = null ;
- }
- if (environmentMap != null) {
- environmentMap.map.clear() ;
- environmentMap = null ;
- }
- if (deviceMap != null) {
- deviceMap.map.clear() ;
- deviceMap = null ;
- }
- if (sensorMap != null) {
- sensorMap.map.clear() ;
- sensorMap = null ;
- }
- if (behaviorMap != null) {
- behaviorMap.map.clear() ;
- behaviorMap = null ;
- }
- if (platformMap != null) {
- platformMap.map.clear() ;
- platformMap = null ;
- }
- if (viewerMap != null) {
- viewerMap.map.clear() ;
- viewerMap = null ;
- }
- if (genericObjectMap != null) {
- genericObjectMap.map.clear() ;
- genericObjectMap = null ;
- }
-
- }
-
- /**
- * Returns the config file URL based on system properties. The current
- * implementation of this method parses the j3d.configURL property as a
- * URL string. For example, the following command line would specify that
- * the config file is taken from the file "j3dconfig" in the current
- * directory:
- *
- *
- *
- * @return the URL of the config file; null is returned if no valid
- * URL is defined by the system properties
- */
- public static URL getConfigURL() {
- return getConfigURL(null) ;
- }
-
- /**
- * Returns the config file URL based on system properties. The current
- * implementation of this method parses the j3d.configURL property as a
- * URL string. For example, the following command line would specify that
- * the config file is taken from the file "j3dconfig" in the current
- * directory:
- * java -Dj3d.configURL=file:j3dconfig ...
- *
- *
- *
- * @param defaultURLString the default string used to construct
- * the URL if the appropriate system properties are not defined
- * @return the URL of the config file; null is returned if no
- * valid URL is defined either by the system properties or the
- * default URL string
- */
- public static URL getConfigURL(String defaultURLString) {
- URL url = null ;
- String urlString = null ;
- final String defProp = defaultURLString ;
-
- urlString = (String)java.security.AccessController.doPrivileged
- (new java.security.PrivilegedAction() {
- @Override
- public Object run() {
- return System.getProperty("j3d.configURL", defProp) ;
- }
- }) ;
-
- if (urlString == null) {
- return null ;
- }
- try {
- url = new URL(urlString) ;
- }
- catch(MalformedURLException e) {
- System.out.println(e) ;
- return null ;
- }
- return url ;
- }
-
- // A general purpose read-only Map backed by a HashMap.
- private static class ReadOnlyMap extends AbstractMap {
- HashMap map ;
- private Set entrySet = null ;
-
- ReadOnlyMap(Map map) {
- this.map = new HashMap(map) ;
- }
-
- // overridden for efficiency
- @Override
- public Object get(Object key) {
- return map.get(key) ;
- }
-
- // overridden for efficiency
- @Override
- public boolean containsKey(Object key) {
- return map.containsKey(key) ;
- }
-
- // overridden for efficiency
- @Override
- public boolean containsValue(Object value) {
- return map.containsValue(value) ;
- }
-
- @Override
- public Set entrySet() {
- if (entrySet == null)
- entrySet = new ReadOnlySet(map.entrySet()) ;
-
- return entrySet ;
- }
- }
-
- // A general purpose read-only Set backed by a Collection containing
- // unique objects.
- private static class ReadOnlySet extends AbstractSet {
- Collection collection = null ;
-
- ReadOnlySet(Collection c) {
- this.collection = c ;
- }
-
- @Override
- public int size() {
- return collection.size() ;
- }
-
- @Override
- public Iterator iterator() {
- return new ReadOnlyIterator(collection.iterator()) ;
- }
- }
-
- // A general purpose read-only Iterator backed by another Iterator.
- private static class ReadOnlyIterator implements Iterator {
- private Iterator i ;
-
- ReadOnlyIterator(Iterator i) {
- this.i = i ;
- }
-
- @Override
- public boolean hasNext() {
- return i.hasNext() ;
- }
-
- @Override
- public Object next() {
- return i.next() ;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException() ;
- }
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfigDevice.java b/src/classes/share/com/sun/j3d/utils/universe/ConfigDevice.java
deleted file mode 100644
index 2102acc..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfigDevice.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe ;
-import javax.media.j3d.InputDevice;
-
-/**
- * Mostly empty now; ConfigObject provides all required methods.
- */
-class ConfigDevice extends ConfigObject {
- /**
- * The corresponding Java 3D core InputDevice instance.
- */
- InputDevice j3dInputDevice ;
-
- /**
- * Instantiate an InputDevice of the given class name.
- *
- * @return the InputDevice, or null if error
- */
- InputDevice createInputDevice() {
- j3dInputDevice = (InputDevice)createTargetObject() ;
- return j3dInputDevice ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfigObject.java b/src/classes/share/com/sun/j3d/utils/universe/ConfigObject.java
deleted file mode 100644
index 8051ada..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfigObject.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe ;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Base class for all configuration objects. A ConfigObject processes
- * configuration parameters for a target object, which is instantiated after
- * the configuration file is parsed. The ConfigObject then applies its
- * configuration properties to the target object.java -Dj3d.configURL=file:j3dconfig ...
- *
- * (ViewPlatformProperty {instanceName} {attrName} {attrValue})
- *
- * @param command the command that invoked this method
- */
- @Override
- protected void setProperty(ConfigCommand command) {
-
- int argc = command.argc ;
- Object[] argv = command.argv ;
- String attribute ;
- Object value ;
-
- if (argc != 4) {
- syntaxError("Incorrect number of arguments to " +
- command.commandName) ;
- }
-
- if (!isName(argv[2])) {
- syntaxError("The second argument to " + command.commandName +
- " must be a property name");
- }
-
- attribute = (String)argv[2] ;
- value = argv[3] ;
-
- if (attribute.equals("NominalViewingTransform")) {
- if (! (value instanceof Boolean)) {
- syntaxError("NominalViewingTransform must be a boolean") ;
- }
- nominalViewingTransform = ((Boolean)value).booleanValue() ;
- }
- else if (attribute.equals("InitialViewingTransform")) {
- if (! (value instanceof Matrix4d)) {
- syntaxError("InitialViewingTransform must be a Matrix4d") ;
- }
- initialViewingTransform = new Transform3D((Matrix4d)value) ;
- }
- else if (attribute.equals("ViewAttachPolicy")) {
- if (! (value instanceof String)) {
- syntaxError("ViewAttachPolicy must be a string") ;
- }
-
- String svalue = (String)value ;
-
- if (svalue.equals("NOMINAL_HEAD"))
- viewAttachPolicy = View.NOMINAL_HEAD ;
- else if (svalue.equals("NOMINAL_SCREEN"))
- viewAttachPolicy = View.NOMINAL_SCREEN ;
- else if (svalue.equals("NOMINAL_FEET"))
- viewAttachPolicy = View.NOMINAL_FEET ;
- else
- syntaxError("Illegal value " +
- svalue + " for ViewAttachPolicy") ;
- }
- else if (attribute.equals("ViewPlatformBehavior")) {
- if (! (value instanceof String)) {
- syntaxError("ViewPlatformBehavior must be a name") ;
- }
- configBehavior =
- (ConfigViewPlatformBehavior)configContainer.findConfigObject
- ("ViewPlatformBehavior", (String)value) ;
- }
- else if (attribute.equals("AllowPolicyRead")) {
- if (!(value instanceof Boolean)) {
- syntaxError("value for AllowPolicyRead " +
- "must be a boolean") ;
- }
- allowPolicyRead = ((Boolean)value).booleanValue() ;
- }
- else if (attribute.equals("AllowLocalToVworldRead")) {
- if (!(value instanceof Boolean)) {
- syntaxError("value for AllowLocalToVworldRead " +
- "must be a boolean") ;
- }
- allowLocalToVworldRead = ((Boolean)value).booleanValue() ;
- }
- else {
- syntaxError("Unknown " + command.commandName +
- " \"" + attribute + "\"") ;
- }
- }
-
- /**
- * Add a ConfigView to this ConfigViewPlatform.
- */
- void addConfigView(ConfigView cv) {
- configViews.add(cv) ;
- }
-
- /**
- * Creates a ViewingPlatform from attributes gathered by this object.
- *
- * @param transformCount the number of TransformGroups to attach to the
- * ViewingPlatform
- * @return the new ViewingPlatform
- */
- ViewingPlatform createViewingPlatform(int transformCount) {
-
- // Get the Viewers attached to this ViewingPlatform.
- // All ConfigViews must be processed at this point.
- if (configViews.size() == 0) {
- viewers = new Viewer[0] ;
- }
- else {
- viewers = new Viewer[configViews.size()] ;
- for (int i = 0 ; i < viewers.length ; i++)
- viewers[i] = ((ConfigView)configViews.get(i)).j3dViewer ;
- }
-
- // Create the viewing platform and get its ViewPlatform instance.
- viewingPlatform = new ViewingPlatform(transformCount) ;
- ViewPlatform vp = viewingPlatform.getViewPlatform() ;
-
- // Set defined policies.
- if (allowPolicyRead)
- vp.setCapability(ViewPlatform.ALLOW_POLICY_READ) ;
-
- if (allowLocalToVworldRead)
- vp.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ) ;
-
- if (viewAttachPolicy == -1) {
- // Apply a default based on the eyepoint policy.
- boolean nominalHead = true ;
- for (int i = 0 ; i < viewers.length ; i++) {
- if (viewers[i].getView().getWindowEyepointPolicy() !=
- View.RELATIVE_TO_FIELD_OF_VIEW) {
- nominalHead = false ;
- break ;
- }
- }
- if (nominalHead)
- vp.setViewAttachPolicy(View.NOMINAL_HEAD) ;
- else
- vp.setViewAttachPolicy(View.NOMINAL_SCREEN) ;
- }
- else {
- vp.setViewAttachPolicy(viewAttachPolicy) ;
- }
-
- // Assign the viewing platform to all viewers.
- for (int i = 0 ; i < viewers.length ; i++) {
- viewers[i].setViewingPlatform(viewingPlatform) ;
- }
-
- // Apply initial viewing transforms if defined.
- if (nominalViewingTransform) {
- viewingPlatform.setNominalViewingTransform() ;
- }
-
- if (initialViewingTransform != null) {
- TransformGroup tg = viewingPlatform.getViewPlatformTransform() ;
- tg.setTransform(initialViewingTransform) ;
- }
-
- return viewingPlatform ;
- }
-
- /**
- * Attach any ViewPlatformBehavior specified for this platform.
- */
- void processBehavior() {
- if (configBehavior != null) {
- viewingPlatform.setViewPlatformBehavior
- (configBehavior.viewPlatformBehavior) ;
- }
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatformBehavior.java b/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatformBehavior.java
deleted file mode 100644
index 2b0d10b..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/ConfigViewPlatformBehavior.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe ;
-
-import javax.media.j3d.Bounds;
-import javax.media.j3d.Transform3D;
-import javax.vecmath.Matrix4d;
-
-import com.sun.j3d.utils.behaviors.vp.ViewPlatformBehavior;
-
-class ConfigViewPlatformBehavior extends ConfigObject {
-
- // All known configurable properties.
- private Transform3D homeTransform = null ;
- private Bounds schedulingBounds = null ;
- private int schedulingInterval = -1 ;
-
- /**
- * The corresponding ViewPlatformBehavior instance.
- */
- ViewPlatformBehavior viewPlatformBehavior ;
-
- /**
- * Processes properties for this object. Handles commands of the form:SimpleUniverse()
. Creates a
- * Locale, a single ViewingPlatform, and a Viewer object.
- *
- * @see SimpleUniverse#SimpleUniverse()
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- */
- public ConfiguredUniverse() {
- super();
- }
-
- /**
- * Equivalent to SimpleUniverse(int)
.
- * Creates a Locale, a single ViewingPlatform with the specified number of
- * transforms, and a Viewer object.
- *
- * @param transformCount the number of transforms in the
- * MultiTransformGroup object to be created
- *
- * @see SimpleUniverse#SimpleUniverse(int)
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- */
- public ConfiguredUniverse(int transformCount) {
- super(transformCount);
- }
-
- /**
- * Equivalent to SimpleUniverse(Canvas3D)
.
- * Creates a Locale, a single ViewingPlatform, and a Viewer object using
- * the given Canvas3D instance.
- *
- * @param canvas the canvas to associate with the Viewer object;
- * passing in null will cause this parameter to be ignored and a canvas
- * to be created by the utility
- *
- * @see SimpleUniverse#SimpleUniverse(Canvas3D)
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- */
- public ConfiguredUniverse(Canvas3D canvas) {
- super(canvas);
- }
-
- /**
- * Equivalent to SimpleUniverse(Canvas3D, int)
.
- * Creates a Locale, a single ViewingPlatform with the specified number of
- * transforms, and a Viewer object with the given Canvas3D.
- *
- * @param canvas the canvas to associate with the Viewer object;
- * passing in null will cause this parameter to be ignored and a canvas
- * to be created by the utility
- * @param transformCount the number of transforms in the
- * MultiTransformGroup object to be created
- *
- * @see SimpleUniverse#SimpleUniverse(Canvas3D, int)
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- */
- public ConfiguredUniverse(Canvas3D canvas, int transformCount) {
- super(canvas, transformCount);
- }
-
- /**
- * Equivalent to SimpleUniverse(ViewingPlatform, Viewer)
.
- * Creates the view side of the scene graph with the given ViewingPlatform
- * and Viewer.
- *
- * @param viewingPlatform the viewingPlatform to use to create
- * the view side of the scene graph
- * @param viewer the viewer object to use to create
- * the view side of the scene graph
- *
- * @see SimpleUniverse#SimpleUniverse(ViewingPlatform, Viewer)
- * @see ViewingPlatform
- * @see Viewer
- */
- public ConfiguredUniverse(ViewingPlatform viewingPlatform, Viewer viewer) {
- super(viewingPlatform, viewer, null);
- }
-
- /**
- * Equivalent to SimpleUniverse(ViewingPlatform, Viewer,
- * LocalFactory)
. Creates the view side of the scene graph with
- * the given ViewingPlatform, Viewer, and Locale created by the specified
- * LocaleFactory.
- *
- * @param viewingPlatform the viewingPlatform to use to create
- * the view side of the scene graph
- * @param viewer the viewer object to use to create
- * the view side of the scene graph
- * @param localeFactory the factory object used to create the Locale
- *
- * @see SimpleUniverse#SimpleUniverse(ViewingPlatform, Viewer,
- * LocaleFactory)
- * @see ViewingPlatform
- * @see Viewer
- * @see LocaleFactory
- */
- public ConfiguredUniverse(ViewingPlatform viewingPlatform, Viewer viewer,
- LocaleFactory localeFactory ) {
- super(viewingPlatform, viewer, localeFactory);
- }
-
- /**
- * Creates a Locale, a single ViewingPlatform, and a Viewer object from
- * the given array of Canvas3D instances.
- *
- * @param canvases the canvases to associate with the Viewer object;
- * passing in null will cause this parameter to be ignored and a canvas
- * to be created by the utility
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- */
- public ConfiguredUniverse(Canvas3D[] canvases) {
- this(1, canvases, null, null, null, true);
- }
-
- /**
- * Creates a Locale, a single ViewingPlatform with the specified number of
- * transforms, and a Viewer object using the given array of Canvas3D
- * instances.
- *
- * @param canvases the canvases to associate with the Viewer object;
- * passing in null will cause this parameter to be ignored and a canvas
- * to be created by the utility
- * @param transformCount the number of transforms in the
- * MultiTransformGroup object to be created
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- */
- public ConfiguredUniverse(Canvas3D[] canvases, int transformCount) {
- this(transformCount, canvases, null, null, null, true);
- }
-
- /**
- * Creates a Locale, a single ViewingPlatform with the specified number of
- * transforms, and a Viewer object using the given array of Canvas3D
- * instances.
- *
- * @param canvases the canvases to associate with the Viewer object;
- * passing in null will cause this parameter to be ignored and a canvas
- * to be created by the utility
- * @param transformCount the number of transforms in the
- * MultiTransformGroup object to be created
- * @param localeFactory the factory object used to create the Locale
- *
- * @since Java 3D 1.5.1
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- */
- public ConfiguredUniverse(Canvas3D[] canvases, int transformCount, LocaleFactory localeFactory ) {
- this(transformCount, canvases, null, localeFactory, null, true);
- }
-
- /**
- * Reads the configuration specified by the given URL to create a Locale,
- * one or more ViewingPlatforms, and at least one Viewer object. The
- * configuration file may also create InputDevice, Sensor, and
- * ViewPlatformBehavior instances.
- *
- * @param userConfig the URL to the user's configuration file; passing in
- * null creates a default Viewer and ViewingPlatform
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- */
- public ConfiguredUniverse(URL userConfig) {
- this(1, null, userConfig, null, null, true);
- }
-
- /**
- * Reads the configuration specified by the given URL to create a Locale,
- * one or more ViewingPlatforms with the specified number of transforms,
- * and at least one Viewer object. The configuration file may also create
- * InputDevice, Sensor, and ViewPlatformBehavior instances.
- *
- * @param userConfig the URL to the user's configuration file; passing in
- * null creates a default Viewer and ViewingPlatform with the specified
- * number of transforms
- * @param transformCount the number of transforms in the
- * MultiTransformGroup objects to be created
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- */
- public ConfiguredUniverse(URL userConfig, int transformCount) {
- this(transformCount, null, userConfig, null, null, true);
- }
-
- /**
- * Reads the configuration specified by the given URL to create a Locale,
- * one or more ViewingPlatforms with the specified number of transforms,
- * and at least one Viewer object with optional visibility. AWT
- * components used by the Viewers will remain invisible unless the
- * setVisible
flag is true. The configuration file may also
- * create InputDevice, Sensor, and ViewPlatformBehavior instances.
- *
- * @param userConfig the URL to the user's configuration file; passing in
- * null creates a default Viewer with the specified visibility and a
- * ViewingPlatform with the specified number of transforms
- * @param transformCount the number of transforms in the
- * MultiTransformGroup object to be created
- * @param setVisible if true, calls setVisible(true)
on all
- * created window components; otherwise, they remain invisible
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- */
- public ConfiguredUniverse(URL userConfig,
- int transformCount, boolean setVisible) {
- this(transformCount, null, userConfig, null, null, setVisible);
- }
-
- /**
- * Reads the configuration specified by the given URL to create a Locale
- * using the given LocaleFactory, one or more ViewingPlatforms, and at
- * least one Viewer object. The configuration file may also create
- * InputDevice, Sensor, and ViewPlatformBehavior instances.
- *
- * @param userConfig the URL to the user's configuration file; passing in
- * null creates a default Viewer and ViewingPlatform with the specified
- * number of transforms
- * @param localeFactory the factory object used to create the Locale
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- */
- public ConfiguredUniverse(URL userConfig, LocaleFactory localeFactory) {
- this(1, null, userConfig, localeFactory, null, true);
- }
-
- /**
- * Reads the configuration specified by the given URL to create a Locale
- * using the given LocaleFactory, one or more ViewingPlatforms, and at
- * least one Viewer object with optional visibility. The configuration
- * file may also create InputDevice, Sensor, and ViewPlatformBehavior
- * instances. Window components used by the Viewers will remain invisible
- * unless the setVisible
flag is true.
- *
- * @param userConfig the URL to the user's configuration file; passing in
- * null creates a default Viewer with the specified visibility and a
- * default ViewingPlatform
- * @param localeFactory the factory object used to create the Locale
- * @param setVisible if true, calls setVisible(true)
on all
- * created window components; otherwise, they remain invisible
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- */
- public ConfiguredUniverse(URL userConfig,
- LocaleFactory localeFactory,
- boolean setVisible) {
- this(1, null, userConfig, localeFactory, null, setVisible);
- }
-
- /**
- * Reads the configuration specified by the given URL to create a Locale
- * using the specified LocaleFactory with the given origin, one or more
- * ViewingPlatforms with the specified number of transforms, and at least
- * one Viewer object with optional visibility. Window components used by
- * the Viewers will remain invisible unless the setVisible
- * flag is true. The configuration file may also create InputDevice,
- * Sensor, and ViewPlatformBehavior instances.
- *
- * @param userConfig the URL to the user's configuration file; passing in
- * null creates a default Viewer with the specified visibility and a
- * ViewingPlatform with the specified number of transforms
- * @param localeFactory the factory object used to create the Locale
- * @param origin the origin used to set the origin of the Locale object;
- * if this object is null, then 0.0 is used
- * @param transformCount the number of transforms in the
- * MultiTransformGroup object to be created
- * @param setVisible if true, calls setVisible(true)
on all
- * created window components; otherwise, they remain invisible
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- */
- public ConfiguredUniverse(URL userConfig, LocaleFactory localeFactory,
- HiResCoord origin, int transformCount,
- boolean setVisible) {
-
- this(transformCount, null, userConfig,
- localeFactory, origin, setVisible);
- }
-
- /**
- * Retrieves view-side scenegraph components from the given container to
- * create a universe with one Locale, one or more ViewingPlatforms, and at
- * least one Viewer object. Equivalent to
- * ConfiguredUniverse(ConfigContainer, null, null)
.
- *
- * @param userConfig container holding viewing configuration components;
- * must not be null
- *
- * @see #ConfiguredUniverse(ConfigContainer, LocaleFactory, HiResCoord)
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @since Java 3D 1.3.1
- */
- public ConfiguredUniverse(ConfigContainer userConfig) {
- this(userConfig, null, null);
- }
-
- /**
- * Retrieves view-side scenegraph components from the given container to
- * create a universe with one Locale created from the specified
- * LocaleFactory and origin, one or more ViewingPlatforms, and at least
- * one Viewer object. The container may also provide InputDevice, Sensor,
- * and ViewPlatformBehavior instances which will be incorporated into the
- * universe if they are referenced by any of the Viewer or ViewingPlatform
- * instances.ConfiguredUniverse(ConfigContainer)
- * both accept ConfigContainer references directly and are the preferred
- * interfaces for constructing universes from configuration files. They
- * differ from the constructors that accept URL objects in the
- * following ways:
- *
- * @param userConfig container holding viewing configuration components;
- * must not be null
- * @param localeFactory the factory object used to create the Locale, or
- * null
- * @param origin the origin used to set the origin of the Locale object;
- * if this object is null, then 0.0 is used
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @since Java 3D 1.3.1
- */
- public ConfiguredUniverse(ConfigContainer userConfig,
- LocaleFactory localeFactory,
- HiResCoord origin) {
-
- super(origin, localeFactory);
- configContainer = userConfig;
-
- Collection c = configContainer.getViewers();
- if (c == null || c.size() == 0)
- throw new IllegalArgumentException(
- "no views defined in configuration file");
-
- viewer = (Viewer[])c.toArray(new Viewer[1]);
-
- c = configContainer.getViewingPlatforms();
- if (c == null || c.size() == 0) {
- createDefaultViewingPlatform
- (configContainer.getViewPlatformTransformCount());
- }
- else {
- Iterator i = c.iterator();
- while (i.hasNext()) {
- ViewingPlatform vp = (ViewingPlatform)i.next();
- vp.setUniverse(this);
- locale.addBranchGraph(vp);
- }
- }
- }
-
- /**
- * Package-scope constructor that creates the view side of the
- * scene graph. The passed in parameters override the default
- * values where appropriate. Note that the userCanvases parameter
- * is ignored when the userConfig is non-null.
- *
- * @param transformCount the number of transforms in the
- * MultiTransformGroup object to be created
- * @param canvases the canvases to associate with the Viewer object;
- * passing in null will cause this parameter to be ignored and a canvas
- * to be created by the utility
- * @param userConfig the URL to the user's configuration file; passing in
- * null causes the default values to be used.
- * @param localeFactory the factory object used to create the Locale
- * @param origin the origin used to set the origin of the Locale object;
- * if this object is null, then 0.0 is used
- * @param setVisible if true, calls setViewingPlatform
method is called; it must wait
- * until its initialize
method is called.setVisible(true)
on all
- * created window components; otherwise, they remain invisible
- *
- * @see Locale
- * @see Viewer
- * @see ViewingPlatform
- * @see MultiTransformGroup
- */
- ConfiguredUniverse(int transformCount,
- Canvas3D[] canvases,
- URL userConfig,
- LocaleFactory localeFactory,
- HiResCoord origin,
- boolean setVisible) {
-
- super(origin, localeFactory);
-
- if (userConfig == null) {
- viewer = new Viewer[1];
- viewer[0] = new Viewer(canvases, null, null, setVisible);
- createDefaultViewingPlatform(transformCount);
- }
- else {
- // Create a ConfigContainer without attaching behaviors. The
- // package-scope constructor is used for backward compatibility.
- configContainer = new ConfigContainer
- (userConfig, setVisible, transformCount, false);
-
- Collection c = configContainer.getViewers();
- if (c == null || c.size() == 0)
- throw new IllegalArgumentException(
- "no views defined in configuration file");
-
- viewer = (Viewer[])c.toArray(new Viewer[1]);
-
- // Get ViewingPlatforms from the ConfigContainer and add them to
- // the locale. The package-scoped findConfigObjects() accesor is
- // used so that backward compatibility can be maintained for older
- // configuration files.
- c = configContainer.findConfigObjects("ViewPlatform");
- if (c == null || c.size() == 0) {
- createDefaultViewingPlatform(transformCount);
- }
- else {
- Iterator i = c.iterator();
- while (i.hasNext()) {
- ConfigViewPlatform cvp = (ConfigViewPlatform)i.next();
- ViewingPlatform vp = cvp.viewingPlatform;
-
- // For backward compatibility, handle the default
- // attachment of one Viewer to one ViewingPlatform. If
- // there are multiple Viewers and ViewingPlatforms then
- // attachments must be made explicitly in the config file.
- if (vp.getViewers() == null &&
- viewer.length == 1 && c.size() == 1) {
- if (cvp.viewAttachPolicy == -1) {
- setDerivedAttachPolicy(viewer[0], vp) ;
- }
- viewer[0].setViewingPlatform(vp);
- }
- vp.setUniverse(this);
- locale.addBranchGraph(vp);
-
- // If there's a behavior associated with the platform,
- // attach it now after the setting the universe reference.
- cvp.processBehavior();
- }
- }
- }
- }
-
- /**
- * Creates a default ViewingPlatform, attaches the first Viewer, and then
- * attaches the platform to the Locale.
- *
- * @param transformCount number of TransformGroups to create in the
- * ViewingPlatform
- */
- private void createDefaultViewingPlatform(int transformCount) {
- ViewingPlatform vp = new ViewingPlatform(transformCount);
- setDerivedAttachPolicy(viewer[0], vp);
- viewer[0].setViewingPlatform(vp);
- vp.setUniverse(this);
- locale.addBranchGraph(vp);
- }
-
- /**
- * Sets a view attach policy appropriate for a window eyepoint policy.
- *
- * @param v Viewer to which the ViewingPlatform will be attached
- * @param vp ViewingPlatform to which the Viewer will be attached
- */
- private void setDerivedAttachPolicy(Viewer v, ViewingPlatform vp) {
- if (v.getView().getWindowEyepointPolicy() !=
- View.RELATIVE_TO_FIELD_OF_VIEW) {
- vp.getViewPlatform().setViewAttachPolicy(View.NOMINAL_SCREEN);
- }
- }
-
-
- /**
- * Returns the Viewer object specified by the given index.
- *
- * @param index The index of which Viewer object to return.
- *
- * @return The Viewer object specified by the given index.
- */
- public Viewer getViewer(int index) {
- return viewer[index];
- }
-
- /**
- * Returns all of the Viewer objects associated with this scene graph.
- *
- * @return The Viewer objects associated with this scene graph.
- */
- public Viewer[] getViewers() {
- Viewer[] ret = new Viewer[viewer.length];
- for (int i = 0; i < viewer.length; i++) {
- ret[i] = viewer[i];
- }
- return ret;
- }
-
- /**
- * Call setVisible()
on all AWT components created by this
- * ConfiguredUniverse instance.setVisible()
- * calls on the window components created by this
- * ConfiguredUniverse instance
- */
- public void setVisible(boolean visible) {
- for (int i = 0; i < viewer.length; i++)
- if (viewer[i] != null)
- viewer[i].setVisible(visible);
- }
-
- /**
- * Returns the config file URL based on system properties. This is
- * equivalent to calling ConfigContainer.getConfigURL()
. The
- * current implementation of this method parses the j3d.configURL property
- * as a URL string. For example, the following command line would specify
- * that the config file is taken from the file "j3dconfig" in the current
- * directory:
- *
- *
- *
- * @return the URL of the config file; null is returned if no valid
- * URL is defined by the system properties
- */
- public static URL getConfigURL() {
- return ConfigContainer.getConfigURL(null);
- }
-
- /**
- * Returns the config file URL based on system properties. This is the
- * same as calling java -Dj3d.configURL=file:j3dconfig ...
- * ConfigContainer.getConfigURL(String)
. The
- * current implementation of this method parses the j3d.configURL property
- * as a URL string. For example, the following command line would specify
- * that the config file is taken from the file "j3dconfig" in the current
- * directory:
- *
- *
- *
- * @param defaultURLString the default string used to construct
- * the URL if the appropriate system properties are not defined
- * @return the URL of the config file; null is returned if no
- * valid URL is defined either by the system properties or the
- * default URL string
- */
- public static URL getConfigURL(String defaultURLString) {
- return ConfigContainer.getConfigURL(defaultURLString);
- }
-
- /**
- * Returns all named Sensors defined by the configuration file used to
- * create the ConfiguredUniverse, if any. Equivalent to
- * java -Dj3d.configURL=file:j3dconfig ...
- * getConfigContainer().getNamedSensors()
.getConfigContainer().getNamedViewPlatformBehaviors()
.GraphicsConfiguration
object
- * for the system. This object can then be used to create the
- * Canvas3D objet for this system.
- *
- * @return The best GraphicsConfiguration
object for
- * the system.
- */
- public static GraphicsConfiguration getPreferredConfiguration() {
- GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D();
-
- // Check if the user has set the Java 3D stereo option.
- // Getting the system properties causes appletviewer to fail with a
- // security exception without a try/catch.
- String stereo = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedActiongetImagePlateToVworld
- * and other methods in the core Java 3D classes use a transform from view
- * platform coordinates to virtual world coordinates that can be out of date
- * with respect to the state of the view platform as set by the application.
- * When an application uses the transforms returned by those methods to update
- * view dependent parts of the scene graph, those updates might not be
- * synchronized with what the viewer actually sees.ALLOW_LOCAL_TO_VWORLD_READ
capability
- * set, which potentially inhibits internal scene graph optimization.ALLOW_LOCAL_TO_VWORLD_READ
view platform
- * capability doesn't need to be set for these applications.
- *
- *
getUserHeadToVworld
method always incorporates a virtual world
- * transform that is out of date with respect to the application scene graph
- * state. ViewInfo reads data from the head tracking sensor directly, but
- * since head trackers are continuous input devices, getting the same data
- * that the renderer is using is unlikely. See the source code for the
- * private method getHeadInfo
in this class for more information
- * and possible workarounds.updateScreen
,
- * updateCanvas
, updateViewPlatform
,
- * updateView
, and updateHead
methods just set flags
- * indicating that derived transforms need to be recomputed; they are safe to
- * call from any thread. updateCanvas
, for example, can safely
- * be called from an AWT event listener.localToVworld
- * transform should be automatically checked with each call to a public
- * method in this class. The View must be attached to a ViewPlatform
- * which is part of a live scene graph, and the ViewPlatform node must
- * have its ALLOW_LOCAL_TO_VWORLD_READ
capability set.
- */
- public final static int PLATFORM_AUTO_UPDATE = 16 ;
-
- //
- // Screen3D and ViewPlatform instances are shared across multiple Views in
- // the Java 3D view model. Since ViewInfo is per-View and we want to
- // cache screen and platform derived data, we maintain static references
- // to the screens and platforms here.
- //
- // From a design standpoint our ViewInfo objects should probably be in the
- // scope of an object that encloses these maps so they can be gc'ed
- // properly. This is cumbersome with the current design constraints, so
- // for now we provide an alternative constructor to override these static
- // maps and a method to explicitly clear them. The alternative
- // constructor can be used to wrap this class into a multi-view context
- // that provides the maps.
- //
- private static Map staticVpMap = new HashMap() ;
- private static Map staticSiMap = new HashMap() ;
-
- private Map screenMap = null ;
- private Map viewPlatformMap = null ;
-
- // The target View and some derived data.
- private View view = null ;
- private Sensor headTracker = null ;
- private boolean useTracking = false ;
- private boolean clipVirtual = false ;
-
- // The current ViewPlatform and Canvas3D information used by this object.
- private ViewPlatformInfo vpi = null ;
- private int canvasCount = 0 ;
- private Map canvasMap = new HashMap() ;
- private CanvasInfo[] canvasInfo = new CanvasInfo[1] ;
-
- // This View's update flags. The other update flags are maintained by
- // ScreenInfo, CanvasInfo, and ViewPlatformInfo.
- private boolean updateView = true ;
- private boolean updateHead = true ;
- private boolean autoUpdate = false ;
- private int autoUpdateFlags = 0 ;
-
- // Cached View policies.
- private int viewPolicy = View.SCREEN_VIEW ;
- private int resizePolicy = View.PHYSICAL_WORLD ;
- private int movementPolicy = View.PHYSICAL_WORLD ;
- private int eyePolicy = View.RELATIVE_TO_FIELD_OF_VIEW ;
- private int projectionPolicy = View.PERSPECTIVE_PROJECTION ;
- private int frontClipPolicy = View.PHYSICAL_EYE ;
- private int backClipPolicy = View.PHYSICAL_EYE ;
- private int scalePolicy = View.SCALE_SCREEN_SIZE ;
- private boolean coeCentering = true ;
-
- // This View's cached transforms. See ScreenInfo, CanvasInfo, and
- // ViewPlatformInfo for the rest of the cached transforms.
- private Transform3D coeToTrackerBase = null ;
- private Transform3D headToHeadTracker = null ;
-
- // These are from the head tracker read.
- private Transform3D headTrackerToTrackerBase = null ;
- private Transform3D trackerBaseToHeadTracker = null ;
-
- // These are derived from the head tracker read.
- private Transform3D headToTrackerBase = null ;
- private Transform3D coeToHeadTracker = null ;
-
- // Cached physical body and environment.
- private PhysicalEnvironment env = null ;
- private PhysicalBody body = null ;
- private Point3d leftEyeInHead = new Point3d() ;
- private Point3d rightEyeInHead = new Point3d() ;
-
- // Temporary variables. These could just be new'ed as needed, but we'll
- // assume that ViewInfo instances are used much more than they're created.
- private Vector3d v3d = new Vector3d() ;
- private double[] m16d = new double[16] ;
- private Point3d leftEye = new Point3d() ;
- private Point3d rightEye = new Point3d() ;
- private Map newMap = new HashMap() ;
- private Set newSet = new HashSet() ;
-
- /**
- * Creates a new ViewInfo for the specified View.localToVworld
transform. These
- * notifications are performed with the updateView
,
- * updateCanvas
, updateScreen
,
- * updateHead
, and updateViewPlatform
- * methods.ALLOW_POLICY_READ
- * capability must be set on the ViewPlatform node.
- *
- * @param view the View to use
- * @see #updateView
- * @see #updateCanvas updateCanvas(Canvas3D)
- * @see #updateScreen updateScreen(Screen3D)
- * @see #updateHead
- * @see #updateViewPlatform
- */
- public ViewInfo(View view) {
- this(view, 0) ;
- }
-
- /**
- * Creates a new ViewInfo for the specified View. The View must be
- * attached to a ViewPlatform. If the ViewPlatform is attached to a live
- * scene graph, then ALLOW_POLICY_READ
capability must be set
- * on the ViewPlatform node.
- *
- * @param view the View to useOR
of any of the
- * VIEW_AUTO_UPDATE
, CANVAS_AUTO_UPDATE
,
- * SCREEN_AUTO_UPDATE
, HEAD_AUTO_UPDATE
, or
- * PLATFORM_AUTO_UPDATE
flags to control whether changes to
- * the View, its Canvas3D or Screen3D components, the tracked head
- * position, or the ViewPlatform's localToVworld
transform
- * are checked automatically with each call to a public method of this
- * class; if a flag is not set, then the application must inform this
- * class of updates to the corresponding data
- */
- public ViewInfo(View view, int autoUpdateFlags) {
- this(view, autoUpdateFlags, staticSiMap, staticVpMap) ;
- }
-
- /**
- * Creates a new ViewInfo for the specified View. The View must be
- * attached to a ViewPlatform. If the ViewPlatform is attached to a live
- * scene graph, then ALLOW_POLICY_READ
capability must be set
- * on the ViewPlatform node.ViewInfo.clear
when done with ViewInfo, or by simply
- * retaining the static references until the JVM exits.OR
of any of the
- * VIEW_AUTO_UPDATE
, CANVAS_AUTO_UPDATE
,
- * SCREEN_AUTO_UPDATE
, HEAD_AUTO_UPDATE
, or
- * PLATFORM_AUTO_UPDATE
flags to control whether changes to
- * the View, its Canvas3D or Screen3D components, the tracked head
- * position, or the ViewPlatform's localToVworld
transform
- * are checked automatically with each call to a public method of this
- * class; if a flag is not set, then the application must inform this
- * class of updates to the corresponding dataALLOW_LOCAL_TO_VWORLD_READ
capability set.
- *
- * @param c3d the Canvas3D associated with the image plate
- * @param ip2vwl the Transform3D to receive the left transform
- * @param ip2vwr the Transform3D to receive the right transform, or null
- */
- public void getImagePlateToVworld(Canvas3D c3d,
- Transform3D ip2vwl, Transform3D ip2vwr) {
-
- CanvasInfo ci = updateCache(c3d, "getImagePlateToVworld", true) ;
- getImagePlateToVworld(ci) ;
- ip2vwl.set(ci.plateToVworld) ;
- if (ci.useStereo && ip2vwr != null)
- ip2vwr.set(ci.rightPlateToVworld) ;
- }
-
- private void getImagePlateToVworld(CanvasInfo ci) {
- if (ci.updatePlateToVworld) {
- if (verbose) System.err.println("updating PlateToVworld") ;
- if (ci.plateToVworld == null)
- ci.plateToVworld = new Transform3D() ;
-
- getImagePlateToViewPlatform(ci) ;
- ci.plateToVworld.mul
- (vpi.viewPlatformToVworld, ci.plateToViewPlatform) ;
-
- if (ci.useStereo) {
- if (ci.rightPlateToVworld == null)
- ci.rightPlateToVworld = new Transform3D() ;
-
- ci.rightPlateToVworld.mul
- (vpi.viewPlatformToVworld, ci.rightPlateToViewPlatform) ;
- }
- ci.updatePlateToVworld = false ;
- }
- }
-
- /**
- * Gets the current transforms from coexistence coordinates to image plate
- * coordinates and copies them into the given Transform3Ds. The default
- * coexistence centering enable and window movement policies are
- * true
and PHYSICAL_WORLD
respectively, which
- * will center coexistence coordinates to the middle of the canvas,
- * aligned with the screen (image plate). A movement policy of
- * VIRTUAL_WORLD
centers coexistence coordinates to the
- * middle of the screen.trackerBaseToImagePlate
transform and the
- * PhysicalEnvironment coexistenceToTrackerBase
transform.
- * These are calibration constants used for multiple fixed screen displays.
- * For head mounted displays the transform is determined by the user head
- * position along with calibration parameters found in Screen3D and
- * PhysicalBody. (See the source code for the private method
- * getEyesHMD
for more information).
- *
- *
- *
- * @param c3d the Canvas3D to use
- * @param vp2coe the Transform3D to receive the transform
- */
- public void getViewPlatformToCoexistence(Canvas3D c3d,
- Transform3D vp2coe) {
-
- CanvasInfo ci = updateCache
- (c3d, "getViewPlatformToCoexistence", false) ;
-
- getViewPlatformToCoexistence(ci) ;
- vp2coe.set(ci.viewPlatformToCoe) ;
- }
-
- private void getViewPlatformToCoexistence(CanvasInfo ci) {
- if (!ci.updateViewPlatformToCoe) return ;
- if (verbose) System.err.println("updating ViewPlatformToCoe") ;
- if (ci.viewPlatformToCoe == null)
- ci.viewPlatformToCoe = new Transform3D() ;
- //
- // The scale from view platform coordinates to coexistence coordinates
- // has two components -- the screen scale and the window scale. The
- // window scale only applies if the resize policy is PHYSICAL_WORLD.
- //
- // This scale is not the same as the vworld to view platform scale.
- // The latter is contained in the view platform's localToVworld
- // transform as defined by the scene graph. The complete scale factor
- // from virtual units to physical units is the product of the vworld
- // to view platform scale and the view platform to coexistence scale.
- //
- getScreenScale(ci) ;
- if (resizePolicy == View.PHYSICAL_WORLD)
- ci.viewPlatformToCoe.setScale(ci.screenScale * ci.windowScale) ;
- else
- ci.viewPlatformToCoe.setScale(ci.screenScale) ;
-
- if (viewPolicy == View.HMD_VIEW) {
- // In HMD mode view platform coordinates are the same as
- // coexistence coordinates, except for scale.
- ci.updateViewPlatformToCoe = false ;
- return ;
- }
-
- //
- // Otherwise, get the offset of the origin of view platform
- // coordinates relative to the origin of coexistence. This is is
- // specified by two policies: the view platform's view attach policy
- // and the physical environment's coexistence center in pworld policy.
- //
- double eyeOffset ;
- double eyeHeight = body.getNominalEyeHeightFromGround() ;
- int viewAttachPolicy = view.getViewPlatform().getViewAttachPolicy() ;
- int pworldAttachPolicy = env.getCoexistenceCenterInPworldPolicy() ;
-
- if (eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW)
- // The view platform origin is the same as the eye position.
- eyeOffset = ci.getFieldOfViewOffset() ;
- else
- // The view platform origin is independent of the eye position.
- eyeOffset = body.getNominalEyeOffsetFromNominalScreen() ;
-
- if (pworldAttachPolicy == View.NOMINAL_SCREEN) {
- // The default. The physical coexistence origin locates the
- // nominal screen. This is rarely, if ever, set to anything
- // else, and the intended effects of the other settings are
- // not well documented.
- if (viewAttachPolicy == View.NOMINAL_HEAD) {
- // The default. The view platform origin is at the origin
- // of the nominal head in coexistence coordinates, offset
- // from the screen along +Z. If the window eyepoint
- // policy is RELATIVE_TO_FIELD_OF_VIEW, then the eyepoint
- // is the same as the view platform origin.
- v3d.set(0.0, 0.0, eyeOffset) ;
- }
- else if (viewAttachPolicy == View.NOMINAL_SCREEN) {
- // View platform and coexistence are the same except for
- // scale.
- v3d.set(0.0, 0.0, 0.0) ;
- }
- else {
- // The view platform origin is at the ground beneath the
- // head.
- v3d.set(0.0, -eyeHeight, eyeOffset) ;
- }
- }
- else if (pworldAttachPolicy == View.NOMINAL_HEAD) {
- // The physical coexistence origin locates the nominal head.
- if (viewAttachPolicy == View.NOMINAL_HEAD) {
- // The view platform origin is set to the head;
- // coexistence and view platform coordinates differ only
- // in scale.
- v3d.set(0.0, 0.0, 0.0) ;
- }
- else if (viewAttachPolicy == View.NOMINAL_SCREEN) {
- // The view platform is set in front of the head, at the
- // nominal screen location.
- v3d.set(0.0, 0.0, -eyeOffset) ;
- }
- else {
- // The view platform origin is at the ground beneath the
- // head.
- v3d.set(0.0, -eyeHeight, 0.0) ;
- }
- }
- else {
- // The physical coexistence origin locates the nominal feet.
- if (viewAttachPolicy == View.NOMINAL_HEAD) {
- v3d.set(0.0, eyeHeight, 0.0) ;
- }
- else if (viewAttachPolicy == View.NOMINAL_SCREEN) {
- v3d.set(0.0, eyeHeight, -eyeOffset) ;
- }
- else {
- v3d.set(0.0, 0.0, 0.0) ;
- }
- }
-
- ci.viewPlatformToCoe.setTranslation(v3d) ;
- ci.updateViewPlatformToCoe = false ;
- if (verbose) t3dPrint(ci.viewPlatformToCoe, "vpToCoe") ;
- }
-
- /**
- * Gets the current transform from coexistence coordinates to
- * view platform coordinates and copies it into the given transform.PHYSICAL_WORLD
, which
- * alters the scale depending upon the width of the canvas.SCALE_SCREEN_SIZE
,
- * which alters the scale depending upon the width of the screen
- * associated with the canvas.RELATIVE_TO_FIELD_OF_VIEW
- * with a view attach policy of NOMINAL_HEAD
in effect,
- * which sets the view platform Z offset in coexistence coordinates
- * based on the width of the canvas. These are the default policies.
- * The offset also follows the width of the canvas when the
- * NOMINAL_FEET
view attach policy is used.getViewPlatformToCoexistence
.ALLOW_LOCAL_TO_VWORLD_READ
capability set.getViewPlatformToCoexistence
.trackerBaseToImagePlate
transform. Otherwise the window
- * eyepoint policy is used to derive the eyepoint relative to the image
- * plate. When using a head mounted display the eye position is
- * determined solely by calibration constants in Screen3D and
- * PhysicalBody; see the source code for the private method
- * getEyesHMD
for more information.RELATIVE_TO_COEXISTENCE
, then the transforms returned may
- * be different for each canvas if stereo is not in use and they have
- * different monoscopic view policies. They may additionally differ in
- * scale across canvases with the PHYSICAL_WORLD
window
- * resize policy or the SCALE_SCREEN_SIZE
screen scale
- * policy, which alter the scale depending upon the width of the canvas or
- * the width of the screen respectively.RELATIVE_TO_FIELD_OF_VIEW
,
- * RELATIVE_TO_SCREEN
, or RELATIVE_TO_WINDOW
,
- * then the transforms returned may differ across canvases due to
- * the following additional conditions:
- *
- *
- *
- * @param c3d the Canvas3D to use
- * @param e2vpl the Transform3D to receive the left transform
- * @param e2vpr the Transform3D to receive the right transform, or null
- */
- public void getEyeToViewPlatform(Canvas3D c3d,
- Transform3D e2vpl, Transform3D e2vpr) {
-
- CanvasInfo ci = updateCache(c3d, "getEyeToViewPlatform", false) ;
- getEyeToViewPlatform(ci) ;
- e2vpl.set(ci.eyeToViewPlatform) ;
- if (ci.useStereo && e2vpr != null)
- e2vpr.set(ci.rightEyeToViewPlatform) ;
- }
-
- private void getEyeToViewPlatform(CanvasInfo ci) {
- if (ci.updateEyeToViewPlatform) {
- if (verbose) System.err.println("updating EyeToViewPlatform") ;
- if (ci.eyeToViewPlatform == null)
- ci.eyeToViewPlatform = new Transform3D() ;
-
- getEyeToImagePlate(ci) ;
- getImagePlateToViewPlatform(ci) ;
- ci.eyeToViewPlatform.mul(ci.plateToViewPlatform, ci.eyeToPlate) ;
-
- if (ci.useStereo) {
- if (ci.rightEyeToViewPlatform == null)
- ci.rightEyeToViewPlatform = new Transform3D() ;
-
- ci.rightEyeToViewPlatform.mul
- (ci.rightPlateToViewPlatform, ci.rightEyeToPlate) ;
- }
- ci.updateEyeToViewPlatform = false ;
- if (verbose) t3dPrint(ci.eyeToViewPlatform, "eyeToVp") ;
- }
- }
-
- /**
- * Gets the current transforms from view platform coordinates to eye
- * coordinates and copies them into the given Transform3Ds.RELATIVE_TO_WINDOW
or
- * RELATIVE_TO_SCREEN
, in which case the manual eye
- * position in image plate can be set differently for each
- * canvas.RELATIVE_TO_FIELD_OF_VIEW
- * and the view attach policy is NOMINAL_SCREEN
, which
- * decouples the view platform's canvas Z offset from the eyepoint's
- * canvas Z offset.RELATIVE_TO_FIELD_OF_VIEW
- * or RELATIVE_TO_WINDOW
, and a window movement policy
- * of VIRTUAL_WORLD
centers the view platform's X and Y
- * coordinates to the middle of the screen.getEyeToViewPlatform
.
- *
- * @param c3d the Canvas3D to use
- * @param vp2el the Transform3D to receive the left transform
- * @param vp2er the Transform3D to receive the right transform, or null
- * @see #getEyeToViewPlatform
- * getEyeToViewPlatform(Canvas3D, Transform3D, Transform3D)
- */
- public void getViewPlatformToEye(Canvas3D c3d,
- Transform3D vp2el, Transform3D vp2er) {
-
- CanvasInfo ci = updateCache(c3d, "getViewPlatformToEye", false) ;
- getViewPlatformToEye(ci) ;
- vp2el.set(ci.viewPlatformToEye) ;
- if (ci.useStereo && vp2er != null)
- vp2er.set(ci.viewPlatformToRightEye) ;
- }
-
- private void getViewPlatformToEye(CanvasInfo ci) {
- if (ci.updateViewPlatformToEye) {
- if (verbose) System.err.println("updating ViewPlatformToEye") ;
- if (ci.viewPlatformToEye == null)
- ci.viewPlatformToEye = new Transform3D() ;
-
- getEyeToViewPlatform(ci) ;
- ci.viewPlatformToEye.invert(ci.eyeToViewPlatform) ;
-
- if (ci.useStereo) {
- if (ci.viewPlatformToRightEye == null)
- ci.viewPlatformToRightEye = new Transform3D() ;
-
- ci.viewPlatformToRightEye.invert(ci.rightEyeToViewPlatform) ;
- }
- ci.updateViewPlatformToEye = false ;
- }
- }
-
- /**
- * Gets the current transforms from eye coordinates to virtual world
- * coordinates and copies them into the given Transform3Ds.ALLOW_LOCAL_TO_VWORLD_READ
capability set.getEyeToViewPlatform
.
- *
- * @param c3d the Canvas3D to use
- * @param e2vwl the Transform3D to receive the left transform
- * @param e2vwr the Transform3D to receive the right transform, or null
- * @see #getEyeToViewPlatform
- * getEyeToViewPlatform(Canvas3D, Transform3D, Transform3D)
- */
- public void getEyeToVworld(Canvas3D c3d,
- Transform3D e2vwl, Transform3D e2vwr) {
-
- CanvasInfo ci = updateCache(c3d, "getEyeToVworld", true) ;
- getEyeToVworld(ci) ;
- e2vwl.set(ci.eyeToVworld) ;
- if (ci.useStereo && e2vwr != null)
- e2vwr.set(ci.rightEyeToVworld) ;
- }
-
- private void getEyeToVworld(CanvasInfo ci) {
- if (ci.updateEyeToVworld) {
- if (verbose) System.err.println("updating EyeToVworld") ;
- if (ci.eyeToVworld == null)
- ci.eyeToVworld = new Transform3D() ;
-
- getEyeToViewPlatform(ci) ;
- ci.eyeToVworld.mul
- (vpi.viewPlatformToVworld, ci.eyeToViewPlatform) ;
-
- if (ci.useStereo) {
- if (ci.rightEyeToVworld == null)
- ci.rightEyeToVworld = new Transform3D() ;
-
- ci.rightEyeToVworld.mul
- (vpi.viewPlatformToVworld, ci.rightEyeToViewPlatform) ;
- }
- ci.updateEyeToVworld = false ;
- }
- }
-
- /**
- * Gets the transforms from eye coordinates to clipping coordinates
- * and copies them into the given Transform3Ds. These transforms take
- * a viewing volume bounded by the physical canvas edges and the
- * physical front and back clip planes and project it into a range
- * bound to [-1.0 .. +1.0] on each of the X, Y, and Z axes. If a
- * perspective projection has been specified then the physical image
- * plate eye location defines the apex of a viewing frustum;
- * otherwise, the orientation of the image plate determines the
- * direction of a parallel projection.VIRTUAL_EYE
or
- * VIRTUAL_SCREEN
are used, then the View should be attached
- * to a ViewPlatform that is part of a live scene graph and that has its
- * ALLOW_LOCAL_TO_VWORLD_READ
capability set; otherwise, a
- * scale factor of 1.0 will be used for the scale factor from virtual
- * world units to view platform units.
- *
- * @param c3d the Canvas3D to use
- * @param e2ccl the Transform3D to receive left transform
- * @param e2ccr the Transform3D to receive right transform, or null
- */
- public void getProjection(Canvas3D c3d,
- Transform3D e2ccl, Transform3D e2ccr) {
-
- CanvasInfo ci = updateCache(c3d, "getProjection", true) ;
- getProjection(ci) ;
- e2ccl.set(ci.projection) ;
- if (ci.useStereo && e2ccr != null)
- e2ccr.set(ci.rightProjection) ;
- }
-
- private void getProjection(CanvasInfo ci) {
- if (ci.updateProjection) {
- if (verbose) System.err.println("updating Projection") ;
- if (ci.projection == null)
- ci.projection = new Transform3D() ;
-
- getEyeToImagePlate(ci) ;
- getClipDistances(ci) ;
-
- // Note: core Java 3D code insists that the back clip plane
- // relative to the image plate must be the same left back clip
- // distance for both the left and right eye. Not sure why this
- // should be, but the same is done here for compatibility.
- double backClip = getBackClip(ci, ci.eyeInPlate) ;
- computeProjection(ci, ci.eyeInPlate,
- getFrontClip(ci, ci.eyeInPlate),
- backClip, ci.projection) ;
-
- if (ci.useStereo) {
- if (ci.rightProjection == null)
- ci.rightProjection = new Transform3D() ;
-
- computeProjection(ci, ci.rightEyeInPlate,
- getFrontClip(ci, ci.rightEyeInPlate),
- backClip, ci.rightProjection) ;
- }
- ci.updateProjection = false ;
- if (verbose) t3dPrint(ci.projection, "projection") ;
- }
- }
-
- /**
- * Gets the transforms from clipping coordinates to eye coordinates
- * and copies them into the given Transform3Ds. These transforms take
- * the clip space volume bounded by the range [-1.0 .. + 1.0] on each
- * of the X, Y, and Z and project it into eye coordinates.VIRTUAL_EYE
or
- * VIRTUAL_SCREEN
are used, then the View should be attached
- * to a ViewPlatform that is part of a live scene graph and that has its
- * ALLOW_LOCAL_TO_VWORLD_READ
capability set; otherwise, a
- * scale factor of 1.0 will be used for the scale factor from virtual
- * world units to view platform units.
- *
- * @param c3d the Canvas3D to use
- * @param cc2el the Transform3D to receive left transform
- * @param cc2er the Transform3D to receive right transform, or null
- */
- public void getInverseProjection(Canvas3D c3d,
- Transform3D cc2el, Transform3D cc2er) {
-
- CanvasInfo ci = updateCache(c3d, "getInverseProjection", true) ;
- getInverseProjection(ci) ;
- cc2el.set(ci.inverseProjection) ;
- if (ci.useStereo && cc2er != null)
- cc2er.set(ci.inverseRightProjection) ;
- }
-
- private void getInverseProjection(CanvasInfo ci) {
- if (ci.updateInverseProjection) {
- if (verbose) System.err.println("updating InverseProjection") ;
- if (ci.inverseProjection == null)
- ci.inverseProjection = new Transform3D() ;
-
- getProjection(ci) ;
- ci.inverseProjection.invert(ci.projection) ;
-
- if (ci.useStereo) {
- if (ci.inverseRightProjection == null)
- ci.inverseRightProjection = new Transform3D() ;
-
- ci.inverseRightProjection.invert(ci.rightProjection) ;
- }
- ci.updateInverseProjection = false ;
- }
- }
-
- /**
- * Gets the transforms from clipping coordinates to view platform
- * coordinates and copies them into the given Transform3Ds. These
- * transforms take the clip space volume bounded by the range
- * [-1.0 .. +1.0] on each of the X, Y, and Z axes and project into
- * the view platform coordinate system.VIRTUAL_EYE
or
- * VIRTUAL_SCREEN
are used, then the View should be attached
- * to a ViewPlatform that is part of a live scene graph and that has its
- * ALLOW_LOCAL_TO_VWORLD_READ
capability set; otherwise, a
- * scale factor of 1.0 will be used for the scale factor from virtual
- * world units to view platform units.
- *
- * @param c3d the Canvas3D to use
- * @param cc2vpl the Transform3D to receive left transform
- * @param cc2vpr the Transform3D to receive right transform, or null
- */
- public void getInverseViewPlatformProjection(Canvas3D c3d,
- Transform3D cc2vpl,
- Transform3D cc2vpr) {
-
- CanvasInfo ci = updateCache
- (c3d, "getInverseViewPlatformProjection", true) ;
-
- getInverseViewPlatformProjection(ci) ;
- cc2vpl.set(ci.inverseViewPlatformProjection) ;
- if (ci.useStereo & cc2vpr != null)
- cc2vpr.set(ci.inverseViewPlatformRightProjection) ;
- }
-
- private void getInverseViewPlatformProjection(CanvasInfo ci) {
- if (ci.updateInverseViewPlatformProjection) {
- if (verbose) System.err.println("updating InverseVpProjection") ;
- if (ci.inverseViewPlatformProjection == null)
- ci.inverseViewPlatformProjection = new Transform3D() ;
-
- getInverseProjection(ci) ;
- getEyeToViewPlatform(ci) ;
- ci.inverseViewPlatformProjection.mul
- (ci.eyeToViewPlatform, ci.inverseProjection) ;
-
- if (ci.useStereo) {
- if (ci.inverseViewPlatformRightProjection == null)
- ci.inverseViewPlatformRightProjection = new Transform3D() ;
-
- ci.inverseViewPlatformRightProjection.mul
- (ci.rightEyeToViewPlatform, ci.inverseRightProjection) ;
- }
- ci.updateInverseVworldProjection = false ;
- }
- }
-
- /**
- * Gets the transforms from clipping coordinates to virtual world
- * coordinates and copies them into the given Transform3Ds. These
- * transforms take the clip space volume bounded by the range
- * [-1.0 .. +1.0] on each of the X, Y, and Z axes and project into
- * the virtual world.ALLOW_LOCAL_TO_VWORLD_READ
capability set.
- *
- * @param c3d the Canvas3D to use
- * @param cc2vwl the Transform3D to receive left transform
- * @param cc2vwr the Transform3D to receive right transform, or null
- */
- public void getInverseVworldProjection(Canvas3D c3d,
- Transform3D cc2vwl,
- Transform3D cc2vwr) {
-
- CanvasInfo ci = updateCache(c3d, "getInverseVworldProjection", true) ;
- getInverseVworldProjection(ci) ;
- cc2vwl.set(ci.inverseVworldProjection) ;
- if (ci.useStereo & cc2vwr != null)
- cc2vwr.set(ci.inverseVworldRightProjection) ;
- }
-
- private void getInverseVworldProjection(CanvasInfo ci) {
- if (ci.updateInverseVworldProjection) {
- if (verbose) System.err.println("updating InverseVwProjection") ;
- if (ci.inverseVworldProjection == null)
- ci.inverseVworldProjection = new Transform3D() ;
-
- getInverseViewPlatformProjection(ci) ;
- ci.inverseVworldProjection.mul
- (vpi.viewPlatformToVworld, ci.inverseViewPlatformProjection) ;
-
- if (ci.useStereo) {
- if (ci.inverseVworldRightProjection == null)
- ci.inverseVworldRightProjection = new Transform3D() ;
-
- ci.inverseVworldRightProjection.mul
- (vpi.viewPlatformToVworld,
- ci.inverseViewPlatformRightProjection) ;
- }
- ci.updateInverseVworldProjection = false ;
- }
- }
-
- //
- // Compute a projection matrix from the given eye position in image plate,
- // the front and back clip Z positions in image plate, and the current
- // canvas position in image plate.
- //
- private void computeProjection(CanvasInfo ci, Point3d eye,
- double front, double back, Transform3D p) {
-
- // Convert everything to eye coordinates.
- double lx = ci.canvasX - eye.x ; // left (low x)
- double ly = ci.canvasY - eye.y ; // bottom (low y)
- double hx = (ci.canvasX+ci.canvasWidth) - eye.x ; // right (high x)
- double hy = (ci.canvasY+ci.canvasHeight) - eye.y ; // top (high y)
- double nz = front - eye.z ; // front (near z)
- double fz = back - eye.z ; // back (far z)
- double iz = -eye.z ; // plate (image z)
-
- if (projectionPolicy == View.PERSPECTIVE_PROJECTION)
- computePerspectiveProjection(lx, ly, hx, hy, iz, nz, fz, m16d) ;
- else
- computeParallelProjection(lx, ly, hx, hy, nz, fz, m16d) ;
-
- p.set(m16d) ;
- }
-
- //
- // Compute a perspective projection from the given eye-space bounds.
- //
- private void computePerspectiveProjection(double lx, double ly,
- double hx, double hy,
- double iz, double nz,
- double fz, double[] m) {
- //
- // We first derive the X and Y projection components without regard
- // for Z scaling. The Z scaling or perspective depth is handled by
- // matrix elements expressed solely in terms of the near and far clip
- // planes.
- //
- // Since the eye is at the origin, the projector for any point V in
- // eye space is just V. Any point along this ray can be expressed in
- // parametric form as P = tV. To find the projection onto the plane
- // containing the canvas, find t such that P.z = iz; ie, t = iz/V.z.
- // The projection P is thus [V.x*iz/V.z, V.y*iz/V.z, iz].
- //
- // This projection can expressed as the following matrix equation:
- //
- // -iz 0 0 0 V.x
- // 0 -iz 0 0 X V.y
- // 0 0 -iz 0 V.z
- // 0 0 -1 0 1 {matrix 1}
- //
- // where the matrix elements have been negated so that w is positive.
- // This is mostly by convention, although some hardware won't handle
- // clipping in the -w half-space.
- //
- // After the point has been projected to the image plate, the
- // canvas bounds need to be mapped to the [-1..1] of Java 3D's
- // clipping space. The scale factor for X is thus 2/(hx - lx); adding
- // the translation results in (V.x - lx)(2/(hx - lx)) - 1, which after
- // some algebra can be confirmed to the same as the following
- // canonical scale/offset form:
- //
- // V.x*2/(hx - lx) - (hx + lx)/(hx - lx)
- //
- // Similarly for Y:
- //
- // V.y*2/(hy - ly) - (hy + ly)/(hy - ly)
- //
- // If we set idx = 1/(hx - lx) and idy = 1/(hy - ly), then we get:
- //
- // 2*V.x*idx - (hx + lx)idx
- // 2*V.y*idy - (hy + ly)idy
- //
- // These scales and offsets are represented by the following matrix:
- //
- // 2*idx 0 0 -(hx + lx)*idx
- // 0 2*idy 0 -(hy + ly)*idy
- // 0 0 1 0
- // 0 0 0 1 {matrix 2}
- //
- // The result after concatenating the projection transform
- // ({matrix 2} X {matrix 1}):
- //
- // -2*iz*idx 0 (hx + lx)*idx 0
- // 0 -2*iz*idy (hy + ly)*idy 0
- // 0 0 -iz {a} 0 {b}
- // 0 0 -1 0 {matrix 3}
- //
- // The Z scaling is handled by m[10] ("a") and m[11] ("b"), which must
- // map the range [front..back] to [1..-1] in clipping space. If ze is
- // the Z coordinate in eye space, and zc is the Z coordinate in
- // clipping space after division by w, then from {matrix 3}:
- //
- // zc = (a*ze + b)/-ze = -(a + b/ze)
- //
- // We want this to map to +1 when ze is at the near clip plane, and
- // to -1 when ze is at the far clip plane:
- //
- // -(a + b/nz) = +1
- // -(a + b/fz) = -1
- //
- // Solving results in:
- //
- // a = -(nz + fz)/(nz - fz)
- // b = (2*nz*fz)/(nz - fz).
- //
- // NOTE: this produces a perspective transform that has matrix
- // components with a different scale than the matrix computed by the
- // Java 3D core. They do in fact effect the equivalent clipping in 4D
- // homogeneous coordinates and project to the same 3D Euclidean
- // coordinates. m[14] is always -1 in our derivation above. If the
- // matrix components produced by Java 3D core are divided by its value
- // of -m[14], then both matrices are the same.
- //
- double idx = 1.0 / (hx - lx) ;
- double idy = 1.0 / (hy - ly) ;
- double idz = 1.0 / (nz - fz) ;
-
- m[0] = -2.0 * iz * idx ;
- m[5] = -2.0 * iz * idy ;
- m[2] = (hx + lx) * idx ;
- m[6] = (hy + ly) * idy ;
- m[10] = -(nz + fz) * idz ;
- m[11] = 2.0 * fz * nz * idz ;
- m[14] = -1.0 ;
- m[1] = m[3] = m[4] = m[7] = m[8] = m[9] = m[12] = m[13] = m[15] = 0.0 ;
- }
-
- //
- // Compute a parallel projection from the given eye-space bounds.
- //
- private void computeParallelProjection(double lx, double ly,
- double hx, double hy,
- double nz, double fz, double[] m) {
- //
- // A parallel projection in eye space just involves scales and offsets
- // with no w division. We can use {matrix 2} for the X and Y scales
- // and offsets and then use a linear mapping of the front and back
- // clip distances to the [1..-1] Z clip range.
- //
- double idx = 1.0 / (hx - lx) ;
- double idy = 1.0 / (hy - ly) ;
- double idz = 1.0 / (nz - fz) ;
-
- m[0] = 2.0 * idx ;
- m[5] = 2.0 * idy ;
- m[10] = 2.0 * idz ;
- m[3] = -(hx + lx) * idx ;
- m[7] = -(hy + ly) * idy ;
- m[11] = -(nz + fz) * idz ;
- m[15] = 1.0 ;
- m[1] = m[2] = m[4] = m[6] = m[8] = m[9] = m[12] = m[13] = m[14] = 0.0 ;
- }
-
- //
- // Get front clip plane Z coordinate in image plate space.
- //
- private double getFrontClip(CanvasInfo ci, Point3d eye) {
- if (frontClipPolicy == View.PHYSICAL_EYE ||
- frontClipPolicy == View.VIRTUAL_EYE) {
- return eye.z - ci.frontClipDistance ;
- }
- else {
- return - ci.frontClipDistance ;
- }
- }
-
- //
- // Get back clip plane Z coordinate in image plate space.
- //
- private double getBackClip(CanvasInfo ci, Point3d eye) {
- //
- // Note: Clip node status is unavailable here. If a clip node is
- // active in the scene graph, it should override the view's back
- // clip plane.
- //
- if (backClipPolicy == View.PHYSICAL_EYE ||
- backClipPolicy == View.VIRTUAL_EYE) {
- return eye.z - ci.backClipDistance ;
- }
- else {
- return -ci.backClipDistance ;
- }
- }
-
- //
- // Compute clip distance scale.
- //
- private double getClipScale(CanvasInfo ci, int clipPolicy) {
- if (clipPolicy == View.VIRTUAL_EYE ||
- clipPolicy == View.VIRTUAL_SCREEN) {
- getScreenScale(ci) ;
- if (resizePolicy == View.PHYSICAL_WORLD)
- return vpi.vworldToViewPlatformScale * ci.screenScale *
- ci.windowScale ;
- else
- return vpi.vworldToViewPlatformScale * ci.screenScale ;
- }
- else {
- if (resizePolicy == View.PHYSICAL_WORLD)
- return ci.windowScale ; // see below
- else
- return 1.0 ;
- }
- }
-
- /**
- * Gets the front clip distance scaled to physical meters. This is useful
- * for ensuring that objects positioned relative to a physical coordinate
- * system (such as eye, image plate, or coexistence) will be within the
- * viewable Z depth. This distance will be relative to either the eye or
- * the image plate depending upon the front clip policy.setFrontClipDistance
, even when the front clip policy
- * is PHYSICAL_SCREEN
or PHYSICAL_EYE
. If
- * the window resize policy is PHYSICAL_WORLD
, then physical
- * clip distances as specified are in fact scaled by the ratio of the
- * window width to the screen width. The Java 3D view model does this
- * to prevent the physical clip planes from moving with respect to the
- * virtual world when the window is resized.VIRTUAL_EYE
or
- * VIRTUAL_SCREEN
are used, then the View should be attached
- * to a ViewPlatform that is part of a live scene graph and that has its
- * ALLOW_LOCAL_TO_VWORLD_READ
capability set; otherwise, a
- * scale factor of 1.0 will be used for the scale factor from virtual
- * world units to view platform units.
- *
- * @param c3d the Canvas3D to use
- * @return the physical front clip distance
- */
- public double getPhysicalFrontClipDistance(Canvas3D c3d) {
- CanvasInfo ci = updateCache
- (c3d, "getPhysicalFrontClipDistance", true) ;
-
- getClipDistances(ci) ;
- return ci.frontClipDistance ;
- }
-
- /**
- * Gets the back clip distance scaled to physical meters. This is useful
- * for ensuring that objects positioned relative to a physical coordinate
- * system (such as eye, image plate, or coexistence) will be within the
- * viewable Z depth. This distance will be relative to either the eye or
- * the image plate depending upon the back clip policy.setBackClipDistance
, even when the back clip policy
- * is PHYSICAL_SCREEN
or PHYSICAL_EYE
. If
- * the window resize policy is PHYSICAL_WORLD
, then physical
- * clip distances as specified are in fact scaled by the ratio of the
- * window width to the screen width. The Java 3D view model does this
- * to prevent the physical clip planes from moving with respect to the
- * virtual world when the window is resized.VIRTUAL_EYE
or
- * VIRTUAL_SCREEN
are used, then the View should be attached
- * to a ViewPlatform that is part of a live scene graph and that has its
- * ALLOW_LOCAL_TO_VWORLD_READ
capability set; otherwise, a
- * scale factor of 1.0 will be used for the scale factor from virtual
- * world units to view platform units.
- *
- * @param c3d the Canvas3D to use
- * @return the physical back clip distance
- */
- public double getPhysicalBackClipDistance(Canvas3D c3d) {
- CanvasInfo ci = updateCache(c3d, "getPhysicalBackClipDistance", true) ;
- getClipDistances(ci) ;
- return ci.backClipDistance ;
- }
-
- private void getClipDistances(CanvasInfo ci) {
- if (ci.updateClipDistances) {
- if (verbose) System.err.println("updating clip distances") ;
-
- ci.frontClipDistance = view.getFrontClipDistance() *
- getClipScale(ci, frontClipPolicy) ;
-
- ci.backClipDistance = view.getBackClipDistance() *
- getClipScale(ci, backClipPolicy) ;
-
- ci.updateClipDistances = false ;
- if (verbose) {
- System.err.println
- (" front clip distance " + ci.frontClipDistance) ;
- System.err.println
- (" back clip distance " + ci.backClipDistance) ;
- }
- }
- }
-
- private void getScreenScale(CanvasInfo ci) {
- if (ci.updateScreenScale) {
- if (verbose) System.err.println("updating screen scale") ;
-
- if (scalePolicy == View.SCALE_SCREEN_SIZE)
- ci.screenScale = ci.si.screenWidth / 2.0 ;
- else
- ci.screenScale = view.getScreenScale() ;
-
- ci.updateScreenScale = false ;
- if (verbose) System.err.println("screen scale " + ci.screenScale) ;
- }
- }
-
- /**
- * Gets the scale factor from physical meters to view platform units.
- *
- *
- *
- * @param c3d the Canvas3D to use
- * @return the physical to view platform scale
- */
- public double getPhysicalToViewPlatformScale(Canvas3D c3d) {
- CanvasInfo ci = updateCache
- (c3d, "getPhysicalToViewPlatformScale", false) ;
-
- getPhysicalToViewPlatformScale(ci) ;
- return ci.physicalToVpScale ;
- }
-
- private void getPhysicalToViewPlatformScale(CanvasInfo ci) {
- if (ci.updatePhysicalToVpScale) {
- if (verbose) System.err.println("updating PhysicalToVp scale") ;
-
- getScreenScale(ci) ;
- if (resizePolicy == View.PHYSICAL_WORLD)
- ci.physicalToVpScale = 1.0/(ci.screenScale * ci.windowScale) ;
- else
- ci.physicalToVpScale = 1.0/ci.screenScale ;
-
- ci.updatePhysicalToVpScale = false ;
- if (verbose) System.err.println("PhysicalToVp scale " +
- ci.physicalToVpScale) ;
- }
- }
-
- /**
- * Gets the scale factor from physical meters to virtual units.PHYSICAL_WORLD
, which
- * alters the scale depending upon the width of the canvas.SCALE_SCREEN_SIZE
,
- * which alters the scale depending upon the width of the screen
- * associated with the canvas.getPhysicalToViewPlatformScale
.ALLOW_LOCAL_TO_VWORLD_READ
capability set.
- *
- * @param c3d the Canvas3D to use
- * @return the physical to virtual scale
- * @see #getPhysicalToViewPlatformScale
- * getPhysicalToViewPlatformScale(Canvas3D)
- */
- public double getPhysicalToVirtualScale(Canvas3D c3d) {
- CanvasInfo ci = updateCache(c3d, "getPhysicalToVirtualScale", true) ;
- getPhysicalToVirtualScale(ci) ;
- return ci.physicalToVirtualScale ;
- }
-
- private void getPhysicalToVirtualScale(CanvasInfo ci) {
- if (ci.updatePhysicalToVirtualScale) {
- if (verbose)
- System.err.println("updating PhysicalToVirtual scale") ;
-
- getPhysicalToViewPlatformScale(ci) ;
- ci.physicalToVirtualScale =
- ci.physicalToVpScale / vpi.vworldToViewPlatformScale ;
-
- ci.updatePhysicalToVirtualScale = false ;
- if (verbose) System.err.println("PhysicalToVirtual scale " +
- ci.physicalToVirtualScale) ;
- }
- }
-
- /**
- * Gets the width of the specified canvas scaled to physical meters. This
- * is derived from the physical screen width as reported by the Screen3D
- * associated with the canvas. If the screen width is not explicitly set
- * using the setPhysicalScreenWidth
method of Screen3D, then
- * Java 3D will derive the screen width based on a screen resolution of 90
- * pixels/inch.
- *
- * @param c3d the Canvas3D to use
- * @return the width of the canvas scaled to physical meters
- */
- public double getPhysicalWidth(Canvas3D c3d) {
- CanvasInfo ci = updateCache(c3d, "getPhysicalWidth", false) ;
- return ci.canvasWidth ;
- }
-
- /**
- * Gets the height of the specified canvas scaled to physical meters. This
- * is derived from the physical screen height as reported by the Screen3D
- * associated with the canvas. If the screen height is not explicitly set
- * using the setPhysicalScreenHeight
method of Screen3D, then
- * Java 3D will derive the screen height based on a screen resolution of 90
- * pixels/inch.
- *
- * @param c3d the Canvas3D to use
- * @return the height of the canvas scaled to physical meters
- */
- public double getPhysicalHeight(Canvas3D c3d) {
- CanvasInfo ci = updateCache(c3d, "getPhysicalHeight", false) ;
- return ci.canvasHeight ;
- }
-
- /**
- * Gets the location of the specified canvas relative to the image plate
- * origin. This is derived from the physical screen parameters as
- * reported by the Screen3D associated with the canvas. If the screen
- * width and height are not explicitly set in Screen3D, then Java 3D will
- * derive those screen parameters based on a screen resolution of 90
- * pixels/inch.
- *
- * @param c3d the Canvas3D to use
- * @param location the output position, in meters, of the lower-left
- * corner of the canvas relative to the image plate lower-left corner; Z
- * is always 0.0
- */
- public void getPhysicalLocation(Canvas3D c3d, Point3d location) {
- CanvasInfo ci = updateCache(c3d, "getPhysicalLocation", false) ;
- location.set(ci.canvasX, ci.canvasY, 0.0) ;
- }
-
- /**
- * Gets the location of the AWT pixel value and copies it into the
- * specified Point3d.
- *
- * @param c3d the Canvas3D to use
- * @param x the X coordinate of the pixel relative to the upper-left
- * corner of the canvas
- * @param y the Y coordinate of the pixel relative to the upper-left
- * corner of the canvas
- * @param location the output position, in meters, relative to the
- * lower-left corner of the image plate; Z is always 0.0
- */
- public void getPixelLocationInImagePlate(Canvas3D c3d, int x, int y,
- Point3d location) {
-
- CanvasInfo ci = updateCache
- (c3d, "getPixelLocationInImagePlate", false) ;
-
- location.set(ci.canvasX + ((double)x * ci.si.metersPerPixelX),
- ci.canvasY - ((double)y * ci.si.metersPerPixelY) +
- ci.canvasHeight, 0.0) ;
- }
-
- /**
- * Gets a read from the specified sensor and transforms it to virtual
- * world coordinates. The View must be attached to a ViewPlatform which
- * is part of a live scene graph, and the ViewPlatform node must have its
- * ALLOW_LOCAL_TO_VWORLD_READ
capability set.getViewPlatformToCoexistence
.
- *
- * @param sensor the Sensor instance to read
- * @param s2vw the output transform
- * @see #getViewPlatformToCoexistence
- * getViewPlatformToCoexistence(Canvas3D, Transform3D)
- */
- public void getSensorToVworld(Canvas3D c3d,
- Sensor sensor, Transform3D s2vw) {
-
- CanvasInfo ci = updateCache(c3d, "getSensorToVworld", true) ;
- getTrackerBaseToVworld(ci) ;
- sensor.getRead(s2vw) ;
- s2vw.mul(ci.trackerBaseToVworld, s2vw) ;
- }
-
- /**
- * Gets the transform from tracker base coordinates to view platform
- * coordinates and copies it into the specified Transform3D.getViewPlatformToCoexistence
.
- *
- * @param c3d the Canvas3D to use
- * @param tb2vp the output transform
- * @see #getViewPlatformToCoexistence
- * getViewPlatformToCoexistence(Canvas3D, Transform3D)
- */
- public void getTrackerBaseToViewPlatform(Canvas3D c3d, Transform3D tb2vp) {
- CanvasInfo ci = updateCache
- (c3d, "getTrackerBaseToViewPlatform", false) ;
-
- getTrackerBaseToViewPlatform(ci) ;
- tb2vp.set(ci.trackerBaseToViewPlatform) ;
- }
-
- private void getTrackerBaseToViewPlatform(CanvasInfo ci) {
- if (ci.updateTrackerBaseToViewPlatform) {
- if (verbose) System.err.println("updating TrackerBaseToVp") ;
- if (ci.trackerBaseToViewPlatform == null)
- ci.trackerBaseToViewPlatform = new Transform3D() ;
-
- getViewPlatformToCoexistence(ci) ;
- ci.trackerBaseToViewPlatform.mul(coeToTrackerBase,
- ci.viewPlatformToCoe) ;
-
- ci.trackerBaseToViewPlatform.invert() ;
- ci.updateTrackerBaseToViewPlatform = false ;
- if (verbose) t3dPrint(ci.trackerBaseToViewPlatform,
- "TrackerBaseToViewPlatform") ;
- }
- }
-
- /**
- * Gets the transform from tracker base coordinates to virtual world
- * coordinates and copies it into the specified Transform3D. The View
- * must be attached to a ViewPlatform which is part of a live scene graph,
- * and the ViewPlatform node must have its
- * ALLOW_LOCAL_TO_VWORLD_READ
capability set.getViewPlatformToCoexistence
.
- *
- * @param c3d the Canvas3D to use
- * @param tb2vw the output transform
- * @see #getViewPlatformToCoexistence
- * getViewPlatformToCoexistence(Canvas3D, Transform3D)
- */
- public void getTrackerBaseToVworld(Canvas3D c3d, Transform3D tb2vw) {
- CanvasInfo ci = updateCache(c3d, "getTrackerBaseToVworld", true) ;
- getTrackerBaseToVworld(ci) ;
- tb2vw.set(ci.trackerBaseToVworld) ;
- }
-
- private void getTrackerBaseToVworld(CanvasInfo ci) {
- if (ci.updateTrackerBaseToVworld) {
- if (verbose) System.err.println("updating TrackerBaseToVworld") ;
- if (ci.trackerBaseToVworld == null)
- ci.trackerBaseToVworld = new Transform3D() ;
- //
- // We compute trackerBaseToViewPlatform and compose with
- // viewPlatformToVworld instead of computing imagePlateToVworld
- // and composing with trackerBaseToImagePlate. That way it works
- // with HMD and avoids the issue of choosing the left image plate
- // or right image plate transform.
- //
- getTrackerBaseToViewPlatform(ci) ;
- ci.trackerBaseToVworld.mul(vpi.viewPlatformToVworld,
- ci.trackerBaseToViewPlatform) ;
-
- ci.updateTrackerBaseToVworld = false ;
- }
- }
-
- /**
- * Release all static memory references held by ViewInfo, if any. These
- * are the Screen3D and ViewPlatform maps shared by all existing ViewInfo
- * instances if they're not provided by a constructor. Releasing the
- * screen references effectively releases all canvas references in all
- * ViewInfo instances as well.localToVworld
transform. The screen and canvas components
- * as well as the ViewPlatform's localToVworld
are cached
- * separately.attachViewPlatform
method, or if
- * any of the setCanvas3D
, addCanvas3D
,
- * insertCanvas3D
, removeCanvas3D
, or
- * removeAllCanvas3Ds
methods of View are called to change
- * the View's canvas list.localToVworld
- * transform of the view platform. If automatic update has not been
- * enabled for this transform, then this method should be called anytime
- * the view platform has been repositioned in the virtual world and a
- * transform involving virtual world coordinates is desired.ALLOW_LOCAL_TO_VWORLD_READ
capability set.
- */
- public void updateViewPlatform() {
- if (verbose) System.err.println("updateViewPlatform") ;
- vpi.updateViewPlatformToVworld = true ;
- }
-
- //
- // Set cache update bits based on auto update flags.
- // VIEW_AUTO_UPDATE is handled in updateCache().
- //
- private void getAutoUpdate(CanvasInfo ci) {
- if ((autoUpdateFlags & SCREEN_AUTO_UPDATE) != 0)
- ci.si.updateScreen = true ;
-
- if ((autoUpdateFlags & CANVAS_AUTO_UPDATE) != 0)
- ci.updateCanvas = true ;
-
- if ((autoUpdateFlags & PLATFORM_AUTO_UPDATE) != 0)
- vpi.updateViewPlatformToVworld = true ;
-
- if ((autoUpdateFlags & HEAD_AUTO_UPDATE) != 0)
- this.updateHead = true ;
- }
-
- //
- // Update any changed cached data. This takes a Canvas3D instance. The
- // cache mechanism could have used a Canvas3D index into the View instead,
- // but the direct reference is probably more convenient for applications.
- //
- private CanvasInfo updateCache(Canvas3D c3d, String name, boolean vworld) {
- if (verbose) {
- System.err.println("updateCache: " + name + " in " + hashCode()) ;
- System.err.println(" canvas " + c3d.hashCode()) ;
- }
-
- // The View may have had Canvas3D instances added or removed, or may
- // have been attached to a different ViewPlatform, so update the view
- // before anything else.
- if (updateView || (autoUpdateFlags & VIEW_AUTO_UPDATE) != 0)
- getViewInfo() ;
-
- // Now get the CanvasInfo to update.
- CanvasInfo ci = (CanvasInfo)canvasMap.get(c3d) ;
- if (ci == null)
- throw new IllegalArgumentException(
- "Specified Canvas3D is not a component of the View") ;
-
- // Check rest of autoUpdateFlags.
- if (autoUpdate) getAutoUpdate(ci) ;
-
- // Update the screen, canvas, view platform, and head caches.
- if (ci.si.updateScreen)
- ci.si.getScreenInfo() ;
-
- if (ci.updateCanvas)
- ci.getCanvasInfo() ;
-
- if (vworld && vpi.updateViewPlatformToVworld)
- vpi.getViewPlatformToVworld() ;
-
- if (useTracking && updateHead)
- getHeadInfo() ;
-
- // Return the CanvasInfo instance.
- return ci ;
- }
-
- //
- // Get physical view parameters and derived data. This is a fairly
- // heavyweight method -- everything gets marked for update since we don't
- // currently track changes in individual view attributes. Fortunately
- // there shouldn't be a need to call it very often.
- //
- private void getViewInfo() {
- if (verbose) System.err.println(" getViewInfo") ;
-
- // Check if an update of the Canvas3D collection is needed.
- if (this.canvasCount != view.numCanvas3Ds()) {
- this.canvasCount = view.numCanvas3Ds() ;
- getCanvases() ;
- }
- else {
- for (int i = 0 ; i < canvasCount ; i++) {
- if (canvasMap.get(view.getCanvas3D(i)) != canvasInfo[i]) {
- getCanvases() ;
- break ;
- }
- }
- }
-
- // Update the ViewPlatform.
- getViewPlatform() ;
-
- // Update the PhysicalBody and PhysicalEnvironment.
- this.body = view.getPhysicalBody() ;
- this.env = view.getPhysicalEnvironment() ;
-
- // Use the result of the possibly overridden method useHeadTracking()
- // to determine if head tracking is to be used within ViewInfo.
- this.useTracking = useHeadTracking() ;
-
- // Get the head tracker only if really available.
- if (view.getTrackingEnable() && env.getTrackingAvailable()) {
- int headIndex = env.getHeadIndex() ;
- this.headTracker = env.getSensor(headIndex) ;
- }
-
- // Get the new policies and update data derived from them.
- this.viewPolicy = view.getViewPolicy() ;
- this.projectionPolicy = view.getProjectionPolicy() ;
- this.resizePolicy = view.getWindowResizePolicy() ;
- this.movementPolicy = view.getWindowMovementPolicy() ;
- this.eyePolicy = view.getWindowEyepointPolicy() ;
- this.scalePolicy = view.getScreenScalePolicy() ;
- this.backClipPolicy = view.getBackClipPolicy() ;
- this.frontClipPolicy = view.getFrontClipPolicy() ;
-
- if (useTracking || viewPolicy == View.HMD_VIEW) {
- if (this.headToHeadTracker == null)
- this.headToHeadTracker = new Transform3D() ;
- if (this.headTrackerToTrackerBase == null)
- this.headTrackerToTrackerBase = new Transform3D() ;
-
- if (viewPolicy == View.HMD_VIEW) {
- if (this.trackerBaseToHeadTracker == null)
- this.trackerBaseToHeadTracker = new Transform3D() ;
- if (this.coeToHeadTracker == null)
- this.coeToHeadTracker = new Transform3D() ;
- }
- else {
- if (this.headToTrackerBase == null)
- this.headToTrackerBase = new Transform3D() ;
- }
-
- body.getLeftEyePosition(this.leftEyeInHead) ;
- body.getRightEyePosition(this.rightEyeInHead) ;
- body.getHeadToHeadTracker(this.headToHeadTracker) ;
-
- if (verbose) {
- System.err.println(" leftEyeInHead " + leftEyeInHead) ;
- System.err.println(" rightEyeInHead " + rightEyeInHead) ;
- t3dPrint(headToHeadTracker, " headToHeadTracker") ;
- }
- }
-
- if (eyePolicy == View.RELATIVE_TO_WINDOW ||
- eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) {
- body.getLeftEyePosition(this.leftEyeInHead) ;
- body.getRightEyePosition(this.rightEyeInHead) ;
- if (verbose) {
- System.err.println(" leftEyeInHead " + leftEyeInHead) ;
- System.err.println(" rightEyeInHead " + rightEyeInHead) ;
- }
- }
-
- if ((env.getCoexistenceCenterInPworldPolicy() !=
- View.NOMINAL_SCREEN) || (viewPolicy == View.HMD_VIEW))
- this.coeCentering = false ;
- else
- this.coeCentering = view.getCoexistenceCenteringEnable() ;
-
- if (!coeCentering || useTracking) {
- if (this.coeToTrackerBase == null)
- this.coeToTrackerBase = new Transform3D() ;
-
- env.getCoexistenceToTrackerBase(this.coeToTrackerBase) ;
- if (verbose) t3dPrint(coeToTrackerBase, " coeToTrackerBase") ;
- }
-
- if (backClipPolicy == View.VIRTUAL_EYE ||
- backClipPolicy == View.VIRTUAL_SCREEN ||
- frontClipPolicy == View.VIRTUAL_EYE ||
- frontClipPolicy == View.VIRTUAL_SCREEN) {
- this.clipVirtual = true ;
- }
- else {
- this.clipVirtual = false ;
- }
-
- // Propagate view updates to each canvas.
- for (int i = 0 ; i < canvasCount ; i++)
- this.canvasInfo[i].updateViewDependencies() ;
-
- this.updateView = false ;
- if (verbose) {
- System.err.println(" tracking " + useTracking) ;
- System.err.println(" coeCentering " + coeCentering) ;
- System.err.println(" clipVirtual " + clipVirtual) ;
- }
- }
-
- //
- // Each view can have multiple canvases, each with an associated screen.
- // Each canvas is associated with only one view. Each screen can have
- // multiple canvases that are used across multiple views. We rebuild the
- // canvas info instead of trying to figure out what canvases have been
- // added or removed from the view.
- //
- private void getCanvases() {
- if (this.canvasInfo.length < canvasCount) {
- this.canvasInfo = new CanvasInfo[canvasCount] ;
- }
-
- for (int i = 0 ; i < canvasCount ; i++) {
- Canvas3D c3d = view.getCanvas3D(i) ;
- Screen3D s3d = c3d.getScreen3D() ;
-
- // Check if we have a new screen.
- ScreenInfo si = (ScreenInfo)screenMap.get(s3d) ;
- if (si == null) {
- si = new ScreenInfo(s3d, c3d.getGraphicsConfiguration()) ;
- screenMap.put(s3d, si) ;
- }
-
- // Check to see if we've encountered the screen so far in this
- // loop over the view's canvases. If not, clear the screen's list
- // of canvases for this ViewInfo.
- if (newSet.add(si)) si.clear(this) ;
-
- // Check if this is a new canvas.
- CanvasInfo ci = (CanvasInfo)canvasMap.get(c3d) ;
- if (ci == null) ci = new CanvasInfo(c3d, si) ;
-
- // Add this canvas to the screen's list for this ViewInfo.
- si.addCanvasInfo(this, ci) ;
-
- // Add this canvas to the new canvas map and canvas array.
- this.newMap.put(c3d, ci) ;
- this.canvasInfo[i] = ci ;
- }
-
- // Null out old references if canvas count shrinks.
- for (int i = canvasCount ; i < canvasInfo.length ; i++)
- this.canvasInfo[i] = null ;
-
- // Update the CanvasInfo map.
- Map tmp = canvasMap ;
- this.canvasMap = newMap ;
- this.newMap = tmp ;
-
- // Clear the temporary collections.
- this.newMap.clear() ;
- this.newSet.clear() ;
- }
-
- //
- // Force the creation of new CanvasInfo instances. This is called when a
- // screen is removed from the screen map.
- //
- private void clearCanvases() {
- this.canvasCount = 0 ;
- this.canvasMap.clear() ;
- this.updateView = true ;
- }
-
- //
- // Update the view platform. Each view can be attached to only one, but
- // each view platform can have many views attached.
- //
- private void getViewPlatform() {
- ViewPlatform vp = view.getViewPlatform() ;
- if (vp == null)
- throw new IllegalStateException
- ("The View must be attached to a ViewPlatform") ;
-
- ViewPlatformInfo tmpVpi =
- (ViewPlatformInfo)viewPlatformMap.get(vp) ;
-
- if (tmpVpi == null) {
- // We haven't encountered this ViewPlatform before.
- tmpVpi = new ViewPlatformInfo(vp) ;
- viewPlatformMap.put(vp, tmpVpi) ;
- }
-
- if (this.vpi != tmpVpi) {
- // ViewPlatform has changed. Could set an update flag here if it
- // would be used, but updating the view updates everything anyway.
- if (this.vpi != null) {
- // Remove this ViewInfo from the list of Views attached to the
- // old ViewPlatform.
- this.vpi.removeViewInfo(this) ;
- }
- this.vpi = tmpVpi ;
- this.vpi.addViewInfo(this) ;
-
- // updateViewPlatformToVworld is initially set false since the
- // capability to read the vworld transform may not be
- // available. If it is, set it here.
- if (vp.getCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ)) {
- this.vpi.updateViewPlatformToVworld = true ;
- if (verbose) System.err.println(" vworld read allowed") ;
- } else
- if (verbose) System.err.println(" vworld read disallowed") ;
- }
- }
-
- //
- // Force the creation of a new ViewPlatformInfo when a view platform is
- // removed from the view platform map.
- //
- private void clearViewPlatform() {
- this.updateView = true ;
- }
-
- //
- // Update vworld dependencies for this ViewInfo -- called by
- // ViewPlatformInfo.getViewPlatformToVworld().
- //
- private void updateVworldDependencies() {
- for (int i = 0 ; i < canvasCount ; i++)
- this.canvasInfo[i].updateVworldDependencies() ;
- }
-
- /**
- * Returns a reference to a Transform3D containing the current transform
- * from head tracker coordinates to tracker base coordinates. It is only
- * called if useHeadTracking
returns true and a head position
- * update is specified with updateHead
or the
- * HEAD_AUTO_UPDATE
constructor flag.getRead
method directly. The result is a sensor reading
- * that may have been taken at a slightly different time from the one used
- * by the renderer. This method can be overridden to synchronize the two
- * readings through an external mechanism.
- *
- * @return current head tracker to tracker base transform
- * @see #useHeadTracking
- * @see #updateHead
- * @see #HEAD_AUTO_UPDATE
- */
- protected Transform3D getHeadTrackerToTrackerBase() {
- headTracker.getRead(this.headTrackerToTrackerBase) ;
- return this.headTrackerToTrackerBase ;
- }
-
- /**
- * Returns true
if head tracking should be used.true
if the View's
- * getTrackingEnable
method and the PhysicalEnvironment's
- * getTrackingAvailable
method both return true
.
- * These are the same conditions under which the Java 3D renderer uses
- * head tracking. This method can be overridden if there is any need to
- * decouple the head tracking status of ViewInfo from the renderer.
- *
- * @return true
if ViewInfo should use head tracking
- */
- protected boolean useHeadTracking() {
- return view.getTrackingEnable() && env.getTrackingAvailable() ;
- }
-
- //
- // Cache the current tracked head position and derived data.
- //
- private void getHeadInfo() {
- if (verbose) System.err.println(" getHeadInfo") ;
-
- this.headTrackerToTrackerBase = getHeadTrackerToTrackerBase() ;
- if (viewPolicy == View.HMD_VIEW) {
- this.trackerBaseToHeadTracker.invert(headTrackerToTrackerBase) ;
- this.coeToHeadTracker.mul(trackerBaseToHeadTracker,
- coeToTrackerBase) ;
- }
- else {
- this.headToTrackerBase.mul(headTrackerToTrackerBase,
- headToHeadTracker) ;
- }
- for (int i = 0 ; i < canvasCount ; i++)
- this.canvasInfo[i].updateHeadDependencies() ;
-
- this.updateHead = false ;
- //
- // The head position used by the Java 3D renderer isn't accessible
- // in the public API. A head tracker generates continuous data, so
- // getting the same sensor read as the renderer is unlikely.
- //
- // Possible workaround: for fixed screens, get the Java 3D
- // renderer's version of plateToVworld and headToVworld by calling
- // Canvas3D.getImagePlateToVworld() and View.getUserHeadToVworld().
- // Although the vworld components will have frame latency, they can
- // be cancelled out by inverting the former transform and
- // multiplying by the latter, resulting in userHeadToImagePlate,
- // which can then be transformed to tracker base coordinates.
- //
- // For head mounted displays, the head to image plate transforms are
- // just calibration constants, so they're of no use. There are more
- // involved workarounds possible, but one that may work for both fixed
- // screens and HMD is to define a SensorInterposer class that extends
- // Sensor. Take the View's head tracking sensor, use it to construct
- // a SensorInterposer, and then replace the head tracking sensor with
- // the SensorInterposer. SensorInterposer can then override the
- // getRead() methods and thus control what the Java 3D renderer gets.
- // getHeadTrackerToTrackerBase() is a protected method in ViewInfo
- // which can be overridden to call a variant of getRead() so that
- // calls from ViewInfo and from the renderer can be distinguished.
- //
- // Even if getting the same head position as used by the renderer is
- // achieved, tracked eye space interactions with objects in the
- // virtual world still can't be synchronized with rendering. This
- // means that objects in the virtual world cannot be made to appear in
- // a fixed position relative to the tracked head position without a
- // frame lag between them.
- //
- // The reason for this is that the tracked head position used by the
- // Java 3D renderer is updated asynchronously from scene graph
- // updates. This is done to reduce latency between the user's
- // position and the rendered image, which is directly related to the
- // quality of the immersive virtual reality experience. So while an
- // update to the scene graph may have a frame latency before it gets
- // rendered, a change to the user's tracked position is always
- // reflected in the current frame.
- //
- // This problem can't be fixed without eliminating the frame latency
- // in the Java 3D internal state, although there are possible
- // workarounds at the expense of increased user position latency.
- // These involve disabling tracking, reading the head sensor directly,
- // performing whatever eye space interactions are necessary with the
- // virtual world (using the view platform's current localToVworld),
- // and then propagating the head position change to the renderer
- // manually through a behavior post mechanism that delays it by a
- // frame.
- //
- // For example, with head tracking in a fixed screen environment (such
- // as a CAVE), disable Java 3D head tracking and set the View's window
- // eyepoint policy to RELATIVE_TO_COEXISTENCE. Read the sensor to get
- // the head position relative to the tracker base, transform it to
- // coexistence coordinates using the inverse of the value of the
- // coexistenceToTrackerBase transform, and then set the eye positions
- // manually with the View's set{Left,Right}ManualEyeInCoexistence
- // methods. If these method calls are delayed through a behavior post
- // mechanism, then they will be synchronized with the rendering of the
- // scene graph updates.
- //
- // With a head mounted display the sensor can be read directly to get
- // the head position relative to the tracker base. If Java 3D's head
- // tracking is disabled, it uses identity for the current
- // headTrackerToTrackerBase transform. It concatenates its inverse,
- // trackerBaseToHeadTracker, with coexistenceToTrackerBase to get the
- // image plate positions in coexistence; the former transform is
- // inaccessible, but the latter can be set through the
- // PhysicalEnvironment. So the workaround is to maintain a local copy
- // with the real value of coexistenceToTrackerBase, but set the
- // PhysicalEnvironment copy to the product of the real value and the
- // trackerBaseToHeadTracker inverted from the sensor read. Like the
- // CAVE example, this update to the View would have to be delayed in
- // order to synchronize with scene graph updates.
- //
- // Another possibility is to put the Java 3D view model in
- // compatibility mode, where it accepts vpcToEye and eyeToCc
- // (projection) directly. The various view attributes can still be
- // set and accessed, but will be ignored by the Java 3D view model.
- // The ViewInfo methods can be used to compute the view and projection
- // matrices, which can then be delayed to synchronize with the scene
- // graph.
- //
- // Note that these workarounds could be used to make view-dependent
- // scene graph updates consistent, but they still can't do anything
- // about synchronizing the actual physical position of the user with
- // the rendered images. That requires zero latency between position
- // update and scene graph state.
- //
- // Still another possibility: extrapolate the position of the user
- // into the next few frames from a sample of recently recorded
- // positions. Unfortunately, that is also a very hard problem. The
- // Java 3D Sensor API is designed to support prediction but it was
- // never realized successfully in the sample implementation.
- }
-
- //
- // A per-screen cache, shared between ViewInfo instances. In the Java 3D
- // view model a single screen can be associated with multiple canvas
- // and view instances.
- //
- private static class ScreenInfo {
- private Screen3D s3d = null ;
- private GraphicsConfiguration graphicsConfiguration = null ;
- private boolean updateScreen = true ;
-
- private Map viewInfoMap = new HashMap() ;
- private List viewInfoList = new LinkedList() ;
- private Transform3D t3d = new Transform3D() ;
-
- private double screenWidth = 0.0 ;
- private double screenHeight = 0.0 ;
- private boolean updateScreenSize = true ;
-
- private Rectangle screenBounds = null ;
- private double metersPerPixelX = 0.0 ;
- private double metersPerPixelY = 0.0 ;
- private boolean updatePixelSize = true ;
-
- // These transforms are pre-allocated here since they are required by
- // some view policies and we don't know what views this screen will be
- // attached to. Their default identity values are used if not
- // explicitly set. TODO: allocate if needed in getCanvasInfo(), where
- // view information will be available.
- private Transform3D trackerBaseToPlate = new Transform3D() ;
- private Transform3D headTrackerToLeftPlate = new Transform3D() ;
- private Transform3D headTrackerToRightPlate = new Transform3D() ;
- private boolean updateTrackerBaseToPlate = false ;
- private boolean updateHeadTrackerToPlate = false ;
-
- private ScreenInfo(Screen3D s3d, GraphicsConfiguration gc) {
- this.s3d = s3d ;
- this.graphicsConfiguration = gc ;
- if (verbose)
- System.err.println(" ScreenInfo: init " + s3d.hashCode()) ;
- }
-
- private List getCanvasList(ViewInfo vi) {
- List canvasList = (List)viewInfoMap.get(vi) ;
- if (canvasList == null) {
- canvasList = new LinkedList() ;
- viewInfoMap.put(vi, canvasList) ;
- viewInfoList.add(canvasList) ;
- }
- return canvasList ;
- }
-
- private synchronized void clear(ViewInfo vi) {
- getCanvasList(vi).clear() ;
- }
-
- private synchronized void clear() {
- Iterator i = viewInfoMap.keySet().iterator() ;
- while (i.hasNext()) ((ViewInfo)i.next()).clearCanvases() ;
- viewInfoMap.clear() ;
-
- i = viewInfoList.iterator() ;
- while (i.hasNext()) ((List)i.next()).clear() ;
- viewInfoList.clear() ;
- }
-
- private synchronized void addCanvasInfo(ViewInfo vi, CanvasInfo ci) {
- getCanvasList(vi).add(ci) ;
- }
-
- //
- // Get all relevant screen information, find out what changed, and
- // flag derived data. With normal use it's unlikely that any of the
- // Screen3D attributes will change after the first time this method is
- // called. It's possible that the screen resolution changed or some
- // sort of interactive screen calibration is in process.
- //
- private synchronized void getScreenInfo() {
- if (verbose)
- System.err.println(" getScreenInfo " + s3d.hashCode());
-
- // This is used for positioning screens in relation to each other
- // and must be accurate for good results with multi-screen
- // displays. By default the coexistence to tracker base transform
- // is identity so in that case this transform will also set the
- // image plate in coexistence coordinates.
- s3d.getTrackerBaseToImagePlate(t3d) ;
- if (! t3d.equals(trackerBaseToPlate)) {
- this.trackerBaseToPlate.set(t3d) ;
- this.updateTrackerBaseToPlate = true ;
- if (verbose) t3dPrint(trackerBaseToPlate,
- " trackerBaseToPlate") ;
- }
-
- // This transform and the following are used for head mounted
- // displays. They should be based on the *apparent* position of
- // the screens as viewed through the HMD optics.
- s3d.getHeadTrackerToLeftImagePlate(t3d) ;
- if (! t3d.equals(headTrackerToLeftPlate)) {
- this.headTrackerToLeftPlate.set(t3d) ;
- this.updateHeadTrackerToPlate = true ;
- if (verbose) t3dPrint(headTrackerToLeftPlate,
- " headTrackerToLeftPlate") ;
- }
-
- s3d.getHeadTrackerToRightImagePlate(t3d) ;
- if (! t3d.equals(headTrackerToRightPlate)) {
- this.headTrackerToRightPlate.set(t3d) ;
- this.updateHeadTrackerToPlate = true ;
- if (verbose) t3dPrint(headTrackerToRightPlate,
- " headTrackerToRightPlate") ;
- }
-
- // If the screen width and height in meters are not explicitly set
- // through the Screen3D, then the Screen3D will assume a pixel
- // resolution of 90 pixels/inch and compute the dimensions from
- // the screen resolution. These dimensions should be measured
- // accurately for multi-screen displays. For HMD, these
- // dimensions should be the *apparent* width and height as viewed
- // through the HMD optics.
- double w = s3d.getPhysicalScreenWidth() ;
- double h = s3d.getPhysicalScreenHeight();
- if (w != screenWidth || h != screenHeight) {
- this.screenWidth = w ;
- this.screenHeight = h ;
- this.updateScreenSize = true ;
- if (verbose) {
- System.err.println(" screen width " + screenWidth) ;
- System.err.println(" screen height " + screenHeight) ;
- }
- }
-
- GraphicsConfiguration gc1 = graphicsConfiguration;
- // Workaround for Issue 316 - use the default config for screen 0
- // if the graphics config is null
- if (gc1 == null) {
- gc1 = GraphicsEnvironment.getLocalGraphicsEnvironment().
- getDefaultScreenDevice().getDefaultConfiguration();
- }
- this.screenBounds = gc1.getBounds() ;
- double mpx = screenWidth / (double)screenBounds.width ;
- double mpy = screenHeight / (double)screenBounds.height ;
- if ((mpx != metersPerPixelX) || (mpy != metersPerPixelY)) {
- this.metersPerPixelX = mpx ;
- this.metersPerPixelY = mpy ;
- this.updatePixelSize = true ;
- if (verbose) {
- System.err.println(" screen bounds " + screenBounds) ;
- System.err.println(" pixel size X " + metersPerPixelX) ;
- System.err.println(" pixel size Y " + metersPerPixelY) ;
- }
- }
-
- // Propagate screen updates to each canvas in each ViewInfo.
- Iterator vi = viewInfoList.iterator() ;
- while (vi.hasNext()) {
- Iterator ci = ((List)vi.next()).iterator() ;
- while (ci.hasNext())
- ((CanvasInfo)ci.next()).updateScreenDependencies() ;
- }
-
- this.updateTrackerBaseToPlate = false ;
- this.updateHeadTrackerToPlate = false ;
- this.updateScreenSize = false ;
- this.updatePixelSize = false ;
- this.updateScreen = false ;
- }
- }
-
- //
- // A per-ViewPlatform cache, shared between ViewInfo instances. In the
- // Java 3D view model, a view platform may have several views attached to
- // it. The only view platform data cached here is its localToVworld, the
- // inverse of its localToVworld, and the scale from vworld to view
- // platform coordinates. The view platform to coexistence transform is
- // cached by the CanvasInfo instances associated with the ViewInfo.
- //
- private static class ViewPlatformInfo {
- private ViewPlatform vp = null ;
- private List viewInfo = new LinkedList() ;
- private double[] m = new double[16] ;
-
- // These transforms are pre-allocated since we don't know what views
- // will be attached. Their default identity values are used if a
- // vworld dependent computation is requested and no initial update of
- // the view platform was performed; this occurs if the local to vworld
- // read capability isn't set. TODO: rationalize this and allocate
- // only if necessary.
- private Transform3D viewPlatformToVworld = new Transform3D() ;
- private Transform3D vworldToViewPlatform = new Transform3D() ;
- private double vworldToViewPlatformScale = 1.0 ;
-
- // Set these update flags initially false since we might not have the
- // capability to read the vworld transform.
- private boolean updateViewPlatformToVworld = false ;
- private boolean updateVworldScale = false ;
-
- private ViewPlatformInfo(ViewPlatform vp) {
- this.vp = vp ;
- if (verbose) System.err.println
- (" ViewPlatformInfo: init " + vp.hashCode()) ;
- }
-
- private synchronized void addViewInfo(ViewInfo vi) {
- this.viewInfo.add(vi) ;
- }
-
- private synchronized void removeViewInfo(ViewInfo vi) {
- this.viewInfo.remove(vi) ;
- }
-
- private synchronized void clear() {
- Iterator i = viewInfo.iterator() ;
- while (i.hasNext()) ((ViewInfo)i.next()).clearViewPlatform() ;
- viewInfo.clear() ;
- }
-
- //
- // Get the view platform's current localToVworld
and
- // force the update of derived data.
- //
- private synchronized void getViewPlatformToVworld() {
- if (verbose) System.err.println
- (" getViewPlatformToVworld " + vp.hashCode()) ;
-
- vp.getLocalToVworld(this.viewPlatformToVworld) ;
- this.vworldToViewPlatform.invert(viewPlatformToVworld) ;
-
- // Get the scale factor from the virtual world to view platform
- // transform. Note that this is always a congruent transform.
- vworldToViewPlatform.get(m) ;
- double newScale = Math.sqrt(m[0]*m[0] + m[1]*m[1] + m[2]*m[2]) ;
-
- // May need to update clip plane distances if scale changed. We'll
- // check with an epsilon commensurate with single precision float.
- // It would be more efficient to check the square of the distance
- // and then compute the square root only if different, but that
- // makes choosing an epsilon difficult.
- if ((newScale > vworldToViewPlatformScale + 0.0000001) ||
- (newScale < vworldToViewPlatformScale - 0.0000001)) {
- this.vworldToViewPlatformScale = newScale ;
- this.updateVworldScale = true ;
- if (verbose) System.err.println(" vworld scale " +
- vworldToViewPlatformScale) ;
- }
-
- // All virtual world transforms must be updated.
- Iterator i = viewInfo.iterator() ;
- while (i.hasNext())
- ((ViewInfo)i.next()).updateVworldDependencies() ;
-
- this.updateVworldScale = false ;
- this.updateViewPlatformToVworld = false ;
- }
- }
-
- //
- // A per-canvas cache.
- //
- private class CanvasInfo {
- private Canvas3D c3d = null ;
- private ScreenInfo si = null ;
- private boolean updateCanvas = true ;
-
- private double canvasX = 0.0 ;
- private double canvasY = 0.0 ;
- private boolean updatePosition = true ;
-
- private double canvasWidth = 0.0 ;
- private double canvasHeight = 0.0 ;
- private double windowScale = 0.0 ;
- private boolean updateWindowScale = true ;
-
- private double screenScale = 0.0 ;
- private boolean updateScreenScale = true ;
-
- private boolean useStereo = false ;
- private boolean updateStereo = true ;
-
- //
- // coeToPlate is the same for each Canvas3D in a Screen3D unless
- // coexistence centering is enabled and the window movement policy is
- // PHYSICAL_WORLD.
- //
- private Transform3D coeToPlate = null ;
- private Transform3D coeToRightPlate = null ;
- private boolean updateCoeToPlate = true ;
-
- //
- // viewPlatformToCoe is the same for each Canvas3D in a View unless
- // the window resize policy is PHYSICAL_WORLD, in which case the scale
- // factor includes the window scale; or if the screen scale policy is
- // SCALE_SCREEN_SIZE, in which case the scale factor depends upon the
- // width of the screen associated with the canvas; or if the window
- // eyepoint policy is RELATIVE_TO_FIELD_OF_VIEW and the view attach
- // policy is not NOMINAL_SCREEN, which will set the view platform
- // origin in coexistence based on the width of the canvas.
- //
- private Transform3D viewPlatformToCoe = null ;
- private Transform3D coeToViewPlatform = null ;
- private boolean updateViewPlatformToCoe = true ;
- private boolean updateCoeToViewPlatform = true ;
-
- //
- // plateToViewPlatform is composed from viewPlatformToCoe and
- // coeToPlate.
- //
- private Transform3D plateToViewPlatform = null ;
- private Transform3D rightPlateToViewPlatform = null ;
- private boolean updatePlateToViewPlatform = true ;
-
- //
- // trackerBaseToViewPlatform is computed from viewPlatformToCoe and
- // coeToTrackerBase.
- //
- private Transform3D trackerBaseToViewPlatform = null ;
- private boolean updateTrackerBaseToViewPlatform = true ;
-
- //
- // Eye position in image plate is always different for each Canvas3D
- // in a View, unless two or more Canvas3D instances are the same
- // position and size, or two or more Canvas3D instances are using a
- // window eyepoint policy of RELATIVE_TO_SCREEN and have the same
- // settings for the manual eye positions.
- //
- private Point3d eyeInPlate = new Point3d() ;
- private Point3d rightEyeInPlate = new Point3d() ;
- private Transform3D eyeToPlate = null ;
- private Transform3D rightEyeToPlate = null ;
- private boolean updateEyeInPlate = true ;
-
- private Point3d leftManualEyeInPlate = new Point3d() ;
- private Point3d rightManualEyeInPlate = new Point3d() ;
- private boolean updateManualEye = true ;
-
- private int monoscopicPolicy = -1 ;
- private boolean updateMonoPolicy = true ;
-
- //
- // eyeToViewPlatform is computed from eyeToPlate and
- // plateToViewPlatform.
- //
- private Transform3D eyeToViewPlatform = null ;
- private Transform3D rightEyeToViewPlatform = null ;
- private boolean updateEyeToViewPlatform = true ;
-
- private Transform3D viewPlatformToEye = null ;
- private Transform3D viewPlatformToRightEye = null ;
- private boolean updateViewPlatformToEye = true ;
-
- //
- // The projection transform depends upon eye position in image plate.
- //
- private Transform3D projection = null ;
- private Transform3D rightProjection = null ;
- private boolean updateProjection = true ;
-
- private Transform3D inverseProjection = null ;
- private Transform3D inverseRightProjection = null ;
- private boolean updateInverseProjection = true ;
-
- private Transform3D inverseViewPlatformProjection = null ;
- private Transform3D inverseViewPlatformRightProjection = null ;
- private boolean updateInverseViewPlatformProjection = true ;
-
- //
- // The physical clip distances can be affected by the canvas width
- // with the PHYSICAL_WORLD resize policy.
- //
- private double frontClipDistance = 0.0 ;
- private double backClipDistance = 0.0 ;
- private boolean updateClipDistances = true ;
-
- //
- // The physical to view platform scale can be affected by the canvas
- // width with the PHYSICAL_WORLD resize policy.
- //
- private double physicalToVpScale = 0.0 ;
- private double physicalToVirtualScale = 0.0 ;
- private boolean updatePhysicalToVpScale = true ;
- private boolean updatePhysicalToVirtualScale = true ;
-
- //
- // The vworld transforms require reading the ViewPlaform's
- // localToVworld tranform.
- //
- private Transform3D plateToVworld = null ;
- private Transform3D rightPlateToVworld = null ;
- private boolean updatePlateToVworld = true ;
-
- private Transform3D coeToVworld = null ;
- private boolean updateCoeToVworld = true ;
-
- private Transform3D eyeToVworld = null ;
- private Transform3D rightEyeToVworld = null ;
- private boolean updateEyeToVworld = true ;
-
- private Transform3D trackerBaseToVworld = null ;
- private boolean updateTrackerBaseToVworld = true ;
-
- private Transform3D inverseVworldProjection = null ;
- private Transform3D inverseVworldRightProjection = null ;
- private boolean updateInverseVworldProjection = true ;
-
- private CanvasInfo(Canvas3D c3d, ScreenInfo si) {
- this.si = si ;
- this.c3d = c3d ;
- if (verbose) System.err.println(" CanvasInfo: init " +
- c3d.hashCode()) ;
- }
-
- private void getCanvasInfo() {
- if (verbose) System.err.println(" getCanvasInfo " +
- c3d.hashCode()) ;
- boolean newStereo =
- c3d.getStereoEnable() && c3d.getStereoAvailable() ;
-
- if (useStereo != newStereo) {
- this.useStereo = newStereo ;
- this.updateStereo = true ;
- if (verbose) System.err.println(" stereo " + useStereo) ;
- }
-
- this.canvasWidth = c3d.getWidth() * si.metersPerPixelX ;
- this.canvasHeight = c3d.getHeight() * si.metersPerPixelY ;
- double newScale = canvasWidth / si.screenWidth ;
-
- if (windowScale != newScale) {
- this.windowScale = newScale ;
- this.updateWindowScale = true ;
- if (verbose) {
- System.err.println(" width " + canvasWidth) ;
- System.err.println(" height " + canvasHeight) ;
- System.err.println(" scale " + windowScale) ;
- }
- }
-
- // For multiple physical screens, AWT returns the canvas location
- // relative to the origin of the aggregated virtual screen. We
- // need the location relative to the physical screen origin.
- Point awtLocation = c3d.getLocationOnScreen() ;
- int x = awtLocation.x - si.screenBounds.x ;
- int y = awtLocation.y - si.screenBounds.y ;
-
- double newCanvasX = si.metersPerPixelX * x ;
- double newCanvasY = si.metersPerPixelY *
- (si.screenBounds.height - (y + c3d.getHeight())) ;
-
- if (canvasX != newCanvasX || canvasY != newCanvasY) {
- this.canvasX = newCanvasX ;
- this.canvasY = newCanvasY ;
- this.updatePosition = true ;
- if (verbose) {
- System.err.println(" lower left X " + canvasX) ;
- System.err.println(" lower left Y " + canvasY) ;
- }
- }
-
- int newMonoPolicy = c3d.getMonoscopicViewPolicy() ;
- if (monoscopicPolicy != newMonoPolicy) {
- this.monoscopicPolicy = newMonoPolicy ;
- this.updateMonoPolicy = true ;
-
- if (verbose && !useStereo) {
- if (monoscopicPolicy == View.LEFT_EYE_VIEW)
- System.err.println(" left eye view") ;
- else if (monoscopicPolicy == View.RIGHT_EYE_VIEW)
- System.err.println(" right eye view") ;
- else
- System.err.println(" cyclopean view") ;
- }
- }
-
- c3d.getLeftManualEyeInImagePlate(leftEye) ;
- c3d.getRightManualEyeInImagePlate(rightEye) ;
-
- if (!leftEye.equals(leftManualEyeInPlate) ||
- !rightEye.equals(rightManualEyeInPlate)) {
-
- this.leftManualEyeInPlate.set(leftEye) ;
- this.rightManualEyeInPlate.set(rightEye) ;
- this.updateManualEye = true ;
-
- if (verbose && (eyePolicy == View.RELATIVE_TO_WINDOW ||
- eyePolicy == View.RELATIVE_TO_SCREEN)) {
- System.err.println(" left manual eye in plate " +
- leftManualEyeInPlate) ;
- System.err.println(" right manual eye in plate " +
- rightManualEyeInPlate) ;
- }
- }
-
- updateCanvasDependencies() ;
- this.updateStereo = false ;
- this.updateWindowScale = false ;
- this.updatePosition = false ;
- this.updateMonoPolicy = false ;
- this.updateManualEye = false ;
- this.updateCanvas = false ;
- }
-
- private double getFieldOfViewOffset() {
- return 0.5 * canvasWidth / Math.tan(0.5 * view.getFieldOfView()) ;
- }
-
- private void updateScreenDependencies() {
- if (si.updatePixelSize || si.updateScreenSize) {
- if (eyePolicy == View.RELATIVE_TO_WINDOW ||
- eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) {
- // Physical location of the canvas might change without
- // changing the pixel location.
- updateEyeInPlate = true ;
- }
- if (resizePolicy == View.PHYSICAL_WORLD ||
- eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) {
- // Could change the window scale or view platform Z offset.
- updateViewPlatformToCoe = true ;
- }
- if (resizePolicy == View.PHYSICAL_WORLD) {
- // Window scale affects the clip distance and the physical
- // to viewplatform scale.
- updateClipDistances = true ;
- updatePhysicalToVpScale = true ;
- updatePhysicalToVirtualScale = true ;
- }
- // Upper right corner of canvas may have moved from eye.
- updateProjection = true ;
- }
- if (si.updateScreenSize && scalePolicy == View.SCALE_SCREEN_SIZE) {
- // Screen scale affects the clip distances and physical to
- // view platform scale. The screen scale is also a component
- // of viewPlatformToCoe.
- updateScreenScale = true ;
- updateClipDistances = true ;
- updatePhysicalToVpScale = true ;
- updatePhysicalToVirtualScale = true ;
- updateViewPlatformToCoe = true ;
- }
-
- if (viewPolicy == View.HMD_VIEW) {
- if (si.updateHeadTrackerToPlate) {
- // Plate moves with respect to the eye and coexistence.
- updateEyeInPlate = true ;
- updateCoeToPlate = true ;
- }
- }
- else if (coeCentering) {
- if (movementPolicy == View.PHYSICAL_WORLD) {
- // Coexistence is centered on the canvas.
- if (si.updatePixelSize || si.updateScreenSize)
- // Physical location of the canvas might change
- // without changing the pixel location.
- updateCoeToPlate = true ;
- }
- else if (si.updateScreenSize)
- // Coexistence is centered on the screen.
- updateCoeToPlate = true ;
- }
- else if (si.updateTrackerBaseToPlate) {
- // Image plate has possibly changed location. Could be
- // offset by an update to coeToTrackerBase in the
- // PhysicalEnvironment though.
- updateCoeToPlate = true ;
- }
-
- if (updateCoeToPlate &&
- eyePolicy == View.RELATIVE_TO_COEXISTENCE) {
- // Coexistence has moved with respect to plate.
- updateEyeInPlate = true ;
- }
- if (updateViewPlatformToCoe) {
- // Derived transforms. trackerBaseToViewPlatform is composed
- // from viewPlatformToCoe and coexistenceToTrackerBase.
- updateCoeToViewPlatform = true ;
- updateCoeToVworld = true ;
- updateTrackerBaseToViewPlatform = true ;
- updateTrackerBaseToVworld = true ;
- }
- if (updateCoeToPlate || updateViewPlatformToCoe) {
- // The image plate to view platform transform is composed from
- // the coexistence to image plate and view platform to
- // coexistence transforms, so these need updates as well.
- updatePlateToViewPlatform = true ;
- updatePlateToVworld = true ;
- }
- updateEyeDependencies() ;
- }
-
- private void updateEyeDependencies() {
- if (updateEyeInPlate) {
- updateEyeToVworld = true ;
- updateProjection = true ;
- }
- if (updateProjection) {
- updateInverseProjection = true ;
- updateInverseViewPlatformProjection = true ;
- updateInverseVworldProjection = true ;
- }
- if (updateEyeInPlate || updatePlateToViewPlatform) {
- updateViewPlatformToEye = true ;
- updateEyeToViewPlatform = true ;
- }
- }
-
- private void updateCanvasDependencies() {
- if (updateStereo || updateMonoPolicy ||
- (updateManualEye && (eyePolicy == View.RELATIVE_TO_WINDOW ||
- eyePolicy == View.RELATIVE_TO_SCREEN))) {
- updateEyeInPlate = true ;
- }
- if (updateWindowScale || updatePosition) {
- if (coeCentering && movementPolicy == View.PHYSICAL_WORLD) {
- // Coexistence is centered on the canvas.
- updateCoeToPlate = true ;
- if (eyePolicy == View.RELATIVE_TO_COEXISTENCE)
- updateEyeInPlate = true ;
- }
- if (eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW ||
- eyePolicy == View.RELATIVE_TO_WINDOW)
- // Eye depends on canvas position and size.
- updateEyeInPlate = true ;
- }
- if (updateWindowScale) {
- if (resizePolicy == View.PHYSICAL_WORLD ||
- eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) {
- // View platform scale and its origin Z offset changed.
- // trackerBaseToViewPlatform needs viewPlatformToCoe.
- updateViewPlatformToCoe = true ;
- updateCoeToViewPlatform = true ;
- updateCoeToVworld = true ;
- updateTrackerBaseToViewPlatform = true ;
- updateTrackerBaseToVworld = true ;
- }
- if (resizePolicy == View.PHYSICAL_WORLD) {
- // Clip distance and physical to view platform scale are
- // affected by the window size.
- updateClipDistances = true ;
- updateProjection = true ;
- updatePhysicalToVpScale = true ;
- updatePhysicalToVirtualScale = true ;
- }
- }
- if (updateViewPlatformToCoe || updateCoeToPlate) {
- // The image plate to view platform transform is composed from
- // the coexistence to image plate and the view platform to
- // coexistence transforms, so these need updates.
- updatePlateToViewPlatform = true ;
- updatePlateToVworld = true ;
- }
- if (coeCentering && !updateManualEye && !updateWindowScale &&
- (movementPolicy == View.PHYSICAL_WORLD) &&
- (eyePolicy != View.RELATIVE_TO_SCREEN)) {
- // The canvas may have moved, but the eye, coexistence, and
- // view platform moved with it. updateEyeDependencies()
- // isn't called since it would unnecessarily update the
- // projection and eyeToViewPlatform transforms. The tested
- // policies are all true by default.
- return ;
- }
- updateEyeDependencies() ;
- }
-
- //
- // TODO: A brave soul could refine cache updates here. There are a
- // lot of attributes to monitor, so we just update everything for now.
- //
- private void updateViewDependencies() {
- // View policy, physical body eye positions, head to head
- // tracker, window eyepoint policy, field of view, coexistence
- // centering, or coexistence to image plate may have changed.
- updateEyeInPlate = true ;
-
- // If the eye position in image plate has changed, then the
- // projection transform may need to be updated. The projection
- // policy and clip plane distances and policies may have changed.
- // The window resize policy and screen scale may have changed,
- // which affects clip plane distance scaling.
- updateProjection = true ;
- updateClipDistances = true ;
- updatePhysicalToVpScale = true ;
- updatePhysicalToVirtualScale = true ;
-
- // View policy, coexistence to tracker base, coexistence centering
- // enable, or window movement policy may have changed.
- updateCoeToPlate = true ;
-
- // Screen scale, resize policy, view policy, view platform,
- // physical body, physical environment, eyepoint policy, or field
- // of view may have changed.
- updateViewPlatformToCoe = true ;
- updateCoeToViewPlatform = true ;
- updateCoeToVworld = true ;
-
- // The image plate to view platform transform is composed from the
- // coexistence to image plate and view platform to coexistence
- // transforms, so these need updates.
- updatePlateToViewPlatform = true ;
- updatePlateToVworld = true ;
-
- // View platform to coexistence or coexistence to tracker base may
- // have changed.
- updateTrackerBaseToViewPlatform = true ;
- updateTrackerBaseToVworld = true ;
-
- // Screen scale policy or explicit screen scale may have changed.
- updateScreenScale = true ;
-
- // Update transforms derived from eye info.
- updateEyeDependencies() ;
- }
-
- private void updateHeadDependencies() {
- if (viewPolicy == View.HMD_VIEW) {
- // Image plates are fixed relative to the head, so their
- // positions have changed with respect to coexistence, the
- // view platform, and the virtual world. The eyes are fixed
- // with respect to the image plates, so the projection doesn't
- // change with respect to them.
- updateCoeToPlate = true ;
- updatePlateToViewPlatform = true ;
- updatePlateToVworld = true ;
- updateViewPlatformToEye = true ;
- updateEyeToViewPlatform = true ;
- updateEyeToVworld = true ;
- updateInverseViewPlatformProjection = true ;
- updateInverseVworldProjection = true ;
- }
- else {
- // Eye positions have changed with respect to the fixed
- // screens, so the projections must be updated as well as the
- // positions.
- updateEyeInPlate = true ;
- updateEyeDependencies() ;
- }
- }
-
- private void updateVworldDependencies() {
- updatePlateToVworld = true ;
- updateCoeToVworld = true ;
- updateEyeToVworld = true ;
- updateTrackerBaseToVworld = true ;
- updateInverseVworldProjection = true ;
-
- if (vpi.updateVworldScale)
- updatePhysicalToVirtualScale = true ;
-
- if (vpi.updateVworldScale && clipVirtual) {
- // vworldToViewPlatformScale changed and clip plane distances
- // are in virtual units.
- updateProjection = true ;
- updateClipDistances = true ;
- updateInverseProjection = true ;
- updateInverseViewPlatformProjection = true ;
- }
- }
- }
-
- /**
- * Prints out the specified transform in a readable format.
- *
- * @param t3d transform to be printed
- * @param name the name of the transform
- */
- private static void t3dPrint(Transform3D t3d, String name) {
- double[] m = new double[16] ;
- t3d.get(m) ;
- String[] sa = formatMatrixRows(4, 4, m) ;
- System.err.println(name) ;
- for (int i = 0 ; i < 4 ; i++) System.err.println(sa[i]) ;
- }
-
- /**
- * Formats a matrix with fixed fractional digits and integer padding to
- * align the decimal points in columns. Non-negative numbers print up to
- * 7 integer digits, while negative numbers print up to 6 integer digits
- * to account for the negative sign. 6 fractional digits are printed.
- *
- * @param rowCount number of rows in the matrix
- * @param colCount number of columns in the matrix
- * @param m matrix to be formatted
- * @return matrix rows formatted into strings
- */
- private static String[] formatMatrixRows
- (int rowCount, int colCount, double[] m) {
-
- DecimalFormat df = new DecimalFormat("0.000000") ;
- FieldPosition fp = new FieldPosition(DecimalFormat.INTEGER_FIELD) ;
- StringBuffer sb0 = new StringBuffer() ;
- StringBuffer sb1 = new StringBuffer() ;
- String[] rows = new String[rowCount] ;
-
- for (int i = 0 ; i < rowCount ; i++) {
- sb0.setLength(0) ;
- for (int j = 0 ; j < colCount ; j++) {
- sb1.setLength(0) ;
- df.format(m[i*colCount+j], sb1, fp) ;
- int pad = 8 - fp.getEndIndex() ;
- for (int k = 0 ; k < pad ; k++) {
- sb1.insert(0, " ") ;
- }
- sb0.append(sb1) ;
- }
- rows[i] = sb0.toString() ;
- }
- return rows ;
- }
-}
diff --git a/src/classes/share/com/sun/j3d/utils/universe/Viewer.java b/src/classes/share/com/sun/j3d/utils/universe/Viewer.java
deleted file mode 100644
index 7553622..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/Viewer.java
+++ /dev/null
@@ -1,888 +0,0 @@
-/*
- * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any
- * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
- * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
- * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
- * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
- * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
- * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
- * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
- * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
- * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed, licensed or
- * intended for use in the design, construction, operation or
- * maintenance of any nuclear facility.
- *
- */
-
-package com.sun.j3d.utils.universe;
-
-import java.awt.BorderLayout;
-import java.awt.Container;
-import java.awt.Frame;
-import java.awt.GraphicsConfiguration;
-import java.awt.GraphicsDevice;
-import java.awt.GraphicsEnvironment;
-import java.awt.Panel;
-import java.awt.Rectangle;
-import java.awt.Window;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.lang.reflect.Constructor;
-import java.net.URL;
-
-import javax.media.j3d.AudioDevice;
-import javax.media.j3d.Canvas3D;
-import javax.media.j3d.GraphicsConfigTemplate3D;
-import javax.media.j3d.PhysicalBody;
-import javax.media.j3d.PhysicalEnvironment;
-import javax.media.j3d.Screen3D;
-import javax.media.j3d.Transform3D;
-import javax.media.j3d.View;
-import javax.swing.JFrame;
-import javax.swing.JPanel;
-
-import com.sun.j3d.audioengines.AudioEngine3DL2;
-
-/**
- * The Viewer class holds all the information that describes the physical
- * and virtual "presence" in the Java 3D universe. The Viewer object
- * consists of:
- *
- *
- * If the Viewer object is created without any Canvas3D's, or indirectly
- * through a configuration file, it will create the Canvas3D's as needed.
- * The default Viewer creates one Canvas3D. If the Viewer object creates
- * the Canvas3D's, it will also create a JPanel and JFrame for each Canvas3D.
- *
- * Dynamic video resize is a new feature in Java 3D 1.3.1.
- * This feature provides a means for doing swap synchronous resizing
- * of the area that is to be magnified (or passed through) to the
- * output video resolution. This functionality allows an application
- * to draw into a smaller viewport in the framebuffer in order to reduce
- * the time spent doing pixel fill. The reduced size viewport is then
- * magnified up to the video output resolution using the SUN_video_resize
- * extension. This extension is only implemented in XVR-4000 and later
- * hardware with back end video out resizing capability.
- *
- * If video size compensation is enable, the line widths, point sizes and pixel
- * operations will be scaled internally with the resize factor to approximately
- * compensate for video resizing. The location of the pixel ( x, y ) in the
- * resized framebuffer = ( floor( x * factor + 0.5 ), floor( y * factor + 0.5 ) )
- *
- *
- *
- *
- *
- *
-Example Configuration Files
-
-
j3d1x1 A single fullscreen
-desktop configuration.
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-syntax.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-syntax.html
deleted file mode 100644
index b170cc0..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/config-syntax.html
+++ /dev/null
@@ -1,1973 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-The Java 3D Configuration File
-
-
-Syntax Description
-Command Overview
-
- Overview of Relevant View Model Parameters
-Top-Level Command Details
-Built-In Command Details
-Command Index
-Property Index
-
-
-
-
-
-
-
-
-
-Syntax Description
-
-
-
-
-Points
-
-A command that consists entirely of two, three, or four numbers is a 2D point,
-a 3D point, or a 4D point respectively. Any other command that starts with a
-number is a syntax error.
-
-Matrices
-
-A 3D matrix is a command that consists entirely of three 3D points. A 4D
-matrix consists entirely of either three or four 4D points; if there are only
-three 4D points then the fourth is implicitly considered to be (0.0 0.0 0.0
-1.0). The points define the row elements of each type of matrix. Any other
-command that starts with a point is a syntax error.
-
-
-Top-level and built-in commands
-
-All other commands start with an alphanumeric string, the command name
-which identifies it. The remaining elements of the command are its arguments.
-
-Java property substitution syntax
-
-All strings are additionally scanned for text enclosed by a starting ${ and a
-matching }. Such text is looked up as a Java system property name and the
-result is substituted back into the string after eliding the starting and
-ending delimiters. For example, the command:
-
-
-
-
-
-
-
-
-Command Overview
-
-
-
-
-
-
-
-
-Overview of Relevant View Model Parameters
-
-
-
-
-
-The Camera View Model
-
-
-
-
-
-The Java 3D View Model
-
-
-
-When a configuration file is being used the defaults are oriented towards
-making the setup of multiple screen environments as easy as possible. If the
-coexistence centering enable has not been explicitly set, and either the
-CoexistenceToTrackerBase transform for the view has been set or
-TrackerBaseToImagePlate has been set for any screen, then the following
-defaults are used instead:RELATIVE_TO_FIELD_OF_VIEW
.PHYSICAL_WORLD
.PHYSICAL_WORLD
.NOMINAL_HEAD
.
-
-
-The avove defaults are also used if coexistence centering enable has been
-explictly set false.
-RELATIVE_TO_COEXISTENCE
.VIRTUAL_WORLD
.VIRTUAL_WORLD
.NOMINAL_SCREEN
.
-
-
-
-
-
-
-
-Top-Level Command Details
-
-
-
-NewDevice
-Syntax:
-
(NewDevice <instance name> <class name>
-[Alias <alias name>])
-
-
-
-DeviceProperty
-Syntax:
-
(DeviceProperty <instance name> <method name> <arg0>
-... <argn>)
-
-
-
-NewSensor
-Syntax:
-
(NewSensor <instance name> <device name>
-<sensor index> [Alias <alias name>])
-
-
-
-SensorProperty
-Syntax:
-
(SensorProperty <instance name> <property name>
-<property value>)
-
-
-
-Hotspot
-A 3D point in the sensor's local coordinate system. The hotspot specifies the
-"active" point which should interact with the virtual world, such as a point
-used for picking or grabbing an object. Its actual interpretation is up to the
-sensor behavior which uses it. Its value is ignored for head tracking sensors.
-
-
-
-NewScreen
-Syntax:
-
-NewWindow
(NewScreen <instance name> <device index>
-[Alias <alias name>])
-
(NewWindow <instance name> <device index>
-[Alias <alias name>])
-
-
-
-ScreenProperty
-Syntax:
-
-WindowProperty
(ScreenProperty <instance name> <property name>
-<property value>)
-
(WindowProperty <instance name> <property name>
-<property value>)
-
-
-PhysicalScreenWidth
-A number specifying the screen's image area width in meters. When using a
-configuration file the default is 0.365. For head mounted displays this should
-be the apparent width of the display at the focal plane.
-
-
-PhysicalScreenHeight
-A number specifying the screen's image area height in meters. When using a
-configuration file the default is 0.292. For head mounted displays this should
-be the apparent height of the display at the focal plane.
-
-
-WindowSize
-This property's value can be a 2D point to create a window with the specified
-X width and Y height in pixels, or it can be either of the strings FullScreen
-or NoBorderFullScreen to specify a full screen canvas with visible frame
-borders or one with no frame borders. A NoBorderFullScreen canvas uses the
-entire physical display surface for its image. The default value is 512 x 512
-pixels. For multiple screen virtual reality installations or head mounted
-displays NoBorderFullScreen should be used.
-
-
-WindowPosition
-This property's value is a 2D point used to create a window with the specified
-X and Y position. These are offsets of the window's upper left corner from the
-screen's upper left corner.
-
-
-TrackerBaseToImagePlate
-A 4D matrix which transforms points from tracker base coordinates to the image
-plate coordinates for the specified screen. This is only used when a
-ViewPolicy of SCREEN_VIEW
is in effect. The matrix value is
-identity by default.
-
-HeadTrackerToLeftImagePlate
-4D matrices which transform points in the head tracking sensor's local
-coordinate system to a head mounted display's left and right image plates
-respectively. The default value for each is the identity matrix.
-HeadTrackerToRightImagePlateHMD_VIEW
is in effect.
-As with physical screen dimensions, these matrices should indicate the
-apparent location and orientation of the screen images as viewed through
-the head mounted display's optics.
-MonoscopicViewPolicy
-This property may have the following string values: CYCLOPEAN_EYE_VIEW,
-LEFT_EYE_VIEW
, or RIGHT_EYE_VIEW
. The default value is
-CYCLOPEAN_EYE_VIEW
. This default works for non-stereo displays
-and field-sequential stereo displays where the two stereo images are generated
-on the same canvas.HMD_VIEW
with the default
-CYCLOPEAN_EYE_VIEW
policy in effect.LEFT_EYE_VIEW
and RIGHT_EYE_VIEW
monoscopic view
-policies are used for generating stereo pairs on separate monoscopic canvases,
-including the left and right canvases needed by HMD devices that are driven by
-two video channels. When using these policies, stereo should not be
-enabled.
-
-
-NewPhysicalEnvironment
-Syntax:
-
(NewPhysicalEnvironment <instance name>
-[Alias <alias name>])
-
-
-
-PhysicalEnvironmentProperty
-Syntax:
-
(PhysicalEnvironmentProperty <instance name>
-<property name> <property value>)
-
-
-
-InputDevice
-Register an InputDevice implementation instantiated by
-NewDevice. The InputDevice instance name is specified
-by the property value string. If an InputDevice is not registered then
-it will not be scheduled to run.
-
-
-HeadTracker
-Register the Sensor which will be used for head tracking. It must provide 6
-degree of freedom position and orientation reads relative to the tracker base.
-The Sensor instance name is specified by the property value string.
-Its corresponding input device must be registered with the InputDevice
-property.
-
-CoexistenceToTrackerBase
-A 4D matrix which transforms points in coexistence coordinates to tracker base
-coordinates. This defines the position and orientation of coexistence
-coordinates relative to the tracker base. Its default value is the identity
-matrix, so if it is not set then coexistence coordinates will be the same as
-tracker base coordinates. See
-TrackerBaseToImagePlate.
-NOMINAL_SCREEN
. Coexistence coordinates and view platform
-coordinates are then equivalent except for scale. For HMD configurations
-placing the coexistence coordinate system aligned with some nominal
-front-facing user position works well.
-
-
-NewPhysicalBody
-Syntax:
-
(NewPhysicalBody <instance name>
-[Alias <alias name>])
-
-
-
-PhysicalBodyProperty
-Syntax:
-
(PhysicalBodyProperty <instance name> <property name>
-<property value>)
-
-
-
-StereoEyeSeparation
-A number indicating the interpupilary distance in meters. This will set the
-left and right eye positions to offsets of half this distance from the head
-origin along its X axis. The default is 0.066 meters.
-
-LeftEarPosition
-A 3D point which sets the left ear position relative to head coordinates.
-The default is (-0.08, -0.03, 0.09).
-
-
-RightEarPosition
-A 3D point which sets the right ear position relative to head coordinates.
-The default is (0.08, -0.03, 0.09).
-
-
-HeadToHeadTracker
-A 4D matrix which transforms points from head coordinates to the local
-coordinate system of the head tracking sensor. This allows the positions
-of the eyes and ears to be determined from the position and orientation
-of the head tracker. The default is the identity matrix.
-
-
-
-NominalEyeOffsetFromNominalScreen
-A distance in meters used as a calibration parameter for
-ViewAttachPolicy. It does not actually set
-the position of the eyes. The property is ignored if ViewAttachPolicy is
-NOMINAL_SCREEN. The default value is 0.4572 meters.
-
-
-NominalEyeHeightFromGround
-A distance in meters used as a calibration parameter for
-ViewAttachPolicy.
-It does not actually set the position of the eyes. This property is
-ignored if ViewAttachPolicy is not NOMINAL_FEET. The default value is 1.68
-meters.
-
-
-
-NewView
-Syntax:
-
(NewView <instance name>
-[Alias <alias name>])
-
-
-
-ViewProperty
-Syntax:
-(NewView <instance name> <property name>
-<property value>)
-
-
-Screen
-These two properties are equivalent. They include a screen created by
-NewScreen or a window created by
-NewWindow into
-this view. The screen or window name is specified by the property value
-string. Multiple-screen or multiple-window views are created by calling this
-command with each window or screen to be used. If no windows or screens are
-defined for this view then an IllegalArgumentException will be thrown after the
-configuration file has been processed.
-
-
-Window
-PhysicalEnvironment
-Sets the PhysicalEnvironment to be used for this view. The property
-value string specifies the name of a PhysicalEnvironment instance created
-by the NewPhysicalEnvironment command.
-If no PhysicalEnvironment is specified for this view then one with default
-values will be created.
-
-
-PhysicalBody
-Sets the PhysicalBody to be used for this view. The property
-value string specifies the name of a PhysicalBody instance created
-by the NewPhysicalBody command. If
-no PhysicalBody is specified for this view then one with default values
-will be created.
-
-
-ViewPlatform
-The property value string is the name of a view platform defined by a
-previous NewViewPlatform command. This
-specifies that the view should be attached to the given view platform.
-ConfiguredUniverse requires that a view platform be specified for every defined
-view unless only a single view without a view platform is provided; in that
-case a view platform is created by default and the view is attached to that.
-If one or more view platforms are defined then the view attachments must be
-made explicitly.
-
-
-ViewPolicy
-The property value string may be either SCREEN_VIEW
or
-HMD_VIEW
to indicate whether fixed room-mounted screens are being
-used or a head mounted display. The default value is SCREEN_VIEW
.
-
-
-CoexistenceCenteringEnable
-The property value is a boolean string. If true, then the origin of the
-coexistence coordinate system is set to either the middle of the canvas or the
-middle of the screen depending upon whether the WindowMovementPolicy is
-PHYSICAL_WORLD
or VIRTUAL_WORLD
respectively. The X,
-Y, and Z directions of coexistence coordinates will point in the same
-directions as those of the screen's image plate.
-HMD_VIEW
.
-WindowEyepointPolicy
-The string value for this property may be either RELATIVE_TO_SCREEN,
-RELATIVE_TO_COEXISTENCE, RELATIVE_TO_WINDOW
, or
-RELATIVE_TO_FIELD_OF_VIEW
. The normal Java 3D default is
-RELATIVE_TO_FIELD_OF_VIEW
. When using a configuration file the
-default is RELATIVE_TO_COEXISTENCE
if
-CoexistenceCenteringEnable is false,
-otherwise the normal default applies. See the
-setWindowEyepointPolicy View method.
-RELATIVE_TO_SCREEN
and RELATIVE_TO_WINDOW
-policies, the eyepoint is set by using the setLeftManualEyeInImagePlate() and
-setRightManualEyeInImagePlate() methods of Canvas3D. The configuration file
-currently does not provide any mechanism for altering these properties from
-their default values. These default values are (0.142, 0.135, 0.4572) for the
-left eye and (0.208, 0.135, 0.4572) for the right eye.
-WindowMovementPolicy
-
-The string values for these properties may be either
-WindowResizePolicyVIRTUAL_WORLD
-or PHYSICAL_WORLD
. The normal Java 3D default value for both is
-PHYSICAL_WORLD
. When using a configuration file the default
-values are VIRTUAL_WORLD
if
-CoexistenceCenteringEnable is false,
-otherwise the normal defaults apply. See the
-setWindowMovementPolicy and
-setWindowResizePolicy View methods.
-CenterEyeInCoexistence
-A 3D point which specifies the location of the center eye relative to
-coexistence coordinates. See
-CoexistenceToTrackerBase. If stereo
-viewing is enabled, then the left and right eye positions are set to offsets
-from this position using the values specified by the PhysicalBody. This
-property is ignored if head tracking is enabled or if WindowEyepointPolicy is
-not RELATIVE_TO_COEXISTENCE
. The default value is (0.0, 0.0,
-0.4572).
-
-ScreenScalePolicy
-The property value string may be either SCALE_SCREEN_SIZE
-or SCALE_EXPLICIT
and determines the source of the screen
-scale, a factor in the scaling of view platform coordinates to physical
-world coordinates.
-SCALE_SCREEN_SIZE
, then the screen scale is half
-the physical screen width in meters. If WindowResizePolicy is
-PHYSICAL_WORLD
, then this scale is further multiplied by the ratio
-of the window width to the width of the screen (the window scale) to
-produce the scale from view platform coordinates to physical coordinates. This
-allows a virtual world which spans a normalized width of [-1.0 .. 1.0] in view
-platform coordinates to map directly to the physical width of the window or
-screen, depending upon the resize policy.SCALE_EXPLICIT
uses the value of the ScreenScale property as the
-screen scale. It is also further multiplied by the window scale when using the
-PHYSICAL_WORLD
window resize policy to produce the scale from view
-platform coordinates to physical coordinates. Viewing configurations
-incorporating multiple screens should generally set the policy to
-SCALE_EXPLICIT
and choose a screen scale based on the aggregate
-display size, but the default value of SCALE_SCREEN_SIZE
will
-usually work if all the screens are the same size and arranged in a linear
-array.PHYSICAL_WORLD
, the window scale. In the usual
-case the view platform scale is 1.0.
-ScreenScale
-The property value is a number specifying the explicit screen scale
-factor. It is only used if ScreenScalePolicy is SCALE_EXPLICIT
;
-otherwise, the screen scale is half the physical width of the screen in meters.
-The default value for this property is 1.0.
-
-
-BackClipPolicy
-The string values of these properties may be either
-FrontClipPolicyPHYSICAL_EYE,
-PHYSICAL_SCREEN, VIRTUAL_EYE
, or VIRTUAL_SCREEN
. The
-default policies are PHYSICAL_EYE
. See the
-setFrontClipPolicy and
-setBackClipPolicy View methods.
-
-
-FrontClipDistance
-These property values are numbers. The defaults are 0.1 and 10.0
-respectively. See the
-setFrontClipDistance and
-setBackClipDistance View methods.
-BackClipDistancePHYSICAL_EYE
the clip distances
-are measured relative to the eye in physical units, so the clip distances
-specified must be scaled to virtual world units in order to determine the
-distances in the virtual world where they would effectively be applied. As
-described in the discussion of
-ScreenScalePolicy above, the scale from
-virtual units to physical units is the product of the view platform scale
-(usually 1.0), the screen scale, and the window scale (if the window resize
-policy is PHYSICAL_WORLD
), so normally the scale from physical
-units to virtual units would be the inverse of that product.PHYSICAL_EYE
or PHYSICAL_SCREEN
clip policies are
-used with the PHYSICAL_WORLD
window resize policy. The locations
-of the clip planes in physical units are not actually set to the physical
-distances as specified, but are in fact scaled by the window scale.
-This means that when determining where the specified physical clip distances
-are in virtual units the scaling to be used is the inverse of the product of
-the screen scale and view platform scale only.PHYSICAL_WORLD
resize policy. It was implemented in this
-manner to prevent objects in the virtual world from getting clipped
-unexpectedly when the virtual world scaling changed as the result of a window
-resize. The quirk can be avoided by using the VIRTUAL_EYE
or
-VIRTUAL_SCREEN
clip policies or by using the
-VIRTUAL_WORLD
resize policy, but in most cases the effect is
-benign and doesn't lead to unexpected results.
-FieldOfView
-This number is the view's horizontal field of view in radians. The default
-value is PI/4. This value is ignored if WindowEyepointPolicy is not
-RELATIVE_TO_FIELD_OF_VIEW
or if head tracking is enabled. The
-eyepoint for each canvas associated with the view is set such that it is
-centered in X and Y, with the Z value at the appropriate distance to match the
-specified field of view across the width of the canvas.
-
-
-StereoEnable
-Enable or disable stereo viewing for this view according to the boolean value
-specified by the property value string. The default value is false.
-
-TrackingEnable
-Enable or disable head tracking for this view according to the boolean value
-specified by the property value string. The default value is false.
-RELATIVE_TO_COEXISTENCE
with the eyepoint in
-coexistence coordinates computed from reading the head tracking sensor.
-Tracking must be made available by registering an input device and a head
-tracking sensor in PhysicalEnvironment.
-AntialiasingEnable
-Enable or disable scene antialiasing for this view according to the boolean
-value specified by the property value string. The default value is
-false.
-
-
-
-NewViewPlatform
-Syntax:
-
(NewViewPlatform <instance name>
-[Alias <alias name>])
-
-
-
-ViewPlatformProperty
-Syntax:
-
(ViewPlatformProperty <instance name> <property name>
-<property value>)
-
-
-
-NominalViewingTransform
-The property value is a boolean string indicating whether or not
-the view platform should be backed up in Z to allow objects at the origin to be
-viewed. This only has effect if the ViewAttachPolicy is
-NOMINAL_HEAD
. The default value is false. See the
-setNominalViewingTransform
-method of ViewingPlatform.
-
-
-InitialViewingTransform
-Sets the initial transform of the view platform to the 4D matrix
-specified by property value. The default value is identity.
-
-
-AllowPolicyRead
-The property value is a boolean string indicating whether or not reading
-the ViewAttachPolicy is allowed. The default value is false.
-
-
-AllowLocalToVworldRead
-The property value is a boolean string indicating whether or not reading
-the view platform's localToVworld transform is allowed. The default value is
-false.
-
-
-ViewPlatformBehavior
-Attaches a ViewPlatformBehavior instantiated by
-NewViewPlatformBehavior.
-The property value string is the name bound to that instance.
-
-
-ViewAttachPolicy
-The property value string can be one of NOMINAL_SCREEN,
-NOMINAL_HEAD,
or NOMINAL_FEET
. This establishes the point
-in coexistence coordinates where the origin of view platform coordinates is
-attached. The basis vectors of view platform coordinates are always aligned
-with those of coexistence coordinates.
-NOMINAL_SCREEN
, the ViewPlatform origin
-is set directly to the origin of coexistence, so that ViewPlatform coordinates
-and coexistence coordinates are identical except for scale.NOMINAL_HEAD
, the ViewPlatform origin is
-set to the origin of the nominal head, the center eye halfway between the left
-and right eyes. The nominal head origin is on the Z axis of coexistence
-coordinates at some offset from the coexistence origin. If the
-WindowEyepointPolicy is RELATIVE_TO_FIELD_OF_VIEW
, then this is
-the positive Z offset producing the required field of view relative to the
-width of the canvas at the coexistence origin, tracking the Z offset of the
-eyepoint defined by that policy; otherwise, the Z offset is the
-NominalEyeOffsetFromNominalScreen property of PhysicalBody and is decoupled
-from the actual eyepoint offset.NOMINAL_FEET
, the ViewPlatform origin is
-at the ground plane, which is NominalEyeHeightFromGround meters along -Y from
-the origin of the nominal head. NominalEyeHeightFromGround is a property of
-PhysicalBody.NOMINAL_HEAD
. When
-using a configuration file, the default is NOMINAL_HEAD
only if
-every view attached to the view platform has a WindowEyepointPolicy of
-RELATIVE_TO_FIELD_OF_VIEW
; otherwise, the default is
-NOMINAL_SCREEN
. If the view policy is HMD_VIEW
, then
-the ViewAttachPolicy is ignored and is always effectively
-NOMINAL_SCREEN
.
-
-
-NewViewPlatformBehavior
-Syntax:
-
(NewViewPlatformBehavior <instance name> <class name>
-[Alias <alias name>])
-
-
-
-ViewPlatformBehaviorProperty
-Syntax:
-
(ViewPlatformBehaviorProperty <instance name>
-<property name> <property value>)
-
-
-
-SchedulingBounds
-The scheduling bounds for this behavior. Use the
-BoundingSphere built-in command to set this
-property. The default is whatever the application or the concrete subclass
-sets.
-
-
-SchedulingInterval
-A number indicating the scheduling interval for this behavior. See the
-setSchedulingInterval
-method of Behavior.
-
-
-HomeTransform
-See the ViewPlatformBehavior method
-setHomeTransform.
-The property value must be a 4D matrix.
-
-
-
-NewObject
-Syntax:
-
(NewObject <instance name> <class name>
-[Alias <alias name>])
-
-
-
-ObjectProperty
-Syntax:
-
(ObjectProperty <instance name> <method name> <arg0>
-... <argn>)
-
-
-
-JavaProperty
-Syntax:
-
(JavaProperty <propertyName> [Default]
-<propertyValue>)
-
-
-
-Include
-Syntax:
-
(Include <URL string>)
-
-
-
-Alias
-Syntax:
-
(<baseName>Alias <aliasName>
-<originalName>)
-
-
-
-
-
-
-
-
-Built-In Command Details
-
-Subtract (translate) the target origin first if it can be conveniently measured
-or computed relative to the source origin along the source X, Y, and Z basis
-vectors. Then rotate with Euler angles that move the target basis vectors to
-their corresponding source basis vectors.
-
-
-
-
-Translate
-Syntax:
-
(Translate <x offset> <y offset> <z offset>)
-
-
-
-Rotate
-Syntax:
-
(Rotate <x degrees> <y degrees> <z degrees>)
-
-
-
-Concatenate
-Syntax:
-
(Concatenate <m1> <m2>)
-
-
-
-RotateTranslate
-Syntax:
-
(RotateTranslate <m1> <m2>)
-
-
-
-TranslateRotate
-Syntax:
-
(TranslateRotate <m1> <m2>)
-
-
-
-BoundingSphere
-Syntax:
-
(BoundingSphere <center> <radius>)
-
-
-
-Canvas3D
-Syntax:
-
(Canvas3D <screen or window name>)
-
-(ViewProperty <view> Screen <screenName>)
-
-view is the name of a view created with the NewView command. The
-argument to the Canvas3D built-in must be a screenName or
-windowName parameter from one of the above commands.
-(ViewProperty <view> Window <windowName>)
-
-
-
-Sensor
-Syntax:
-
(Sensor <sensor name>)
-
-
-
-Device
-Syntax:
-
(Device <device name>)
-
-
-
-PhysicalBody
-Syntax:
-
(PhysicalBody <body name>)
-
-
-
-PhysicalEnvironment
-Syntax:
-
(PhysicalEnvironment <environment name>)
-
-
-
-View
-Syntax:
-
(View <view name>)
-
-
-
-ViewPlatform
-Syntax:
-
(ViewPlatform <view platform name>)
-
-
-
-ViewPlatformBehavior
-Syntax:
-
(ViewPlatformBehavior <behavior name>)
-
-
-
-Object
-Syntax:
-
(Object <generic object name>)
-
-(NewObject <instance name> <class name>
-[Alias <alias name>])
-
-
-
-
-ConfigContainer
-Syntax:
-
(ConfigContainer)
-
-
-
-
-
-
-
-
-Command Index
-
-
-
-
-
-
-Command
-Type
-
-
-Alias
-top-level
-
-
-BoundingSphere
-built-in
-
-
-Canvas3D
-built-in
-
-
-Concatenate
-built-in
-
-
-ConfigContainer
-built-in
-
-
-Device
-built-in
-
-
-DeviceProperty
-top-level
-
-
-Include
-top-level
-
-
-JavaProperty
-top-level
-
-
-NewDevice
-top-level
-
-
-NewObject
-top-level
-
-
-NewPhysicalBody
-top-level
-
-
-NewPhysicalEnvironment
-top-level
-
-
-NewScreen
-top-level
-
-
-NewSensor
-top-level
-
-
-NewView
-top-level
-
-
-NewViewPlatform
-top-level
-
-
-NewViewPlatformBehavior
-top-level
-
-
-NewWindow
-top-level
-
-
-Object
-built-in
-
-
-ObjectProperty
-top-level
-
-
-PhysicalBody
-built-in
-
-
-PhysicalBodyProperty
-top-level
-
-
-PhysicalEnvironment
-built-in
-
-
-PhysicalEnvironmentProperty
-top-level
-
-
-Rotate
-built-in
-
-
-RotateTranslate
-built-in
-
-
-ScreenProperty
-top-level
-
-
-Sensor
-built-in
-
-
-SensorProperty
-top-level
-
-
-Translate
-built-in
-
-
-TranslateRotate
-built-in
-
-
-View
-built-in
-
-
-ViewPlatform
-built-in
-
-
-ViewPlatformBehavior
-built-in
-
-
-ViewProperty
-top-level
-
-
-ViewPlatformProperty
-top-level
-
-
-ViewPlatformBehaviorProperty
-top-level
-
-
-WindowProperty
-top-level
-
-
-
-
-
-
-
-
-Property Index
-
-
-
-/*
- ************************************************************************
- *
- * Java 3D configuration file for single fullscreen desktop configuration.
- * A view platform behavior is created and configured here as well.
- *
- ************************************************************************
- */
-
-(NewScreen center 0)
-(ScreenProperty center WindowSize NoBorderFullScreen)
-
-(NewView view0)
-(ViewProperty view0 Screen center)
-
-// Create a view platform behavior. Here we use OrbitBehavior, although any
-// concrete subclass of the abstract ViewPlatformBehavior with a parameterless
-// constructor could be used. The logical name to assign to this behavior is
-// specified by the 2nd argument to the NewViewPlatformBehavior command, while
-// the 3rd argument is the name of the ViewPlatformBehavior subclass. It is
-// instantiated through introspection.
-//
-(NewViewPlatformBehavior vpb com.sun.j3d.utils.behaviors.vp.OrbitBehavior)
-
-// Set the scheduling bounds to be a BoundingSphere with its center at
-// (0.0 0.0 0.0) and an infinite radius.
-//
-(ViewPlatformBehaviorProperty vpb SchedulingBounds
- (BoundingSphere (0.0 0.0 0.0) infinite))
-
-// Set properties specific to OrbitBehavior. All arguments following the
-// method name are wrapped and passed to the specified method as an array of
-// Objects. Strings "true" and "false" get turned into Boolean, and number
-// strings get turned into Double. Constructs such as (0.0 1.0 2.0) and
-// ((0.0 1.0 2.0 0.5) (3.0 4.0 5.0 1.0) (6.0 7.0 8.0 0.0)) get converted to
-// Point3d and Matrix4d respectively. Note that last row of a Matrix4d doesn't
-// need to be specified; it is implicitly (0.0 0.0 0.0 1.0).
-//
-// The REVERSE_ALL flags are usually passed to the OrbitBehavior constructor.
-// Since it is being instantiated with its parameterless constructor the
-// reverse flags are set here explicitly.
-//
-(ViewPlatformBehaviorProperty vpb ReverseTranslate true)
-(ViewPlatformBehaviorProperty vpb ReverseRotate true)
-(ViewPlatformBehaviorProperty vpb ReverseZoom true)
-
-// Create a new view platform and set the view platform behavior.
-//
-(NewViewPlatform vp)
-(ViewPlatformProperty vp ViewPlatformBehavior vpb)
-
-// Attach the view to the view platform.
-(ViewProperty view0 ViewPlatform vp)
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-stereo.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-stereo.html
deleted file mode 100644
index 0a91eed..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-stereo.html
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
-
-/*
- ************************************************************************
- *
- * Java 3D configuration file for single fullscreen stereo desktop
- * configuration with no head tracking.
- *
- ************************************************************************
- */
-
-(NewScreen center 0)
-(ScreenProperty center WindowSize NoBorderFullScreen)
-
-// Define the physical body.
-//
-// The head origin is halfway between the eyes, with X extending to the right,
-// Y up, and positive Z extending into the skull.
-//
-(NewPhysicalBody SiteUser)
-
-// Set the interpupilary distance. This sets the LeftEyePosition and
-// RightEyePosition to offsets of half this distance along both directions of
-// the X axis.
-//
-(PhysicalBodyProperty SiteUser StereoEyeSeparation 0.066)
-
-// Create a view using the defined screen and physical body.
-//
-(NewView view0)
-(ViewProperty view0 Screen center)
-(ViewProperty view0 PhysicalBody SiteUser)
-
-// Enable stereo viewing.
-//
-(ViewProperty view0 StereoEnable true)
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-vr.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-vr.html
deleted file mode 100644
index 4c18317..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-vr.html
+++ /dev/null
@@ -1,173 +0,0 @@
-
-
-
-
-
-/*
- ************************************************************************
- *
- * Java 3D configuration file for a single screen stereo desktop display
- * using a head tracker and 6DOF mouse.
- *
- ************************************************************************
- */
-
-// Create a screen object and give it a logical name.
-(NewScreen center 0)
-
-// Set the actual available image area.
-(ScreenProperty center PhysicalScreenWidth 0.398)
-(ScreenProperty center PhysicalScreenHeight 0.282)
-(ScreenProperty center WindowSize NoBorderFullScreen)
-
-// Set the TrackerBaseToImagePlate transform for this screen.
-(ScreenProperty center TrackerBaseToImagePlate
- (RotateTranslate (Rotate 50.000 0.000 0.000)
- (Translate 0.199 0.376 0.000)))
-
-// Configure the head tracker.
-(NewDevice tracker1 com.sun.j3d.input.LogitechTracker)
-(DeviceProperty tracker1 SerialPort "/dev/ttya")
-(DeviceProperty tracker1 ReceiverBaseline 0.1450)
-(DeviceProperty tracker1 ReceiverLeftLeg 0.0875)
-(DeviceProperty tracker1 ReceiverHeight 0.0470)
-(DeviceProperty tracker1 ReceiverTopOffset 0.0000)
-(DeviceProperty tracker1 RealtimeSerialBuffer true)
-
-// Configure the 6DOF wand.
-(NewDevice tracker2 com.sun.j3d.input.LogitechTracker)
-(DeviceProperty tracker2 SerialPort "/dev/ttyb")
-(DeviceProperty tracker2 ReceiverBaseline 0.0700)
-(DeviceProperty tracker2 ReceiverLeftLeg 0.0625)
-(DeviceProperty tracker2 ReceiverHeight 0.0510)
-(DeviceProperty tracker2 ReceiverTopOffset 0.0000)
-(DeviceProperty tracker2 RealtimeSerialBuffer true)
-
-// Make the tracker2 device a slave of the tracker1 device.
-(DeviceProperty tracker1 Slave (Device tracker2))
-
-// Create a 2D mouse valuator.
-(NewDevice mouse com.sun.j3d.input.Mouse2DValuator)
-(DeviceProperty mouse Components (Canvas3D center))
-
-// Create logical names for the available sensors.
-(NewSensor head tracker1 0)
-(NewSensor mouse6d tracker2 0)
-(NewSensor mouse2d mouse 0)
-
-// Set the 6DOF mouse sensor hotspot in the local sensor coordinate system.
-(SensorProperty mouse6d Hotspot (0.00 0.00 -0.10))
-
-// Create a physical environment.
-(NewPhysicalEnvironment SampleSite)
-
-// Register the input devices and head tracker sensor.
-(PhysicalEnvironmentProperty SampleSite InputDevice tracker1)
-(PhysicalEnvironmentProperty SampleSite InputDevice tracker2)
-(PhysicalEnvironmentProperty SampleSite InputDevice mouse)
-(PhysicalEnvironmentProperty SampleSite HeadTracker head)
-
-// Define coexistence coordinates.
-(PhysicalEnvironmentProperty SampleSite CoexistenceToTrackerBase
- (TranslateRotate (Translate 0.0 -0.235 0.0)
- (Rotate -50.0 0.0 0.0)))
-
-// Define the physical body.
-(NewPhysicalBody SiteUser)
-
-// Set the interpupilary distance.
-(PhysicalBodyProperty SiteUser StereoEyeSeparation 0.066)
-
-// Define the head location relative to the tracker mounted on the head.
-(PhysicalBodyProperty SiteUser HeadToHeadTracker ((1.0 0.0 0.0 0.000)
- (0.0 1.0 0.0 0.020)
- (0.0 0.0 1.0 0.018)))
-
-// Create a view platform behavior.
-//
-(NewViewPlatformBehavior vpb com.sun.j3d.utils.behaviors.vp.WandViewBehavior)
-
-(ViewPlatformBehaviorProperty vpb Sensor6D (Sensor mouse6d))
-(ViewPlatformBehaviorProperty vpb Sensor2D (Sensor mouse2d))
-
-(ViewPlatformBehaviorProperty vpb ButtonAction6D 1 GrabView)
-(ViewPlatformBehaviorProperty vpb ButtonAction6D 2 TranslateForward)
-(ViewPlatformBehaviorProperty vpb ButtonAction6D 0 TranslateBackward)
-
-(ViewPlatformBehaviorProperty vpb RotationCoords ViewPlatform)
-(ViewPlatformBehaviorProperty vpb ButtonAction2D 1 Translation)
-(ViewPlatformBehaviorProperty vpb ButtonAction2D 2 Scale)
-
-(ViewPlatformBehaviorProperty vpb EchoType Beam)
-(ViewPlatformBehaviorProperty vpb EchoSize 0.004)
-
-(ViewPlatformBehaviorProperty vpb EchoColor 1.0 0.7 0.0)
-(ViewPlatformBehaviorProperty vpb EchoTransparency 0.4)
-
-// Create a new view platform and set the view platform behavior.
-//
-(NewViewPlatform vp)
-(ViewPlatformProperty vp ViewPlatformBehavior vpb)
-
-// Create a view.
-//
-(NewView view0)
-(ViewProperty view0 Screen center)
-(ViewProperty view0 PhysicalEnvironment SampleSite)
-(ViewProperty view0 PhysicalBody SiteUser)
-(ViewProperty view0 ViewPlatform vp)
-
-// Enable stereo viewing and head tracking.
-(ViewProperty view0 StereoEnable true)
-(ViewProperty view0 TrackingEnable True)
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-window.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-window.html
deleted file mode 100644
index 3ff401f..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1-window.html
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
-
-
-/*
- ************************************************************************
- *
- * Java 3D configuration file for a conventional single screen, windowed
- * desktop configuration.
- *
- ************************************************************************
- */
-
-(NewWindow window1 0)
-(WindowProperty window1 WindowSize (700.0 700.0))
-
-(NewView view1)
-(ViewProperty view1 Window window1)
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1.html
deleted file mode 100644
index 1f7f17b..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x1.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-/*
- ************************************************************************
- *
- * Java 3D configuration file for a single fullscreen desktop configuration.
- *
- ************************************************************************
- */
-
-(NewWindow big 0)
-(WindowProperty big WindowSize NoBorderFullScreen)
-
-(NewView view0)
-(ViewProperty view0 Window big)
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-flat.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-flat.html
deleted file mode 100644
index 9391af2..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-flat.html
+++ /dev/null
@@ -1,152 +0,0 @@
-
-
-
-
-
-/*
- ************************************************************************
- *
- * Java 3D configuration file for dual-screen (flat) desktop configuration
- * with no head tracking.
- *
- ************************************************************************
- */
-
-// Create new screen objects and associate them with logical names and numbers.
-// These numbers are used as indices to retrieve the AWT GraphicsDevice from
-// the array that GraphicsEnvironment.getScreenDevices() returns.
-//
-// NOTE: The GraphicsDevice order in the array is specific to the local
-// site and display system.
-//
-(NewScreen left 0)
-(NewScreen right 1)
-
-// Set the screen dimensions.
-//
-(ScreenProperty left PhysicalScreenWidth 0.360)
-(ScreenProperty left PhysicalScreenHeight 0.288)
-
-(ScreenProperty right PhysicalScreenWidth 0.360)
-(ScreenProperty right PhysicalScreenHeight 0.288)
-
-// Specify full screen windows.
-//
-(ScreenProperty left WindowSize NoBorderFullScreen)
-(ScreenProperty right WindowSize NoBorderFullScreen)
-
-// Set the TrackerBaseToImagePlate transforms for these screens. This
-// transforms points in tracker base coordinates to each screen's image plate
-// coordinates, where the origin of the image plate is defined to be the lower
-// left corner of the screen with X increasing to the right, Y increasing to
-// the top, and Z increasing away from the screen.
-//
-// Without head or sensor tracking the tracker base is still needed as a fixed
-// frame of reference for describing the orientation and position of each
-// screen to the others. The coexistence to tracker base transform is set to
-// identity by default, so the tracker base origin and orientation will also
-// set the origin and orientation of coexistence coordinates in the physical
-// world.
-//
-// The tracker base and center of coexistence is set here to the middle of the
-// edge shared by the two screens.
-//
-(ScreenProperty left TrackerBaseToImagePlate
- (Translate 0.360 0.144 0.0))
-(ScreenProperty right TrackerBaseToImagePlate
- (Translate 0.000 0.144 0.0))
-
-// Sometimes it is desirable to include the bevels in between the monitors in
-// the TrackerBaseToImagePlate transforms, so that the abutting bevels obscure
-// the view of the virtual world instead of stretching it out between the
-// monitors. For a bevel width of 4.5 cm on each monitor, the above commands
-// would become the following:
-//
-// (ScreenProperty left TrackerBaseToImagePlate
-// (Translate 0.405 0.144 0.0))
-// (ScreenProperty right TrackerBaseToImagePlate
-// (Translate -0.045 0.144 0.0))
-//
-// Conversely, a similar technique may be used to include overlap between the
-// screens. This is useful for projection systems which use edge blending
-// to provide seamless integration between screens.
-
-
-// Create a view using the defined screens.
-//
-(NewView view0)
-(ViewProperty view0 Screen left)
-(ViewProperty view0 Screen right)
-
-// Set the eyepoint relative to coexistence coordinates. Here it is set 45cm
-// toward the user along Z, extending out from the midpoint of the edge shared
-// by the two screens. This will create the appropriate skewed projection
-// frustums for each image plate.
-//
-// If a planar display surface is all that is required, the same effect could
-// be achieved in a virtual screen enviroment such as Xinerama by simply
-// creating a canvas that spans both screens. In some display environments the
-// use of a canvas that spans multiple physical screens may cause significant
-// performance degradation, however.
-//
-// See j3d1x2-rot30 for an example of a non-planar configuration that cannot be
-// achieved through a single canvas spanning both screens.
-//
-(ViewProperty view0 CenterEyeInCoexistence (0.0 0.0 0.45))
-
-(NewViewPlatform vp)
-(ViewPlatformProperty vp AllowPolicyRead true)
-(ViewPlatformProperty vp AllowLocalToVworldRead true)
-
-(ViewProperty view0 ViewPlatform vp)
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-rot30.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-rot30.html
deleted file mode 100644
index ca5fdd6..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x2-rot30.html
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
-
-
-/*
- ************************************************************************
- *
- * Java 3D configuration file for a dual-screen desktop configuration
- * with each screen rotated toward the other by 30 degrees about Y from
- * planar. The inside angle between them is 120 degrees.
- *
- ************************************************************************
- */
-
-// Create new screen objects and associate them with logical names and numbers.
-// These numbers are used as indices to retrieve the AWT GraphicsDevice from
-// the array that GraphicsEnvironment.getScreenDevices() returns.
-//
-// NOTE: The GraphicsDevice order in the array is specific to the local
-// site and display system.
-//
-(NewScreen left 0)
-(NewScreen right 1)
-
-// Set the available image areas for full screens.
-//
-(ScreenProperty left PhysicalScreenWidth 0.360)
-(ScreenProperty left PhysicalScreenHeight 0.288)
-
-(ScreenProperty right PhysicalScreenWidth 0.360)
-(ScreenProperty right PhysicalScreenHeight 0.288)
-
-// Specify full screen windows.
-//
-(ScreenProperty left WindowSize NoBorderFullScreen)
-(ScreenProperty right WindowSize NoBorderFullScreen)
-
-// Set the TrackerBaseToImagePlate transforms for these screens.
-//
-// The tracker base is set here to the middle of the edge shared by the two
-// screens. Each screen is rotated 30 degrees toward the other about the
-// tracker base +Y axis, so that the tracker base +Z is centered between the
-// two screens.
-//
-(ScreenProperty left TrackerBaseToImagePlate
- (RotateTranslate (Rotate 0.000 -30.000 0.0)
- (Translate 0.360 0.144 0.0)))
-
-(ScreenProperty right TrackerBaseToImagePlate
- (RotateTranslate (Rotate 0.000 30.000 0.0)
- (Translate 0.000 0.144 0.0)))
-
-
-// Create a view using the defined screens.
-//
-(NewView view0)
-(ViewProperty view0 Screen left)
-(ViewProperty view0 Screen right)
-(ViewProperty view0 CenterEyeInCoexistence (0.0 0.0 0.45))
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave-vr.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave-vr.html
deleted file mode 100644
index fcc58b4..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave-vr.html
+++ /dev/null
@@ -1,243 +0,0 @@
-
-
-
-
-
-/*
- ************************************************************************
- *
- * Java 3D configuration file for a cave environment with head tracking and
- * stereo viewing. This cave consists of 3 projectors with 3 screens to the
- * left, front, and right of the user, all at 90 degrees to each other.
- *
- * The projectors in Sun's VirtualPortal sample site are actually turned
- * on their sides to get more height. Screen 0 is rotated 90 degrees
- * counter-clockwise, while screens 1 and 2 are rotated 90 degrees
- * clockwise.
- *
- ************************************************************************
- */
-
-// Configure the head tracker.
-//
-(NewDevice tracker1 com.sun.j3d.input.LogitechTracker)
-(DeviceProperty tracker1 SerialPort "/dev/ttya") // Unix paths need quoting.
-(DeviceProperty tracker1 TransmitterBaseline 0.4600)
-(DeviceProperty tracker1 TransmitterLeftLeg 0.4400)
-(DeviceProperty tracker1 TransmitterCalibrationDistance 0.4120)
-
-// Configure an InputDevice to use for a 6 degree of freedom wand.
-//
-(NewDevice tracker2 com.sun.j3d.input.LogitechTracker)
-(DeviceProperty tracker2 SerialPort "/dev/ttyb")
-(DeviceProperty tracker2 ReceiverBaseline 0.0700)
-(DeviceProperty tracker2 ReceiverLeftLeg 0.0625)
-(DeviceProperty tracker2 ReceiverHeight 0.0510)
-(DeviceProperty tracker2 ReceiverTopOffset 0.0000)
-
-// Make the tracker2 device a slave of the tracker1 device.
-(DeviceProperty tracker1 Slave (Device tracker2))
-
-// Create logical names for the head tracker and wand sensors. The last
-// argument is the sensor's index in the input device.
-//
-(NewSensor head tracker1 0)
-(NewSensor sensor6d tracker2 0)
-
-// Create new screen objects and associate them with logical names and numbers.
-// These numbers are used as indices to retrieve the AWT GraphicsDevice from
-// the array that GraphicsEnvironment.getScreenDevices() returns.
-//
-// NOTE: The GraphicsDevice order in the array is specific to the local
-// site and display system.
-//
-(NewScreen left 0)
-(NewScreen center 1)
-(NewScreen right 2)
-
-
-// Set the available image areas as well as their positition and orientation
-// relative to the tracker base. From the orientation of a user standing
-// within this VirtualPortal site and facing the center screen, the tracker
-// base is along the vertical midline of the screen, 0.248 meters down from
-// the top edge, and 1.340 meters in front of it. The tracker base is
-// oriented so that its +X axis points to the left, its +Y axis points toward
-// the screen, and its +Z axis points toward the floor.
-//
-(ScreenProperty left PhysicalScreenWidth 2.480)
-(ScreenProperty left PhysicalScreenHeight 1.705)
-(ScreenProperty left WindowSize NoBorderFullScreen)
-(ScreenProperty left TrackerBaseToImagePlate
- (( 0.0 0.0 -1.0 2.230)
- ( 0.0 -1.0 0.0 1.340)
- (-1.0 0.0 0.0 0.885)))
-
-(ScreenProperty center PhysicalScreenWidth 2.485)
-(ScreenProperty center PhysicalScreenHeight 1.745)
-(ScreenProperty center WindowSize NoBorderFullScreen)
-(ScreenProperty center TrackerBaseToImagePlate
- (( 0.0 0.0 1.0 0.248)
- (-1.0 0.0 0.0 0.885)
- ( 0.0 -1.0 0.0 1.340)))
-
-(ScreenProperty right PhysicalScreenWidth 2.480)
-(ScreenProperty right PhysicalScreenHeight 1.775)
-(ScreenProperty right WindowSize NoBorderFullScreen)
-(ScreenProperty right TrackerBaseToImagePlate
- (( 0.0 0.0 1.0 0.2488)
- ( 0.0 -1.0 0.0 1.340)
- ( 1.0 0.0 0.0 0.860)))
-
-// Create a physical environment. This contains the available input devices,
-// audio devices, and sensors, and defines the coexistence coordinate system
-// for mapping between the virtual and physical worlds.
-//
-(NewPhysicalEnvironment VirtualPortal)
-
-// Register the input device defined in this file and the sensor which will
-// drive head tracking.
-//
-(PhysicalEnvironmentProperty VirtualPortal InputDevice tracker1)
-(PhysicalEnvironmentProperty VirtualPortal InputDevice tracker2)
-(PhysicalEnvironmentProperty VirtualPortal HeadTracker head)
-
-// Set the location of the center of coexistence relative to the tracker base.
-// Here it set to the center of the center screen. The default view attach
-// policy of NOMINAL_SCREEN used by ConfiguredUniverse will place the origin of
-// the view platform in coexistence coordinates at the center of coexistence.
-//
-(PhysicalEnvironmentProperty VirtualPortal
- CoexistenceToTrackerBase
- ((-1.0 0.0 0.0 0.000)
- ( 0.0 0.0 -1.0 1.340)
- ( 0.0 -1.0 0.0 0.994)))
-
-// Define the physical body. The head origin is halfway between the eyes, with
-// X extending to the right, Y up, and positive Z extending into the skull.
-//
-(NewPhysicalBody LabRat)
-(PhysicalBodyProperty LabRat StereoEyeSeparation .07)
-
-// Define the position and orientation of the head relative to the tracker
-// mounted on the head.
-//
-(PhysicalBodyProperty LabRat HeadToHeadTracker
- ((-1.0 0.0 0.0 0.00)
- ( 0.0 0.0 -1.0 0.05)
- ( 0.0 -1.0 0.0 0.11)))
-
-// Create a view platform behavior for the 6DOF sensor.
-//
-(NewViewPlatformBehavior vpb com.sun.j3d.utils.behaviors.vp.WandViewBehavior)
-
-(ViewPlatformBehaviorProperty vpb Sensor6D sensor6d)
-(ViewPlatformBehaviorProperty vpb ButtonAction6D 2 GrabView)
-(ViewPlatformBehaviorProperty vpb ButtonAction6D 1 TranslateForward)
-(ViewPlatformBehaviorProperty vpb ButtonAction6D 0 TranslateBackward)
-
-// Default normal translation speed is 0.1 physical meters per second.
-(ViewPlatformBehaviorProperty vpb TranslationSpeed
- 1.0 PhysicalMeters PerSecond)
-
-// Default rotation coordinates are Sensor.
-(ViewPlatformBehaviorProperty vpb RotationCoords Head)
-
-// Nominal sensor transform for modified joystick RedBarron
-(SensorProperty sensor6d Hotspot (0.00 0.6 0.00))
-(ViewPlatformBehaviorProperty vpb NominalSensorRotation
- ((-1.0 0.0 0.0)
- ( 0.0 0.0 -1.0)
- ( 0.0 -1.0 0.0)))
-
-// Default 6DOF sensor echo is Gnomon
-(ViewPlatformBehaviorProperty vpb EchoSize 0.015)
-(ViewPlatformBehaviorProperty vpb EchoType Beam)
-
-// Default 6DOF sensor echo color is white
-(ViewPlatformBehaviorProperty vpb EchoColor 1.0 0.7 0.0)
-
-// Default 6DOF sensor transparency is 0.0 (opaque)
-(ViewPlatformBehaviorProperty vpb EchoTransparency 0.4)
-
-// Create a new view platform and set the view platform behavior.
-//
-(NewViewPlatform vp)
-(ViewPlatformProperty vp ViewPlatformBehavior vpb)
-
-// Now define the view.
-//
-(NewView view0)
-(ViewProperty view0 Screen left)
-(ViewProperty view0 Screen center)
-(ViewProperty view0 Screen right)
-(ViewProperty view0 PhysicalBody LabRat)
-(ViewProperty view0 PhysicalEnvironment VirtualPortal)
-(ViewProperty view0 ViewPlatform vp)
-
-// Set the screen scale. This is scale factor from virtual to physical
-// coordinates.
-//
-(ViewProperty view0 ScreenScalePolicy SCALE_SCREEN_SIZE)
-
-// Alternative for explict scaling.
-//
-//(ViewProperty view0 ScreenScalePolicy SCALE_EXPLICIT)
-//(ViewProperty view0 ScreenScale 5.00)
-
-// Enable stereo viewing. Enable head tracking to get the position of the eyes
-// with respect to coexistence. Boolean values may be specified as either
-// true, True, false, or False.
-//
-(ViewProperty view0 StereoEnable true)
-(ViewProperty view0 TrackingEnable True)
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave.html
deleted file mode 100644
index 9b0298b..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-cave.html
+++ /dev/null
@@ -1,156 +0,0 @@
-
-
-
-
-
-/*
- ************************************************************************
- *
- * Java 3D configuration file for a cave environment. This cave
- * consists of 3 projectors with 3 screens to the left, front, and right
- * of the user, all at 90 degrees to each other.
- *
- * The projectors in the VirtualPortal sample site are actually turned
- * on their sides to get more height. Screen 0 is rotated 90 degrees
- * counter-clockwise, while screens 1 and 2 are rotated 90 degrees
- * clockwise.
- *
- ************************************************************************
- */
-
-// Create new screen objects and associate them with logical names and numbers.
-// These numbers are used as indices to retrieve the AWT GraphicsDevice from
-// the array that GraphicsEnvironment.getScreenDevices() returns.
-//
-// NOTE: The GraphicsDevice order in the array is specific to the local
-// site and display system.
-//
-(NewScreen left 0)
-(NewScreen center 1)
-(NewScreen right 2)
-
-
-// Set the available image areas as well as their positition and orientation
-// relative to the tracker base. Although this config file doesn't enable
-// head tracking, the tracker base is still needed as a point of reference to
-// describe the position and orientation of the screens relative to the
-// environment.
-//
-// From the orientation of a user standing within this VirtualPortal site and
-// facing the center screen, the tracker base is along the vertical midline of
-// the screen, 0.248 meters down from the top edge, and 1.340 meters in front
-// of it. The tracker base is oriented so that its +X axis points to the left,
-// its +Y axis points toward the screen, and its +Z axis points toward the
-// floor.
-//
-(ScreenProperty left PhysicalScreenWidth 2.480)
-(ScreenProperty left PhysicalScreenHeight 1.705)
-(ScreenProperty left WindowSize NoBorderFullScreen)
-(ScreenProperty left TrackerBaseToImagePlate
- (( 0.0 0.0 -1.0 2.230)
- ( 0.0 -1.0 0.0 1.340)
- (-1.0 0.0 0.0 0.885)))
-
-(ScreenProperty center PhysicalScreenWidth 2.485)
-(ScreenProperty center PhysicalScreenHeight 1.745)
-(ScreenProperty center WindowSize NoBorderFullScreen)
-(ScreenProperty center TrackerBaseToImagePlate
- (( 0.0 0.0 1.0 0.248)
- (-1.0 0.0 0.0 0.885)
- ( 0.0 -1.0 0.0 1.340)))
-
-(ScreenProperty right PhysicalScreenWidth 2.480)
-(ScreenProperty right PhysicalScreenHeight 1.775)
-(ScreenProperty right WindowSize NoBorderFullScreen)
-(ScreenProperty right TrackerBaseToImagePlate
- (( 0.0 0.0 1.0 0.2488)
- ( 0.0 -1.0 0.0 1.340)
- ( 1.0 0.0 0.0 0.860)))
-
-// Set the location of the center of coexistence relative to the tracker base.
-// Here it set to the center of the center screen. This config file will set
-// the location of the user's eyes relative to this point. The default view
-// attach policy of NOMINAL_SCREEN used by ConfiguredUniverse will place the
-// origin of the view platform in coexistence coordinates at the center of
-// coexistence.
-//
-(NewPhysicalEnvironment VirtualPortal)
-(PhysicalEnvironmentProperty VirtualPortal
- CoexistenceToTrackerBase
- ((-1.0 0.0 0.0 0.000)
- ( 0.0 0.0 -1.0 1.340)
- ( 0.0 -1.0 0.0 0.994)))
-
-// Now define the view.
-//
-(NewView view0)
-(ViewProperty view0 Screen left)
-(ViewProperty view0 Screen center)
-(ViewProperty view0 Screen right)
-(ViewProperty view0 PhysicalEnvironment VirtualPortal)
-
-// Set the user eye position in the display environment. It is set here to
-// 1.340 meters back from the center screen (directly under the tracker), and
-// 1.737 meters from the floor (about 5 ft 8.4 inches).
-//
-(ViewProperty view0 CenterEyeInCoexistence (0.0 0.494 1.340))
-
-// Explict scaling.
-//
-(ViewProperty view0 ScreenScalePolicy SCALE_EXPLICIT)
-(ViewProperty view0 ScreenScale 0.30)
-
-// No stereo viewing for this configuration.
-//
-(ViewProperty view0 StereoEnable False)
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-rot45.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-rot45.html
deleted file mode 100644
index 927dbd8..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d1x3-rot45.html
+++ /dev/null
@@ -1,122 +0,0 @@
-
-
-
-
-
-/*
- ************************************************************************
- *
- * Java 3D configuration file for 3 screens. Left and right screens are
- * rotated 45 degrees from the center screen.
- *
- ************************************************************************
- */
-
-// Create new screen objects and associate them with logical names and numbers.
-// These numbers are used as indices to retrieve the AWT GraphicsDevice from
-// the array that GraphicsEnvironment.getScreenDevices() returns.
-//
-// NOTE: The GraphicsDevice order in the array is specific to the local
-// site and display system.
-//
-(NewScreen left 0)
-(NewScreen center 1)
-(NewScreen right 2)
-
-// Set the available image areas for full screens.
-//
-(ScreenProperty left PhysicalScreenWidth 0.360)
-(ScreenProperty left PhysicalScreenHeight 0.288)
-
-(ScreenProperty center PhysicalScreenWidth 0.360)
-(ScreenProperty center PhysicalScreenHeight 0.288)
-
-(ScreenProperty right PhysicalScreenWidth 0.360)
-(ScreenProperty right PhysicalScreenHeight 0.288)
-
-// Specify full screen windows.
-//
-(ScreenProperty left WindowSize NoBorderFullScreen)
-(ScreenProperty center WindowSize NoBorderFullScreen)
-(ScreenProperty right WindowSize NoBorderFullScreen)
-
-// Set the TrackerBaseToImagePlate transforms for these screens.
-//
-// The tracker base and center of coexistence are set here to the middle of the
-// center screen. The basis vectors are aligned with the center screen image
-// plate. The left and right screens are rotated 45 degrees toward each other
-// about their shared edges with the center screen.
-//
-(ScreenProperty center TrackerBaseToImagePlate
- (Translate 0.180000 0.144000 0.000000))
-
-// cos(45) * 0.360 * 0.5 = 0.127279; 0.360 + 0.127279 = 0.487279
-(ScreenProperty left TrackerBaseToImagePlate
- (RotateTranslate
- (Rotate 0.000000 -45.000000 0.000000)
- (Translate 0.487279 0.144000 0.127279)))
-
-// cos(45) * 0.360 * 0.5 = 0.127279
-(ScreenProperty right TrackerBaseToImagePlate
- (RotateTranslate
- (Rotate 0.000000 45.000000 0.000000)
- (Translate -0.127279 0.144000 0.127279)))
-
-// Create a view using the defined screens.
-//
-(NewView view0)
-(ViewProperty view0 Screen left)
-(ViewProperty view0 Screen center)
-(ViewProperty view0 Screen right)
-(ViewProperty view0 CenterEyeInCoexistence (0.0 0.0 0.5))
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d2x2-flat.html b/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d2x2-flat.html
deleted file mode 100644
index af6f62f..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/doc-files/j3d2x2-flat.html
+++ /dev/null
@@ -1,147 +0,0 @@
-
-
-
-
-
-/*
- ************************************************************************
- *
- * Java 3D configuration file for 4 screen projection configuration
- * arranged in a 2x2 power wall.
- *
- ************************************************************************
- */
-
-// Create new screen objects and associate them with logical names and numbers.
-// These numbers are used as indices to retrieve the AWT GraphicsDevice from
-// the array that GraphicsEnvironment.getScreenDevices() returns.
-//
-// NOTE: The GraphicsDevice order in the array is specific to the local
-// site and display system.
-//
-(NewScreen topleft 0)
-(NewScreen topright 1)
-(NewScreen bottomleft 3)
-(NewScreen bottomright 2)
-
-// Set the available image areas for full screens. This is important when
-// precise scaling between objects in the virtual world and their projections
-// into the physical world is desired through use of explicit ScreenScale view
-// attributes. The defaults are 0.365 meters for width and 0.292 meters for
-// height.
-//
-(ScreenProperty topleft PhysicalScreenWidth 0.912)
-(ScreenProperty topleft PhysicalScreenHeight 0.680)
-
-(ScreenProperty topright PhysicalScreenWidth 0.912)
-(ScreenProperty topright PhysicalScreenHeight 0.680)
-
-(ScreenProperty bottomleft PhysicalScreenWidth 0.912)
-(ScreenProperty bottomleft PhysicalScreenHeight 0.685)
-
-(ScreenProperty bottomright PhysicalScreenWidth 0.912)
-(ScreenProperty bottomright PhysicalScreenHeight 0.685)
-
-
-// Specify full screen windows.
-//
-(ScreenProperty topleft WindowSize NoBorderFullScreen)
-(ScreenProperty topright WindowSize NoBorderFullScreen)
-(ScreenProperty bottomleft WindowSize NoBorderFullScreen)
-(ScreenProperty bottomright WindowSize NoBorderFullScreen)
-
-// Set the TrackerBaseToImagePlate transforms for these screens. This
-// transforms points in tracker base coordinates to each screen's image plate
-// coordinates, where the origin of the image plate is defined to be the lower
-// left corner of the screen with X increasing to the right, Y increasing to
-// the top, and Z increasing away from the screen.
-//
-// Without head or sensor tracking the tracker base is still needed as a point
-// of reference for describing the orientation and position of each screen to
-// the others. The coexistence to tracker base transform is set to identity by
-// default, so the tracker base origin and orientation will also set the origin
-// and orientation of coexistence coordinates in the physical world.
-//
-// The tracker base and center of coexistence are set here to the center of the
-// 2x2 array with its basis vectors aligned to image plate coordinates.
-//
-(ScreenProperty topleft TrackerBaseToImagePlate
- (Translate 0.912 0.000 0.0))
-(ScreenProperty topright TrackerBaseToImagePlate
- (Translate 0.000 0.000 0.0))
-(ScreenProperty bottomleft TrackerBaseToImagePlate
- (Translate 0.912 0.685 0.0))
-(ScreenProperty bottomright TrackerBaseToImagePlate
- (Translate 0.000 0.685 0.0))
-
-// Create a view using the defined screens.
-//
-(NewView view0)
-(ViewProperty view0 Screen topleft)
-(ViewProperty view0 Screen topright)
-(ViewProperty view0 Screen bottomleft)
-(ViewProperty view0 Screen bottomright)
-
-// Set the screen scale. This is scale factor from virtual to physical
-// coordinates. The default policy of SCALE_SCREEN_SIZE doesn't work well here
-// since in the 2x2 arrangement the individual screens are too small. The
-// explicit scale factor below assumes a normalized range of object coordinates
-// of [-1.0 .. +1.0].
-//
-(ViewProperty view0 ScreenScalePolicy SCALE_EXPLICIT)
-(ViewProperty view0 ScreenScale 0.912)
-
-// Set the user eye position in the display environment.
-//
-(ViewProperty view0 CenterEyeInCoexistence (0.0 0.0 1.0))
-
-
-
diff --git a/src/classes/share/com/sun/j3d/utils/universe/package.html b/src/classes/share/com/sun/j3d/utils/universe/package.html
deleted file mode 100644
index 1ef0eaf..0000000
--- a/src/classes/share/com/sun/j3d/utils/universe/package.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
+ * Lightweight canvas also handles redirection to heavyweight canvas for the
+ * following events:
+ * - InputMethodEvent
+ * - KeyEvent
+ * - FocusEvent
+ * - ComponentKeyEvent
+ * - MouseWheelEvent
+ * - MouseEvent
+ * - MouseMotionEvent
+ *
+ *
+ * When Swing is waiting for a canvas to be retrieved and that canvas is in
+ * rendering stage,a loop takes place, which includes small calls to wait().
+ * The canvas status is tested for readiness before and after the wait(). If
+ * the canvas is not ready to be retrieved after the wait(), counter is
+ * decremented and control is given back to awt thread, which will repaint old
+ * buffer. If the loop goes over a certain amount of iterations, the canvas is
+ * declared 'crashed' and won't be updated anymore. This was done so that a
+ * crashed canvas/universe does not remove control over your GUI and does not
+ * leave you with a frozen application. In current implementation, the delay
+ * before a canvas is declared crashed is of :
+ * 30 Math.max(20.0, getView().getMinimumFrameCycleTime() )
+ *
+ * @author Frederic 'pepe' Barachant
+ *
+ * @see getLightweightComponent()
+ * @see setResizeValidationDelay()
+ * @see setResizeMode()
+ *
+ * @since Java 3D 1.5
+ */
+public class JCanvas3D extends JPanel implements AncestorListener {
+ /**
+ * Resizing the canvas or component will be done immediately. This
+ * operation might take some time and make the application look sluggish.
+ *
+ * @see setResizeMode()
+ */
+ public final static int RESIZE_IMMEDIATELY = 0;
+
+ /**
+ * Resizing the canvas or component will be done if no resizing
+ * occurs after expiration of a certain delay. Rendering will be
+ * eventually stretched or deformed. It can be useful on certain
+ * applications where smooth update of UI during layout is needed or
+ * desired.
+ *
+ * @see setResizeMode()
+ */
+ public final static int RESIZE_DELAYED = 1;
+
+ //TODO: FBA: this had been taken from org.jogamp.java3d.Screen3D. When/IF proper dpi handling comes one day, that part will have to be changed also for consistency
+ /** size of a pixel */
+ private static double METERS_PER_PIXEL = 0.0254 / 90.0;
+
+ /** the template to be used for this canvas */
+ private GraphicsConfigTemplate3D template;
+
+ /** the graphics configuration used for this canvas */
+ private GraphicsConfiguration graphicsConfig;
+
+ /** The canvas that is linked to the component. */
+ private InternalCanvas3D canvas;
+
+ /** flag indicating that the JCanvas3D has been added to a container */
+ private boolean hasBeenAdded = false;
+
+ /** The resize mode currently being used. */
+ int resizeMode;
+
+ /**
+ * the idle delay that will trigger a real resize. ('idle' being
+ * the lack of resizing action from the user)
+ */
+ int resizeValidationDelay;
+
+ /** the device to be used by this canvas */
+ private GraphicsDevice device;
+
+ //TODO: FBA: the constructor below should be callable. Code should be changed so that it is possible, in order for the canvas to be useable into netbeans.
+ //TODO: FBA: create a netbeans module that installs J3D as a library and the JCanvas3D as a new item in a new J3D category of the swing palette (take from the java.net swash project)
+
+ /**
+ * Constructs and initializes a new JCanvas3D object that Java 3D
+ * can render into. The screen device is obtained from
+ * GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
,
+ * which might not be the one you should use if you are in a multiscreen environment.
+ * The JCanvas3D is constructed using the following default parameters:
+ * resize mode : RESIZE_IMMEDIATELY
+ * validation delay : 100ms
+ * double buffer enable : false
+ * stereo enable : false
+ */
+ public JCanvas3D() {
+ this(null, GraphicsEnvironment.getLocalGraphicsEnvironment().
+ getDefaultScreenDevice());
+ }
+
+ /**
+ * Constructs and initializes a new Canvas3D object that Java 3D
+ * can render into, using the specified graphics device.
+ *
+ * @param device the screen graphics device that will be used to construct
+ * a GraphicsConfiguration.
+ */
+ public JCanvas3D(GraphicsDevice device) {
+ this(null, device);
+ }
+
+ /**
+ * Constructs and initializes a new Canvas3D object that Java 3D
+ * can render into, using the specified template.
+ * The screen device is obtained from
+ * GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
,
+ * which might not be the one you should use if you are
+ * in a multiscreen environment.
+ *
+ * @param template The template that will be used to construct a
+ * GraphicsConfiguration. The stereo and doublebuffer properties
+ * are forced to UNNECESSARY.
+ */
+ public JCanvas3D(GraphicsConfigTemplate3D template) {
+ this(template, GraphicsEnvironment.getLocalGraphicsEnvironment().
+ getDefaultScreenDevice());
+ }
+
+ /**
+ * Constructs and initializes a new Canvas3D object that Java 3D
+ * can render into, using the specified template and graphics device.
+ *
+ * @param template The template that will be used to construct a
+ * GraphicsConfiguration. The stereo and doublebuffer properties
+ * are forced to UNNECESSARY.
+ * @param device the screen graphics device that will be used to construct
+ * a GraphicsConfiguration in conjunction with the template.
+ */
+ public JCanvas3D(GraphicsConfigTemplate3D template, GraphicsDevice device) {
+ this.device = device;
+ this.template = new GraphicsConfigTemplate3D();
+
+ if (template != null) {
+ // Clone template (it would be easier if GCT3D were cloneable)
+ this.template.setRedSize(template.getRedSize());
+ this.template.setGreenSize(template.getGreenSize());
+ this.template.setBlueSize(template.getBlueSize());
+ this.template.setDepthSize(template.getDepthSize());
+ this.template.setSceneAntialiasing(template.getSceneAntialiasing());
+ this.template.setStencilSize(template.getStencilSize());
+ this.template.setDoubleBuffer(template.getDoubleBuffer());
+// this.template.setStereo(template.getStereo());
+ }
+
+ // Force double-buffer and stereo to UNNECESSARY
+ this.template.setStereo(GraphicsConfigTemplate.UNNECESSARY);
+
+ graphicsConfig = this.device.getBestConfiguration(this.template);
+
+ addAncestorListener(this);
+ setDoubleBuffered(false);
+ setResizeMode(RESIZE_IMMEDIATELY);
+ setResizeValidationDelay(100);
+
+ // so that key events and such can be received.
+ setFocusable(true);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param event {@inheritDoc}
+ */
+ @Override
+ public void ancestorAdded(javax.swing.event.AncestorEvent event) {
+ // if ( true == isVisible( ) ) // check if the component itself is visible.
+ {
+ Dimension sz = getSize();
+
+ if (0 == sz.width) {
+ sz.width = 100;
+ }
+
+ if (0 == sz.height) {
+ sz.height = 100;
+ }
+
+ createCanvas(sz.width, sz.height);
+ canvas.addNotifyFlag = true; // make it so that i can call addNotify() without being rejected.
+ canvas.addNotify();
+ hasBeenAdded = true;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param event {@inheritDoc}
+ */
+ @Override
+ public void ancestorMoved(javax.swing.event.AncestorEvent event) {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param event {@inheritDoc}
+ */
+ @Override
+ public void ancestorRemoved(javax.swing.event.AncestorEvent event) {
+ hasBeenAdded = false;
+ canvas.removeNotify();
+ }
+
+ /**
+ * Computes the physical dimensions of the screen in space.
+ */
+ private void computePhysicalDimensions() {
+ // Fix to Issue : 433 - JCanvas3D crashed when using jogl pipe.
+ Rectangle screenRect = this.graphicsConfig.getBounds();
+ int screenWidth = (int) screenRect.getWidth();
+ int screenHeight = (int) screenRect.getHeight();
+ canvas.getScreen3D().setSize(screenWidth, screenHeight);
+ canvas.getScreen3D()
+ .setPhysicalScreenWidth(((double) screenWidth) * METERS_PER_PIXEL);
+ canvas.getScreen3D()
+ .setPhysicalScreenHeight(((double) screenHeight) * METERS_PER_PIXEL);
+ }
+
+ /**
+ * Creates a heavyweight canvas and initializes it, or changes the
+ * size of the current one if present. Current heavyweight canvas is
+ * changed only if size is different from the actual one. No canvas is
+ * created if this component has no parent, that is, was not added to a
+ * container.
+ *
+ * @param width the width of the canvas to create.
+ * @param height the height of the canvas to create.
+ */
+ void createCanvas(int width, int height) {
+ if (getParent() == null) {
+ return;
+ }
+
+ if (null != canvas) {
+ // i had a canvas, i need to check if i really need to change it
+ if ((width != canvas.getWidth()) || (height != canvas.getHeight())) {
+ if ((null != canvas.getOffScreenBuffer()) &&
+ (null != canvas.getOffScreenBuffer().getImage())) {
+ canvas.getOffScreenBuffer().getImage().flush(); // flushing so that eventual resources are freed.
+ }
+ } else {
+ return;
+ }
+ } else {
+ // no canvas, i have to create it.
+ canvas = new InternalCanvas3D(this.graphicsConfig, this);
+ }
+
+ createOffScreenBuffer(width, height); // whatever happened right above, i need to create the offscreen buffer.
+ }
+
+ /**
+ * Creates an offscreen buffer to be attached to the heavyweight
+ * buffer. Buffer is created 'byreference'
+ *
+ * @param width the width of the buffer.
+ * @param height the height of the buffer.
+ */
+ private void createOffScreenBuffer(int width, int height) {
+ computePhysicalDimensions();
+
+ // this.canvas.setDoubleBufferEnable( false );
+ java.awt.image.BufferedImage bImage = new java.awt.image.BufferedImage(width,
+ height, java.awt.image.BufferedImage.TYPE_INT_ARGB);
+ org.jogamp.java3d.ImageComponent2D image = new org.jogamp.java3d.ImageComponent2D(org.jogamp.java3d.ImageComponent2D.FORMAT_RGBA8,
+ bImage, true, false );
+ image.setCapability(image.ALLOW_IMAGE_READ);
+ image.setCapability(image.ALLOW_IMAGE_WRITE);
+
+ this.canvas.stopRenderer();
+
+ // offscreenrendering might occur even if the renderer is stopped. For that reason, i'm waiting for an hypothetical offscreen render to finish before setting offscreen rendering.
+ // Otherwise, rendering will stop with an exception.
+ this.canvas.waitForOffScreenRendering();
+
+ this.canvas.setOffScreenBuffer(image);
+ this.canvas.startRenderer();
+ }
+
+ /**
+ * Returns the offscreen heavyweight canvas of that lightweight
+ * component.
+ *
+ * @return the heavyweight canvas that lies in the deepness of this
+ * Component.
+ */
+ public Canvas3D getOffscreenCanvas3D() {
+ if (null == this.canvas) {
+ createCanvas(getWidth(), getHeight());
+ }
+
+ return this.canvas;
+ }
+
+ /**
+ * Retrieves the resize mode for that component.
+ *
+ * @return the resize mode, which can be one of RESIZE_IMMEDIATELY or
+ * RESIZE_DELAYED
+ */
+ public int getResizeMode() {
+ return resizeMode;
+ }
+
+ /**
+ * Retrieves the validation delay for that canvas, whatever the
+ * resize mode is set to.
+ *
+ * @return the validation delay.
+ */
+ public int getResizeValidationDelay() {
+ return resizeValidationDelay;
+ }
+
+ /**
+ * Paints the result of the rendering. If the rendered buffer is
+ * not useable (render thread being between [code]postRender()[/code] and
+ * [code]postSwap()[/code]), it will wait for it to be ready. Otherwise it
+ * will directly paint the previous buffer.
+ *
+ * @param g {@inheritDoc}
+ */
+ @Override
+ public void paintComponent(java.awt.Graphics g) {
+ super.paintComponent(g); //paint background
+
+ // Wait for and display image if JCanvas3D was added to an ancestor
+ if (hasBeenAdded) {
+ if ((false == canvas.canvasCrashed) &&
+ (true == canvas.isRendererRunning())) {
+ // System.err.println("paintComponentWaitforSwap");
+ canvas.waitForSwap();
+
+ // System.err.println("wait is over");
+ }
+
+ if (null != canvas.bi) {
+ // can eventually be null if the canvas did not send the result in the desired timeframe
+ // for first render. In that case, we don't paint and keep the background as-is.
+ g.drawImage(canvas.bi, 0, 0, getWidth(), getHeight(), null);
+ }
+ }
+ }
+
+ /**
+ * Redirects event to canvas and to superclass.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processComponentKeyEvent(java.awt.event.KeyEvent e) {
+ super.processComponentKeyEvent(e);
+
+ Object src = e.getSource();
+ e.setSource(canvas);
+ canvas.processComponentEvent(e);
+ e.setSource(src);
+ }
+
+ /**
+ * Redirects event to canvas and to superclass.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processFocusEvent(java.awt.event.FocusEvent e) {
+ super.processFocusEvent(e);
+
+ Object src = e.getSource();
+ e.setSource(canvas);
+ canvas.processFocusEvent(e);
+ e.setSource(src);
+ }
+
+ /**
+ * Redirects event to canvas and to superclass.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processInputMethodEvent(java.awt.event.InputMethodEvent e) {
+ super.processInputMethodEvent(e);
+
+ Object src = e.getSource();
+ e.setSource(canvas);
+ canvas.processInputMethodEvent(e);
+ e.setSource(src);
+ }
+
+ /**
+ * Redirects event to canvas and to superclass.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processKeyEvent(java.awt.event.KeyEvent e) {
+ super.processKeyEvent(e);
+
+ Object src = e.getSource();
+ e.setSource(canvas);
+ canvas.processKeyEvent(e);
+ e.setSource(src);
+ }
+
+ /**
+ * Redirects event to canvas and to superclass.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processMouseEvent(java.awt.event.MouseEvent e) {
+ super.processMouseEvent(e);
+
+ Object src = e.getSource();
+ e.setSource(canvas);
+ canvas.processMouseEvent(e);
+ e.setSource(src);
+ }
+
+ /**
+ * Redirects event to canvas and to superclass.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processMouseMotionEvent(java.awt.event.MouseEvent e) {
+ super.processMouseMotionEvent(e);
+
+ Object src = e.getSource();
+ e.setSource(canvas);
+ canvas.processMouseMotionEvent(e);
+ e.setSource(src);
+ }
+
+ /**
+ * Redirects event to canvas and to superclass.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processMouseWheelEvent(java.awt.event.MouseWheelEvent e) {
+ super.processMouseWheelEvent(e);
+
+ Object src = e.getSource();
+ e.setSource(canvas);
+ canvas.processMouseWheelEvent(e);
+ e.setSource(src);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param x {@inheritDoc}
+ * @param y {@inheritDoc}
+ * @param width {@inheritDoc}
+ * @param height {@inheritDoc}
+ */
+ @Override
+ public void setBounds(int x, int y, int width, int height) {
+ super.setBounds(x, y, width, height);
+
+ if ((null == canvas) || (null == canvas.getOffScreenBuffer()) ||
+ (JCanvas3D.RESIZE_IMMEDIATELY == getResizeMode())) //whatever the resize mode, i create on first setbounds(). (not doing so would create a deadlock in DELAYED mode when trying to do the first paint
+ {
+ createCanvas(width, height);
+ } else if ((JCanvas3D.RESIZE_DELAYED == getResizeMode()) &&
+ ((null != canvas.getParent()) &&
+ (true == canvas.getParent().isVisible()))) {
+ if ((null == canvas.resizeThread) ||
+ (false == canvas.resizeThread.isAlive())) {
+ canvas.resizeThread = new ResizeThread(width, height,
+ getResizeValidationDelay(), this);
+ canvas.resizeThread.start();
+ } else {
+ canvas.resizeThread.setWidth(width);
+ canvas.resizeThread.setHeight(height);
+ }
+ }
+ }
+
+ /**
+ * Sets resize mode to be used on this component. Resize mode
+ * permits to have smoother canvas resizes. The time taken by a canvas to
+ * be resized can be pretty long: renderer has to stop, current render has
+ * to end, everything has to be initialized again, and after all that has
+ * been done, renderer is started again, then the image is displayed once
+ * rendered. Resize mode uses a timer to make those steps only after the
+ * last refresh request occured. 'Latest refresh' is determined by the
+ * amount of time between now and the last time you asked for a size
+ * change. If that time expires, a real resize is done. In between, the
+ * same size is rendered, but the drawn image is scaled down/up. This has
+ * some drawbacks, as the image can appear blocked, imprecise, distorted,
+ * incomplete for that while, but most of the time only some of the
+ * drawbacks will be users will see nothing. Default delay is set to
+ * 100ms, which is low enough for common human not to be able to really
+ * see that the rendered image is scaled.
+ *
+ * @param resizeMode can be one of RESIZE_IMMEDIATELY or RESIZE_DELAYED
+ * @see #RESIZE_IMMEDIATELY
+ * @see #RESIZE_DELAYED
+ */
+ public void setResizeMode(int resizeMode) {
+ this.resizeMode = resizeMode;
+ }
+
+ /**
+ * Sets the validation delay for the component. The validation
+ * delay is the maximum time allowed for the canvas resizing to occur
+ * using rendered buffer scaling. Once that delay expired, the canvas is
+ * resized at the lowest level possible, thus in the rendering pipeline.
+ * Note: Changing this field is only useful if resize mode is set to
+ * RESIZE_IMMEDIATELY or RESIZE_DELAYED
+ *
+ * @param resizeValidationDelay the delay before a real resize would occur.
+ * @see #RESIZE_IMMEDIATELY
+ * @see #RESIZE_DELAYED
+ */
+ public void setResizeValidationDelay(int resizeValidationDelay) {
+ this.resizeValidationDelay = resizeValidationDelay;
+ }
+
+ /**
+ * This class is the internal Canvas3D that is used and sent to
+ * Java 3D. It is remote controlled through JCanvas3D and is modified to be
+ * able to tell the lightweight component when refreshes are needed.
+ */
+ static class InternalCanvas3D extends Canvas3D
+ implements AutoOffScreenCanvas3D {
+
+ // These two constants define the maximum amount of time
+ // to wait for the readback of the off-screen buffer to complete.
+ // The total time is MAX_WAIT_LOOPS * MAX_WAIT_TIME msec.
+ private static final int MAX_WAIT_LOOPS = 5;
+ private static final long MAX_WAIT_TIME = 10;
+
+ /**
+ * the bufferedImage that will be displayed as the result
+ * of the computations.
+ */
+ BufferedImage bi = null;
+
+ /**
+ * This is the lightweight canvas that is linked to that
+ * offscreen canvas.
+ */
+ JCanvas3D lwCanvas;
+
+ /**
+ * If delayed resizing is selected, a thread handling
+ * resising will be started.
+ */
+ ResizeThread resizeThread;
+
+ /**
+ * flag used to sort a call to addnotify() from user and
+ * from the lightweight component. Lightweight component calls
+ * addNotify() so that the rendering begins and uses normal routines,
+ * but this is a method that user must not call.
+ */
+ boolean addNotifyFlag;
+
+ /**
+ * flag indicating that the canvas crashed in a way or an
+ * other, making swing to wait for the swap for much too long.
+ */
+ protected boolean canvasCrashed;
+
+ /**
+ * flag used to know when image can be painted or not. This
+ * is to avoid component potentially displaying a buffer with an
+ * unfinished blit. There is already a flag (imageReady) in Canvas3D
+ * that does this but it can't be used because of restrictions. This
+ * flag is not really fine grained, being set from end of postRender()
+ * to end of postSwap()
+ */
+ boolean imageReadyBis;
+
+ /**
+ * Flag to indicate that the component is waiting for the
+ * canvas to acomplish its swap, and that the component has to be
+ * notified when done.
+ */
+ boolean waitingForSwap;
+
+ /**
+ * Creates a new instance of JCanvas3D. Resize mode is set
+ * to RESIZE_IMMEDIATELY and validation delay to 100ms.
+ *
+ * @param graphicsConfiguration The graphics configuration to be used.
+ * @param lwCanvas the lightweight canvas that is linked to that
+ * heavyweight canvas.
+ */
+ public InternalCanvas3D(GraphicsConfiguration graphicsConfiguration,
+ JCanvas3D lwCanvas) {
+ super(graphicsConfiguration, true);
+ this.lwCanvas = lwCanvas;
+ imageReadyBis = false;
+ waitingForSwap = false;
+ addNotifyFlag = false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ if (false == addNotifyFlag) {
+ throw new UnsupportedOperationException("CHANGE ME");
+ } else {
+ addNotifyFlag = false;
+ super.addNotify();
+ }
+ }
+
+ /**
+ * Normally, returns the parent of that component. As the
+ * canvas ought to never be added to any component, it has no parent.
+ * Java 3D expects it to have a parent for some operations, so we in
+ * fact cheat it by returning the parent of the lightweight component.
+ *
+ * @return the parent of the lightweight component, if any. Returns
+ * null if the component is not created or if it has no
+ * parent.
+ */
+ @Override
+ public java.awt.Container getParent() {
+ if (null == this.lwCanvas) {
+ return null;
+ }
+
+ return this.lwCanvas.getParent();
+ }
+
+ /**
+ * Blocks the retrieval of the render buffer.
+ */
+ @Override
+ public void postRender() {
+ imageReadyBis = false;
+ }
+
+ /**
+ * Retrieves the buffer from canvas, if possible, and
+ * calls/notifies component to be repainted, if necessary.
+ */
+ @Override
+ synchronized public void postSwap() {
+ if (true == isRendererRunning()) { // as weird as it can look, there can be postswaps without rendered running. (?!!) Anyway, in that case we should not refresh.
+ bi = getOffScreenBuffer().getImage();
+ imageReadyBis = true;
+
+ if (false == waitingForSwap) {
+ // System.err.println("repaint " + System.currentTimeMillis());
+ this.lwCanvas.repaint();
+ } else {
+ notify();
+ }
+ } else {
+ // System.err.println("SWAP WITHOUT RENDERER RUNNING");
+ }
+ }
+
+ /**
+ * Overriden so that the JComponent can access it.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processComponentEvent(java.awt.event.ComponentEvent e) {
+ super.processComponentEvent(e);
+ }
+
+ /**
+ * Overriden so that the JComponent can access it.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processFocusEvent(java.awt.event.FocusEvent e) {
+ super.processFocusEvent(e);
+ }
+
+ /**
+ * Overriden so that the JComponent can access it.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processInputMethodEvent(
+ java.awt.event.InputMethodEvent e) {
+ super.processInputMethodEvent(e);
+ }
+
+ /**
+ * Overriden so that the JComponent can access it.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processKeyEvent(java.awt.event.KeyEvent e) {
+ super.processKeyEvent(e);
+ }
+
+ /**
+ * Overriden so that the JComponent can access it.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processMouseEvent(java.awt.event.MouseEvent e) {
+ super.processMouseEvent(e);
+ }
+
+ /**
+ * Overriden so that the JComponent can access it.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processMouseMotionEvent(java.awt.event.MouseEvent e) {
+ super.processMouseMotionEvent(e);
+ }
+
+ /**
+ * Overriden so that the JComponent can access it.
+ *
+ * @param e {@inheritDoc}
+ */
+ @Override
+ protected void processMouseWheelEvent(java.awt.event.MouseWheelEvent e) {
+ super.processMouseWheelEvent(e);
+ }
+
+ /**
+ * If the Canvas is in a state that forbids the retrieving
+ * of the buffer, wait a bit before trying again.
+ */
+ synchronized void waitForSwap() {
+ int counter = MAX_WAIT_LOOPS;
+ while (false == imageReadyBis) {
+ try {
+ waitingForSwap = true;
+ wait(MAX_WAIT_TIME);
+ waitingForSwap = false;
+
+ if (!imageReadyBis && --counter <= 0) {
+ //if i've waited too long for the canvas to be there, let us declare it crashed.
+ //System.err.println("CANVAS CRASHED!!!");
+ canvasCrashed = true;
+ return;
+ }
+ } catch (InterruptedException ex) {
+ System.err.println(ex);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * This Runnable is the class used when the canvas has to be
+ * resized.
+ */
+ static class ResizeSwingRunnable implements Runnable {
+ /** The component that is displaying the canvas */
+ JCanvas3D canvas;
+
+ /** latest height that was requested */
+ int height;
+
+ /** latest width that was requested */
+ int width;
+
+ /**
+ * Creates a new ResizeSwingRunnable object.
+ */
+ private ResizeSwingRunnable() {
+ }
+
+ /**
+ * Creates a new ResizeSwingRunnable object.
+ *
+ * @param canvas the canvas to check
+ * @param width the width that is requested
+ * @param height the height that is requested
+ */
+ public ResizeSwingRunnable(JCanvas3D canvas, int width, int height) {
+ this.canvas = canvas;
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run() {
+ canvas.createCanvas(width, height);
+ }
+ }
+
+ /**
+ * This Thread handles the resizing changes and handles the timer
+ * up to the moment when the resizing has to really occur.
+ */
+ static class ResizeThread extends Thread {
+ //TODO: refactor so that it can handle a list of canvases, delays and start delay date, and change to a singleton. Actually, each JCanvas3D that would have to resize would spawn its own thread, which ought to be seen as "a bad thing"
+ /** the canvas that has to be checked */
+ JCanvas3D canvas;
+
+ /** A flag indicating that since last check, size got changed again and the delay has to be reset */
+ boolean sizeChanged;
+
+ /** the delay that has to occur between last size change and real resize */
+ int delay;
+
+ /** latest height that was requested */
+ int height;
+
+ /** latest width that was requested */
+ int width;
+
+ /**
+ * Creates a new ResizeThread object.
+ */
+ private ResizeThread() {
+ }
+
+ /**
+ * Creates a new ResizeThread object.
+ *
+ * @param width initial width change
+ * @param height initial height change
+ * @param delay delay to be used
+ * @param canvas the canvas that has to be checked
+ */
+ public ResizeThread(int width, int height, int delay, JCanvas3D canvas) {
+ this.width = width;
+ this.height = height;
+ this.delay = delay;
+ this.sizeChanged = true;
+ this.canvas = canvas;
+ }
+
+ /**
+ * returns the latest height that is being requested for change
+ *
+ * @return latest height requested
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * returns the latest width that is being requested for change
+ *
+ * @return latest width requested
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run() {
+ try {
+ while (true == sizeChanged) // the double loop is made so that if a change of size arrives while the canvas is already resizing, the same thread can keep up with subsequent resizes.
+ { // the effect of the double loop is to simplify some subtle race conditions at higher level.
+
+ while (true == sizeChanged) {
+ sizeChanged = false;
+ Thread.sleep(delay); // while the thread sleeps, value can change. if value changes, flag will be true, and i'll have to wait again. if size does not change during the sleep, thread will quit and size will change.
+ //TODO: should i force a resize after a definite delay occured, so it does not stay zoomed too long ?
+ }
+
+ try {
+ EventQueue.invokeAndWait(new ResizeSwingRunnable(
+ canvas, width, height));
+ } catch (InterruptedException ie) {
+ } catch (InvocationTargetException ite) {
+ }
+ }
+ } catch (InterruptedException ie) {
+ //if i get interrupted, this is not important, i'll quit method.
+ }
+ }
+
+ /**
+ * sets height. this has the effect of resetting the timeout.
+ *
+ * @param height the new height.
+ *
+ * @throws RuntimeException DOCUMENT ME!
+ */
+ public void setHeight(int height) {
+ if (isAlive()) {
+ this.height = height;
+ sizeChanged = true;
+ } else {
+ throw new RuntimeException(
+ "Resizing order arrived to a dead resizing thread. Spawn a new one.");
+ }
+ }
+
+ /**
+ * Sets width. This has the effect of resetting the timeout.
+ *
+ * @param width the new width.
+ *
+ * @throws RuntimeException DOCUMENT ME!
+ */
+ public void setWidth(int width) {
+ if (isAlive()) {
+ this.width = width;
+ sizeChanged = true;
+ } else {
+ throw new RuntimeException(
+ "Resizing order arrived to a dead resizing thread. Spawn a new one.");
+ }
+ }
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/exp/swing/impl/AutoOffScreenCanvas3D.java b/src/classes/share/org/jogamp/java3d/exp/swing/impl/AutoOffScreenCanvas3D.java
new file mode 100644
index 0000000..6e87725
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/exp/swing/impl/AutoOffScreenCanvas3D.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.exp.swing.impl;
+
+/**
+ * Tagging interface for Java 3D off-screen Canvas3D objects that are
+ * automatically rendered. This is used internally by the JCanvas3D
+ * implementation.
+ * dst.length
+ * bytes from
+ * the buffer to the destination array and increments the
+ * buffer's position by dst.length
.
+ */
+ public ByteBufferWrapper get(byte[] dst) {
+ buffer.get(dst);
+ return this;
+ }
+
+ /**
+ * Bulk get method. Transfers length bytes
+ * from the buffer starting at position offset into
+ * the destination array.
+ */
+ public ByteBufferWrapper get(byte[] dst, int offset, int length) {
+ buffer.get(dst, offset, length);
+ return this;
+ }
+
+ /**
+ * Returns the byte order of this buffer.
+ */
+ public ByteOrder order() {
+ return buffer.order();
+ }
+
+ /**
+ * Modifies this buffer's byte order.
+ */
+ public ByteBufferWrapper order(ByteOrder bo)
+ {
+ buffer.order( bo );
+ return this;
+ }
+
+ /**
+ * Creates a view of this ByteBufferWrapper as a
+ * FloatBufferWrapper. Uses the correct
+ */
+ public FloatBufferWrapper asFloatBuffer() {
+ return new FloatBufferWrapper( buffer.asFloatBuffer() );
+ }
+
+ /**
+ * Creates a view of this ByteBufferWrapper as a
+ * DoubleBufferWrapper.
+ */
+ public DoubleBufferWrapper asDoubleBuffer() {
+ return new DoubleBufferWrapper( buffer.asDoubleBuffer() );
+ }
+
+ /**
+ * Bulk put method. Transfers src.length
+ * bytes into the buffer at the current position.
+ */
+ public ByteBufferWrapper put(byte[] src) {
+ buffer.put(src);
+ return this;
+ }
+
+ /**
+ * Creates and returns a J3DBuffer object containing the
+ * buffer in this ByteBufferWrapper object.
+ */
+ public J3DBuffer getJ3DBuffer() {
+ return new J3DBuffer( buffer );
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/internal/Distance.java b/src/classes/share/org/jogamp/java3d/internal/Distance.java
new file mode 100644
index 0000000..d5a7bfc
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/internal/Distance.java
@@ -0,0 +1,1092 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// --------------------------------------------------
+//
+// Distance routines, ported from:
+//
+// Magic Software, Inc.
+// http://www.magic-software.com
+// http://www.wild-magic.com
+// Copyright (c) 2004. All Rights Reserved
+//
+// The Wild Magic Library (WML) source code is supplied under the terms of
+// the license agreement http://www.magic-software.com/License/WildMagic.pdf
+// and may not be copied or disclosed except in accordance with the terms of
+// that agreement.
+//
+// --------------------------------------------------
+
+package org.jogamp.java3d.internal;
+
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Vector3d;
+
+/**
+ * Utility class used to calculate distance. Contains static methods
+ * used by picking method to determine intersections.
+ */
+
+public class Distance {
+ /* Threshold factor to determine if two lines are parallel */
+ static final double FUZZ = 1E-5;
+
+ /* Utility method, for easy switch between distance and squared distance */
+ private static final double DIST (double in) {
+ // return Math.sqrt (Math.abs (in));
+ return Math.abs (in);
+ }
+
+ /**
+ * Minimum ray to segment distance.
+ *
+ * @param rayorig Origin of the ray
+ * @param raydir Direction of the ray
+ * @param segstart Segment start point
+ * @param segend Segment end point
+ * @return the square of the minimum distance from the ray to the segment
+ */
+ static public double rayToSegment (Point3d rayorig,
+ Vector3d raydir,
+ Point3d segstart,
+ Point3d segend) {
+ return rayToSegment (rayorig, raydir, segstart, segend, null, null, null);
+ }
+
+ /**
+ * Minimum ray to segment distance. Returns the square of the distance.
+ *
+ * @param rayorig Origin of the ray
+ *
+ * @param raydir Direction of the ray
+ *
+ * @param segstart Segment start point
+ *
+ * @param segend Segment end point
+ *
+ * @param rayint If non-null, will be filled with the coordinates of
+ * the point corresponding to the minimum distance on the ray.
+ *
+ * @param segint If non-null, will be filled with the coordinates of
+ * the point corresponding to the minimum distance on the segment.
+ *
+ * @param param An array of two doubles, will be filled with the
+ * parametric factors used to find the point of shortest distance on
+ * each primitive (ray = O +sD, with O=origin and
+ * D=direction). param[0] will contain the parameter for the ray,
+ * and param[1] the parameter for the segment.
+ *
+ * @return the square of the minimum distance from the ray to the
+ * segment
+ */
+ static public double rayToSegment (Point3d rayorig,
+ Vector3d raydir,
+ Point3d segstart,
+ Point3d segend,
+ Point3d rayint,
+ Point3d segint,
+ double[] param) {
+ double s, t;
+
+ Vector3d diff = new Vector3d();
+ diff.sub (rayorig,segstart);
+ Vector3d segdir = new Vector3d();
+ segdir.sub (segend, segstart);
+ /*
+ System.out.println (rayorig + "\n" + raydir + "\n" + segstart + "\n" +
+ segdir);
+ */
+ double A = raydir.dot (raydir);//Dot(ray.m,ray.m);
+ double B = -raydir.dot (segdir);//-Dot(ray.m,seg.m);
+ double C = segdir.dot (segdir);//Dot(seg.m,seg.m);
+ double D = raydir.dot (diff);//Dot(ray.m,diff);
+ double E; // -Dot(seg.m,diff), defer until needed
+ double F = diff.dot (diff);//Dot(diff,diff);
+ double det = Math.abs(A*C-B*B); // A*C-B*B = |Cross(M0,M1)|^2 >= 0
+
+ double tmp;
+
+ if (det >= FUZZ) {
+ // ray and segment are not parallel
+ E = -segdir.dot (diff);//-Dot(seg.m,diff);
+ s = B*E-C*D;
+ t = B*D-A*E;
+
+ if (s >= 0) {
+ if (t >= 0) {
+ if (t <= det) { // region 0
+ // minimum at interior points of ray and segment
+ double invDet = 1.0f/det;
+ s *= invDet;
+ t *= invDet;
+ if (rayint!=null) rayint.scaleAdd (s, raydir, rayorig);
+ if (segint!=null) segint.scaleAdd (t, segdir, segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(s*(A*s+B*t+2*D)+t*(B*s+C*t+2*E)+F);
+ }
+ else { // region 1
+
+ t = 1;
+ if (D >= 0) {
+ s = 0;
+ if (rayint!=null) rayint.set (rayorig);
+ if (segint!=null) segint.set (segend);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(C+2*E+F);
+ }
+ else {
+ s = -D/A;
+ if (rayint!=null) rayint.scaleAdd (s, raydir, rayorig);
+ if (segint!=null) segint.set (segend);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST((D+2*B)*s+C+2*E+F);
+ }
+ }
+ }
+ else { // region 5
+ t = 0;
+ if (D >= 0) {
+ s = 0;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.set (segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else {
+ s = -D/A;
+ if (rayint != null) rayint.scaleAdd (s, raydir, rayorig);
+ if (segint != null) segint.set (segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ }
+ }
+ else {
+ if (t <= 0) { // region 4
+ if (D < 0) {
+ s = -D/A;
+ t = 0;
+ if (rayint != null) rayint.scaleAdd (s, raydir, rayorig);
+ if (segint != null) segint.set (segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ else {
+ s = 0;
+ if (E >= 0) {
+ t = 0;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.set (segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else if (-E >= C) {
+ t = 1;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.set (segend);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(C+2*E+F);
+ }
+ else {
+ t = -E/C;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.scaleAdd (t, segdir, segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(E*t+F);
+ }
+ }
+ }
+ else if (t <= det) { // region 3
+ s = 0;
+ if (E >= 0) {
+ t = 0;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.set (segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else if (-E >= C) {
+ t = 1;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.set (segend);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(C+2*E+F);
+ }
+ else {
+ t = -E/C;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.scaleAdd (t, segdir, segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(E*t+F);
+ }
+ }
+ else { // region 2
+ tmp = B+D;
+ if (tmp < 0) {
+ s = -tmp/A;
+ t = 1;
+ if (rayint != null) rayint.scaleAdd (s, raydir, rayorig);
+ if (segint != null) segint.set (segend);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(tmp*s+C+2*E+F);
+ }
+ else {
+ s = 0;
+ if (E >= 0) {
+ t = 0;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.set (segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else if (-E >= C) {
+ t = 1;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.set (segend);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(C+2*E+F);
+ }
+ else {
+ t = -E/C;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.scaleAdd (t, segdir, segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(E*t+F);
+ }
+ }
+ }
+ }
+ }
+ else {
+ // ray and segment are parallel
+ if (B > 0) {
+ // opposite direction vectors
+ t = 0;
+ if (D >= 0) {
+ s = 0;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.set (segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else {
+ s = -D/A;
+ if (rayint != null) rayint.scaleAdd (s, raydir, rayorig);
+ if (segint != null) segint.set (segstart);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ }
+ else {
+ // same direction vectors
+ E = segdir.dot (diff);//-Dot(seg.m,diff);
+ t = 1;
+ tmp = B+D;
+ if (tmp >= 0) {
+ s = 0;
+ if (rayint != null) rayint.set (rayorig);
+ if (segint != null) segint.set (segend);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(C+2*E+F);
+ }
+ else {
+ s = -tmp/A;
+ if (rayint != null) rayint.scaleAdd (s, raydir, rayorig);
+ if (segint != null) segint.set (segend);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(tmp*s+C+2*E+F);
+ }
+ }
+ }
+ }
+
+ /**
+ * Minimum ray to ray distance. Returns the square of the distance.
+ *
+ * @param ray0orig Origin of ray 0
+ * @param ray0dir Direction of ray 0
+ * @param ray1orig Origin of ray 1
+ * @param ray1dir Direction of ray 1
+ * @return the square of the minimum distance from the ray to the segment
+ */
+ static public double rayToRay (Point3d ray0orig,
+ Vector3d ray0dir,
+ Point3d ray1orig,
+ Vector3d ray1dir) {
+ return rayToRay (ray0orig, ray0dir, ray1orig, ray1dir, null, null, null);
+ }
+
+ /**
+ * Minimum ray to ray distance. Returns the square of the distance.
+ *
+ * @param ray0orig Origin of ray 0
+ *
+ * @param ray0dir Direction of ray 0
+ *
+ * @param ray1orig Origin of ray 1
+ *
+ * @param ray1dir Direction of ray 1
+ *
+ * @param ray0int If non-null, will be filled with the coordinates
+ * of the point corresponding to the minimum distance on ray 0.
+ *
+ * @param ray1int If non-null, will be filled with the coordinates
+ * of the point corresponding to the minimum distance on ray 1.
+ *
+ * @param param An array of two doubles, will be filled with the
+ * parametric factors used to find the point of shortest distance on
+ * each primitive (ray = O +sD, with O=origin and
+ * D=direction). param[0] will contain the parameter for ray0, and
+ * param[1] the parameter for ray1.
+ *
+ * @return the square of the minimum distance from the ray to the segment
+ */
+ static public double rayToRay (Point3d ray0orig,
+ Vector3d ray0dir,
+ Point3d ray1orig,
+ Vector3d ray1dir,
+ Point3d ray0int,
+ Point3d ray1int,
+ double[] param) {
+
+ double s, t;
+
+ Vector3d diff = new Vector3d();
+ diff.sub (ray0orig, ray1orig);
+
+ double A = ray0dir.dot (ray0dir); //Dot(ray0.m,ray0.m);
+ double B = -ray0dir.dot (ray1dir); //-Dot(ray0.m,ray1.m);
+ double C = ray1dir.dot (ray1dir); //Dot(ray1.m,ray1.m);
+ double D = ray0dir.dot (diff); //Dot(ray0.m,diff);
+ double E; // -Dot(ray1.m,diff), defer until needed
+ double F = diff.dot (diff); //Dot(diff,diff);
+ double det = Math.abs(A*C-B*B); // A*C-B*B = |Cross(M0,M1)|^2 >= 0
+ /*
+ System.out.println (ray0orig + "\n" + ray0dir + "\n" +
+ ray1orig + "\n" + ray1dir);
+ System.out.println (A + " " + B + " " + C + " " + D + " " + F + " " + det);
+ */
+ if (det >= FUZZ) {
+ // rays are not parallel
+ E = -ray1dir.dot (diff); //-Dot(ray1.m,diff);
+ s = B*E-C*D;
+ t = B*D-A*E;
+
+ if (s >= 0) {
+ if (t >= 0) { // region 0 (interior)
+ // minimum at two interior points of rays
+ double invDet = 1.0f/det;
+ s *= invDet;
+ t *= invDet;
+ if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig);
+ if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(s*(A*s+B*t+2*D)+t*(B*s+C*t+2*E)+F);
+ }
+ else { // region 3 (side)
+ t = 0;
+ if (D >= 0) {
+ s = 0;
+ if (ray0int != null) ray0int.set (ray0orig);
+ if (ray1int != null) ray1int.set (ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else {
+ s = -D/A;
+ if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig);
+ if (ray1int != null) ray1int.set (ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ }
+ }
+ else {
+ if (t >= 0) { // region 1 (side)
+ s = 0;
+ if (E >= 0) {
+ t = 0;
+ if (ray0int != null) ray0int.set (ray0orig);
+ if (ray1int != null) ray1int.set (ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else {
+ t = -E/C;
+ if (ray0int != null) ray0int.set (ray0orig);
+ if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(E*t+F);
+ }
+ }
+ else { // region 2 (corner)
+ if (D < 0) {
+ s = -D/A;
+ t = 0;
+ if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig);
+ if (ray1int != null) ray1int.set (ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ else {
+ s = 0;
+ if (E >= 0) {
+ t = 0;
+ if (ray0int != null) ray0int.set (ray0orig);
+ if (ray1int != null) ray1int.set (ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else {
+ t = -E/C;
+ if (ray0int != null) ray0int.set (ray0orig);
+ if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(E*t+F);
+ }
+ }
+ }
+ }
+ }
+ else {
+ // rays are parallel
+ if (B > 0) {
+ // opposite direction vectors
+ t = 0;
+ if (D >= 0) {
+ s = 0;
+ if (ray0int != null) ray0int.set (ray0orig);
+ if (ray1int != null) ray1int.set (ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else {
+ s = -D/A;
+ if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig);
+ if (ray1int != null) ray1int.set (ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ }
+ else {
+ // same direction vectors
+ if (D >= 0) {
+ E = ray1dir.dot (diff); //-Dot(ray1.m,diff);
+ s = 0;
+ t = -E/C;
+ if (ray0int != null) ray0int.set (ray0orig);
+ if (ray1int != null) ray1int.scaleAdd (t, ray1dir, ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(E*t+F);
+ }
+ else {
+ s = -D/A;
+ t = 0;
+ if (ray0int != null) ray0int.scaleAdd (s, ray0dir, ray0orig);
+ if (ray1int != null) ray1int.set (ray1orig);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ }
+ }
+ }
+
+ /**
+ * Minimum pt to ray distance. Returns the square of the distance.
+ * @param pt The point
+ * @param rayorig Origin of the ray
+ * @param raydir Direction of the ray
+ * @return the square of the minimum distance between the point and the ray
+ */
+ static public double pointToRay (Point3d pt,
+ Point3d rayorig,
+ Vector3d raydir) {
+ return pointToRay (pt, rayorig, raydir, null, null);
+ }
+
+ /**
+ * Minimum pt to ray distance. Returns the square of the distance.
+ *
+ * @param pt The point
+ *
+ * @param rayorig Origin of the ray
+ *
+ * @param raydir Direction of the ray
+ *
+ * @param rayint If non-null, will be filled with the coordinates of
+ * the point corresponding to the minimum distance on the ray.
+ *
+ * @param param An array of one double, will be filled with the
+ * parametric factors used to find the point of shortest distance on
+ * the ray (ray = O +sD, with O=origin and D=direction). param[0]
+ * will contain the parameter for the ray.
+ *
+ * @return the square of the minimum distance between the point and the ray
+ */
+ static public double pointToRay (Point3d pt,
+ Point3d rayorig,
+ Vector3d raydir,
+ Point3d rayint,
+ double[] param) {
+
+ double t;
+
+ Vector3d diff = new Vector3d();
+ diff.sub (pt, rayorig);
+ t = raydir.dot (diff); //Dot(ray.m,diff);
+
+ if (t <= 0.0) {
+ t = 0.0; // behind start of ray
+ if (rayint != null) rayint.set (rayorig);
+ if (param != null) { param[0] = t; }
+ } else {
+ t /= raydir.dot (raydir); //Dot(ray.m,ray.m);
+ diff.scaleAdd (-t, raydir, diff); // diff = diff - t*ray.m;
+ if (rayint != null) rayint.scaleAdd (t, raydir, rayorig);
+ if (param != null) { param[0] = t; }
+ }
+ return diff.dot(diff);
+ }
+
+ /**
+ * Minimum pt to segment distance. Returns the square of the distance.
+ */
+ static public double pointToSegment (Point3d pt,
+ Point3d segstart,
+ Point3d segend) {
+ return pointToSegment (pt, segstart, segend, null, null);
+ }
+
+ /**
+ * Minimum pt to segment distance. Returns the square of the distance.
+ */
+ static public double pointToSegment (Point3d pt,
+ Point3d segstart,
+ Point3d segend,
+ Point3d segint,
+ double[] param) {
+
+ double t;
+ Vector3d segdir = new Vector3d ();
+ segdir.sub (segend, segstart);
+ Vector3d diff = new Vector3d();
+ diff.sub (pt,segstart);
+ t = segdir.dot (diff); //Dot(seg.m,diff);
+
+ if (t <= 0.0) {
+ t = 0.0f;
+ if (segint != null) segint.set (segstart);
+ if (param != null) { param[0] = t; }
+ }
+ else {
+ double mDotm = segdir.dot (segdir); //Dot(seg.m,seg.m);
+ if (t >= mDotm) {
+ t = 1.0f;
+ diff.sub (segdir);
+ if (segint != null) segint.set (segend);
+ if (param != null) { param[0] = t; }
+ }
+ else {
+ t /= mDotm;
+ diff.scaleAdd (-t, segdir, diff); //diff = diff - t*seg.m;
+ if (segint != null) segint.scaleAdd (t, segdir, segstart);
+ if (param != null) { param[0] = t; }
+ }
+ }
+ return diff.dot(diff); //DIST(diff);
+ }
+
+
+ /**
+ * Minimum segment to segment distance. Returns the square of the distance.
+ * @param seg0start the start of segment 0
+ * @param seg0end the end of segment 0
+ * @param seg1start the start of segment 1
+ * @param seg1end the end of segment 1
+ * @return the square of the minimum distance from segment to segment
+ */
+ static public double segmentToSegment (Point3d seg0start,
+ Point3d seg0end,
+ Point3d seg1start,
+ Point3d seg1end) {
+ return segmentToSegment (seg0start, seg0end, seg1start, seg1end,
+ null, null, null);
+ }
+
+ /**
+ * Minimum segment to segment distance. Returns the square of the distance.
+ *
+ * @param seg0start the start of segment 0
+ *
+ * @param seg0end the end of segment 0
+ *
+ * @param seg1start the start of segment 1
+ *
+ * @param seg1end the end of segment 1
+ *
+ * @param seg0int If non-null, will be filled with the coordinates
+ * of the point corresponding to the minimum distance on segment 0.
+ *
+ * @param seg1int If non-null, will be filled with the coordinates
+ * of the point corresponding to the minimum distance on segment 1.
+ *
+ * @param param An array of two doubles, will be filled with the
+ * parametric factors used to find the point of shortest distance on
+ * each primitive (segment = O +sD, with O=origin and
+ * D=direction). param[0] will contain the parameter for segment 0,
+ * and param[1] the parameter for segment 1.
+ *
+ * @return the square of the minimum distance from segment to segment
+ */
+ static public double segmentToSegment (Point3d seg0start,
+ Point3d seg0end,
+ Point3d seg1start,
+ Point3d seg1end,
+ Point3d seg0int,
+ Point3d seg1int,
+ double[] param) {
+ double s,t;
+
+ Vector3d diff = new Vector3d();
+ diff.sub (seg0start,seg1start);
+
+ Vector3d seg0dir = new Vector3d();
+ seg0dir.sub (seg0end, seg0start);
+ Vector3d seg1dir = new Vector3d();
+ seg1dir.sub (seg1end, seg1start);
+
+ double A = seg0dir.dot (seg0dir); //Dot(seg0dir,seg0dir);
+ double B = -seg0dir.dot (seg1dir); //-Dot(seg0dir,seg1dir);
+ double C = seg1dir.dot (seg1dir); //Dot(seg1dir,seg1dir);
+ double D = seg0dir.dot (diff); //Dot(seg0dir,diff);
+ double E; // -Dot(seg1dir,diff), defer until needed
+ double F = diff.dot (diff); //Dot(diff,diff);
+ double det = Math.abs(A*C-B*B); // A*C-B*B = |Cross(M0,M1)|^2 >= 0
+
+ double tmp;
+
+ if (det >= FUZZ) {
+ // line segments are not parallel
+ E = -seg1dir.dot (diff); //-Dot(seg1dir,diff);
+ s = B*E-C*D;
+ t = B*D-A*E;
+
+ if (s >= 0) {
+ if (s <= det) {
+ if (t >= 0) {
+ if (t <= det) { // region 0 (interior)
+ // minimum at two interior points of 3D lines
+ double invDet = 1.0f/det;
+ s *= invDet;
+ t *= invDet;
+ if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
+ if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(s*(A*s+B*t+2*D)+t*(B*s+C*t+2*E)+F);
+ }
+ else { // region 3 (side)
+ t = 1;
+ tmp = B+D;
+ if (tmp >= 0) {
+ s = 0;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(C+2*E+F);
+ }
+ else if (-tmp >= A) {
+ s = 1;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+C+F+2*(E+tmp));
+ }
+ else {
+ s = -tmp/A;
+ if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(tmp*s+C+2*E+F);
+ }
+ }
+ }
+ else { // region 7 (side)
+ t = 0;
+ if (D >= 0) {
+ s = 0;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else if (-D >= A) {
+ s = 1;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+2*D+F);
+ }
+ else {
+ s = -D/A;
+ if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ }
+ }
+ else {
+ if (t >= 0) {
+ if (t <= det) { // region 1 (side)
+ s = 1;
+ tmp = B+E;
+ if (tmp >= 0) {
+ t = 0;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+2*D+F);
+ }
+ else if (-tmp >= C) {
+ t = 1;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+C+F+2*(D+tmp));
+ }
+ else {
+ t = -tmp/C;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(tmp*t+A+2*D+F);
+ }
+ }
+ else { // region 2 (corner)
+ tmp = B+D;
+ if (-tmp <= A) {
+ t = 1;
+ if (tmp >= 0) {
+ s = 0;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(C+2*E+F);
+ }
+ else {
+ s = -tmp/A;
+ if (seg0int!=null) seg0int.scaleAdd (s, seg0dir, seg0start);
+ if (seg1int!=null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(tmp*s+C+2*E+F);
+ }
+ }
+ else {
+ s = 1;
+ tmp = B+E;
+ if (tmp >= 0) {
+ t = 0;
+ if (seg0int!=null) seg0int.set (seg0end);
+ if (seg1int!=null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+2*D+F);
+ }
+ else if (-tmp >= C) {
+ t = 1;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+C+F+2*(D+tmp));
+ }
+ else {
+ t = -tmp/C;
+ if (seg0int!=null) seg0int.set (seg0end);
+ if (seg1int!=null) seg1int.scaleAdd (t, seg1dir, seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(tmp*t+A+2*D+F);
+ }
+ }
+ }
+ }
+ else { // region 8 (corner)
+ if (-D < A) {
+ t = 0;
+ if (D >= 0) {
+ s = 0;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else {
+ s = -D/A;
+ if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ }
+ else {
+ s = 1;
+ tmp = B+E;
+ if (tmp >= 0) {
+ t = 0;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+2*D+F);
+ }
+ else if (-tmp >= C) {
+ t = 1;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+C+F+2*(D+tmp));
+ }
+ else {
+ t = -tmp/C;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(tmp*t+A+2*D+F);
+ }
+ }
+ }
+ }
+ }
+ else {
+ if (t >= 0) {
+ if (t <= det) { // region 5 (side)
+ s = 0;
+ if (E >= 0) {
+ t = 0;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else if (-E >= C) {
+ t = 1;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(C+2*E+F);
+ }
+ else {
+ t = -E/C;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(E*t+F);
+ }
+ }
+ else { // region 4 (corner)
+ tmp = B+D;
+ if (tmp < 0) {
+ t = 1;
+ if (-tmp >= A) {
+ s = 1;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+C+F+2*(E+tmp));
+ }
+ else {
+ s = -tmp/A;
+ if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(tmp*s+C+2*E+F);
+ }
+ }
+ else {
+ s = 0;
+ if (E >= 0) {
+ t = 0;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else if (-E >= C) {
+ t = 1;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(C+2*E+F);
+ }
+ else {
+ t = -E/C;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(E*t+F);
+ }
+ }
+ }
+ }
+ else { // region 6 (corner)
+ if (D < 0) {
+ t = 0;
+ if (-D >= A) {
+ s = 1;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+2*D+F);
+ }
+ else {
+ s = -D/A;
+ if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ }
+ else {
+ s = 0;
+ if (E >= 0) {
+ t = 0;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else if (-E >= C) {
+ t = 1;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(C+2*E+F);
+ }
+ else {
+ t = -E/C;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(E*t+F);
+ }
+ }
+ }
+ }
+ }
+ else {
+ // line segments are parallel
+ if (B > 0) {
+ // direction vectors form an obtuse angle
+ if (D >= 0) {
+ s = 0;
+ t = 0;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F);
+ }
+ else if (-D <= A) {
+ s = -D/A;
+ t = 0;
+ if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ else {
+ E = -seg1dir.dot (diff); //-Dot(seg1dir,diff);
+ s = 1;
+ tmp = A+D;
+ if (-tmp >= B) {
+ t = 1;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+C+F+2*(B+D+E));
+ }
+ else {
+ t = -tmp/B;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+2*D+F+t*(C*t+2*(B+E)));
+ }
+ }
+ }
+ else {
+ // direction vectors form an acute angle
+ if (-D >= A) {
+ s = 1;
+ t = 0;
+ if (seg0int != null) seg0int.set (seg0end);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(A+2*D+F);
+ }
+ else if (D <= 0) {
+ s = -D/A;
+ t = 0;
+ if (seg0int != null) seg0int.scaleAdd (s, seg0dir, seg0start);
+ if (seg1int != null) seg1int.set (seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(D*s+F);
+ }
+ else {
+ E = -seg1dir.dot (diff); //-Dot(seg1dir,diff);
+ s = 0;
+ if (D >= -B) {
+ t = 1;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.set (seg1end);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(C+2*E+F);
+ }
+ else {
+ t = -D/B;
+ if (seg0int != null) seg0int.set (seg0start);
+ if (seg1int != null) seg1int.scaleAdd (t, seg1dir, seg1start);
+ if (param != null) { param[0] = s; param[1] = t; }
+ return DIST(F+t*(2*E+C*t));
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/internal/DoubleBufferWrapper.java b/src/classes/share/org/jogamp/java3d/internal/DoubleBufferWrapper.java
new file mode 100644
index 0000000..952486e
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/internal/DoubleBufferWrapper.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.internal;
+
+import java.nio.DoubleBuffer;
+
+import org.jogamp.java3d.J3DBuffer;
+
+/**
+ * NIO Buffers are new in Java 1.4 but we need to run on 1.3
+ * as well, so this class was created to hide the NIO classes
+ * from non-1.4 Java 3D users.
+ *
+ * dst.length
+ * doubles from
+ * the buffer to the destination array and increments the
+ * buffer's position by dst.length
.
+ */
+ public DoubleBufferWrapper get(double[] dst) {
+ buffer.get(dst);
+ return this;
+ }
+
+ /**
+ * Bulk get method. Transfers length doubles
+ * from the buffer starting at position offset into
+ * the destination array.
+ */
+ public DoubleBufferWrapper get(double[] dst, int offset, int length){
+ buffer.get(dst, offset, length);
+ return this;
+ }
+
+ /**
+ * Bulk put method. Transfers src.length
+ * doubles into the buffer at the current position.
+ */
+ public DoubleBufferWrapper put(double[] src) {
+ buffer.put(src);
+ return this;
+ }
+
+ /**
+ * Creates and returns a J3DBuffer object containing the
+ * buffer in this DoubleBufferWrapper object.
+ */
+ public J3DBuffer getJ3DBuffer() {
+ return new J3DBuffer( buffer );
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/internal/FastVector.java b/src/classes/share/org/jogamp/java3d/internal/FastVector.java
new file mode 100644
index 0000000..271c2ac
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/internal/FastVector.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.internal;
+
+/**
+ * The FastVector object is a growable array of ints. It's much faster
+ * than the Java Vector class because it isn't synchronized. This class
+ * was created because it is needed in several places by graphics
+ * utilities.
+ */
+public class FastVector {
+
+ private int data[];
+ private int capacity;
+ private int increment;
+ private int size;
+
+ /**
+ * Add an element to the end of the array.
+ */
+ public void addElement(int element)
+ {
+ if (size >= capacity) {
+ capacity += (increment == 0) ? capacity : increment;
+ int newData[] = new int[capacity];
+ System.arraycopy(data, 0, newData, 0, size);
+ data = newData;
+ }
+ data[size++] = element;
+ } // End of addElement
+
+
+
+ /**
+ * Get number of ints currently stored in the array;
+ */
+ public int getSize()
+ {
+ return size;
+ } // End of getSize
+
+
+
+ /**
+ * Get access to array data
+ */
+ public int[] getData()
+ {
+ return data;
+ } // End of getData
+
+
+
+ /**
+ * Constructor.
+ * @param initialCapacity Number of ints the object can hold
+ * without reallocating the array.
+ * @param capacityIncrement Once the array has grown beyond
+ * its capacity, how much larger the reallocated array should be.
+ */
+ public FastVector(int initialCapacity, int capacityIncrement)
+ {
+ data = new int[initialCapacity];
+ capacity = initialCapacity;
+ increment = capacityIncrement;
+ size = 0;
+ } // End of FastVector(int, int)
+
+
+
+ /**
+ * Constructor.
+ * When the array runs out of space, its size is doubled.
+ * @param initialCapacity Number of ints the object can hold
+ * without reallocating the array.
+ */
+ public FastVector(int initialCapacity)
+ {
+ data = new int[initialCapacity];
+ capacity = initialCapacity;
+ increment = 0;
+ size = 0;
+ } // End of FastVector(int)
+
+
+
+ /**
+ * Constructor.
+ * The array is constructed with initial capacity of one integer.
+ * When the array runs out of space, its size is doubled.
+ */
+ public FastVector()
+ {
+ data = new int[1];
+ capacity = 1;
+ increment = 0;
+ size = 0;
+ } // End of FastVector()
+} // End of class FastVector
+
+// End of file FastVector.java
diff --git a/src/classes/share/org/jogamp/java3d/internal/FloatBufferWrapper.java b/src/classes/share/org/jogamp/java3d/internal/FloatBufferWrapper.java
new file mode 100644
index 0000000..8e84c82
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/internal/FloatBufferWrapper.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.internal;
+
+import java.nio.FloatBuffer;
+
+import org.jogamp.java3d.J3DBuffer;
+
+/**
+ * NIO Buffers are new in Java 1.4 but we need to run on 1.3
+ * as well, so this class was created to hide the NIO classes
+ * from non-1.4 Java 3D users.
+ *
+ * dst.length
+ * floats from
+ * the buffer to the destination array and increments the
+ * buffer's position by dst.length
.
+ */
+ public FloatBufferWrapper get(float[] dst) {
+ buffer.get(dst);
+ return this;
+ }
+
+ /**
+ * Bulk get method. Transfers length floats
+ * from the buffer starting at position offset into
+ * the destination array.
+ */
+ public FloatBufferWrapper get(float[] dst, int offset, int length){
+ buffer.get(dst, offset, length);
+ return this;
+ }
+
+ /**
+ * Bulk put method. Transfers src.length
+ * floats into the buffer at the current position.
+ */
+ public FloatBufferWrapper put(float[] src) {
+ buffer.put(src);
+ return this;
+ }
+
+ /**
+ * Creates and returns a J3DBuffer object containing the
+ * buffer in this FloatBufferWrapper object.
+ */
+ public J3DBuffer getJ3DBuffer() {
+ return new J3DBuffer( buffer );
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/internal/HashCodeUtil.java b/src/classes/share/org/jogamp/java3d/internal/HashCodeUtil.java
new file mode 100644
index 0000000..3ad6a8f
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/internal/HashCodeUtil.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.internal;
+
+/**
+ * Utility class used when computing the hash code for
+ * objects containing float or double values. This fixes Issue 36.
+ */
+public class HashCodeUtil {
+ /**
+ * Returns the representation of the specified floating-point
+ * value according to the IEEE 754 floating-point "single format"
+ * bit layout, after first mapping -0.0 to 0.0. This method is
+ * identical to Float.floatToIntBits(float) except that an integer
+ * value of 0 is returned for a floating-point value of
+ * -0.0f. This is done for the purpose of computing a hash code
+ * that satisfies the contract of hashCode() and equals(). The
+ * equals() method in some Java 3D classes does a pair-wise
+ * "==" test on each floating-point field in the class. Since
+ * 0.0f == -0.0f returns true, we must also return the
+ * same hash code for two objects, one of which has a field with a
+ * value of -0.0f and the other of which has a cooresponding field
+ * with a value of 0.0f.
+ *
+ * @param f an input floating-point number
+ * @return the integer bits representing that floating-point
+ * number, after first mapping -0.0f to 0.0f
+ */
+ public static int floatToIntBits(float f) {
+ // Check for +0 or -0
+ if (f == 0.0f) {
+ return 0;
+ }
+ else {
+ return Float.floatToIntBits(f);
+ }
+ }
+
+ /**
+ * Returns the representation of the specified floating-point
+ * value according to the IEEE 754 floating-point "double format"
+ * bit layout, after first mapping -0.0 to 0.0. This method is
+ * identical to Double.doubleToLongBits(double) except that an
+ * integer value of 0L is returned for a floating-point value of
+ * -0.0. This is done for the purpose of computing a hash code
+ * that satisfies the contract of hashCode() and equals(). The
+ * equals() method in some Java 3D classes does a pair-wise
+ * "==" test on each floating-point field in the class. Since
+ * 0.0 == -0.0 returns true, we must also return the
+ * same hash code for two objects, one of which has a field with a
+ * value of -0.0 and the other of which has a cooresponding field
+ * with a value of 0.0.
+ *
+ * @param d an input double precision floating-point number
+ * @return the integer bits representing that floating-point
+ * number, after first mapping -0.0f to 0.0f
+ */
+ public static long doubleToLongBits(double d) {
+ // Check for +0 or -0
+ if (d == 0.0) {
+ return 0L;
+ }
+ else {
+ return Double.doubleToLongBits(d);
+ }
+ }
+
+
+ /**
+ * Do not construct an instance of this class.
+ */
+ private HashCodeUtil() {
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/internal/J3dUtilsI18N.java b/src/classes/share/org/jogamp/java3d/internal/J3dUtilsI18N.java
new file mode 100644
index 0000000..8961ba7
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/internal/J3dUtilsI18N.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.internal;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+
+public class J3dUtilsI18N {
+ static public String getString(String key) {
+ String s;
+ try {
+ s = ResourceBundle.getBundle("org.jogamp.java3d.ExceptionStrings").getString(key);
+ }
+ catch (MissingResourceException e) {
+ System.err.println("J3dUtilsI18N: Error looking up: " + key);
+ s = key;
+ }
+ return s;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/IncorrectFormatException.java b/src/classes/share/org/jogamp/java3d/loaders/IncorrectFormatException.java
new file mode 100644
index 0000000..35a0231
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/IncorrectFormatException.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders;
+
+
+/**
+ * Exception used to indicate that a file of the incorrect
+ * type was passed to a loader.
+ */
+public class IncorrectFormatException extends RuntimeException {
+
+ public IncorrectFormatException() {
+ super();
+ }
+
+ public IncorrectFormatException(String s) {
+ super(s);
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/loaders/Loader.java b/src/classes/share/org/jogamp/java3d/loaders/Loader.java
new file mode 100644
index 0000000..83c876a
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/Loader.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders;
+
+import java.io.FileNotFoundException;
+import java.io.Reader;
+import java.net.URL;
+
+/**
+ * The Loader interface is used to specify the location
+ * and elements of a file format to load.
+ * The interface is used to give loaders of various
+ * file formats a common public interface. Ideally
+ * the Scene interface will be implemented to give
+ * the user a consistent interface to extract the
+ * data.
+ *
+ * @see org.jogamp.java3d.loaders.Scene
+ */
+public interface Loader {
+
+ // These are the values to be used in constructing the
+ // load flags for the loader. Users should OR the selected
+ // values together to construct an aggregate flag integer
+ // (see the setFlags() method). Users wishing to load all
+ // data in a file should use the LOAD_ALL specifier.
+
+ /** This flag enables the loading of light objects into the scene.*/
+ public static final int LOAD_LIGHT_NODES = 1;
+
+ /** This flag enables the loading of fog objects into the scene.*/
+ public static final int LOAD_FOG_NODES = 2;
+
+ /** This flag enables the loading of background objects into the scene.*/
+ public static final int LOAD_BACKGROUND_NODES = 4;
+
+ /** This flag enables the loading of behaviors into the scene.*/
+ public static final int LOAD_BEHAVIOR_NODES = 8;
+
+ /** This flag enables the loading of view (camera) objects into
+ * the scene.*/
+ public static final int LOAD_VIEW_GROUPS = 16;
+
+ /** This flag enables the loading of sound objects into the scene.*/
+ public static final int LOAD_SOUND_NODES = 32;
+
+ /** This flag enables the loading of all objects into the scene.*/
+ public static final int LOAD_ALL = 0xffffffff;
+
+
+ // Loading methods
+
+ /**
+ * This method loads the named file and returns the Scene
+ * containing the scene. Any data files referenced by this
+ * file should be located in the same place as the named file;
+ * otherwise users should specify an alternate base path with
+ * the setBasePath(String) method.
+ */
+ public Scene load(String fileName) throws FileNotFoundException,
+ IncorrectFormatException, ParsingErrorException;
+
+ /**
+ * This method loads the named file and returns the Scene
+ * containing the scene. Any data files referenced by the Reader
+ * should be located in the same place as the named file; otherwise,
+ * users should specify an alternate base path with the setBaseUrl(URL)
+ * method.
+ */
+ public Scene load(URL url) throws FileNotFoundException,
+ IncorrectFormatException, ParsingErrorException;
+
+ /**
+ * This method loads the Reader and returns the Scene
+ * containing the scene. Any data files referenced by the Reader should
+ * be located in the user's current working directory.
+ */
+ public Scene load(Reader reader)
+ throws FileNotFoundException, IncorrectFormatException,
+ ParsingErrorException;
+
+
+ // Variable get/set methods
+
+ /**
+ * This method sets the base URL name for data files associated with
+ * the file passed into the load(URL) method.
+ * The basePath should be null by default, which is an indicator
+ * to the loader that it should look for any associated files starting
+ * from the same directory as the file passed into the load(URL) method.
+ */
+ public void setBaseUrl(URL url);
+
+ /**
+ * This method sets the base path name for data files associated with
+ * the file passed into the load(String) method.
+ * The basePath should be null by default, which is an indicator
+ * to the loader that it should look for any associated files starting
+ * from the same directory as the file passed into the load(String)
+ * method.
+ */
+ public void setBasePath(String pathName);
+
+ /**
+ * Returns the current base URL setting. By default this is null,
+ * implying the loader should look for associated files starting
+ * from the same directory as the file passed into the load(URL) method.
+ */
+ public URL getBaseUrl();
+
+ /**
+ * Returns the current base path setting. By default this is null,
+ * implying the loader should look for associated files starting
+ * from the same directory as the file passed into the load(String)
+ * method.
+ */
+ public String getBasePath();
+
+ /**
+ * This method sets the load flags for the file. The flags should
+ * equal 0 by default (which tells the loader to only load geometry).
+ * To enable the loading of any particular scene elements, pass
+ * in a logical OR of the LOAD values specified above.
+ */
+ public void setFlags(int flags);
+
+ /**
+ * Returns the current loading flags setting.
+ */
+ public int getFlags();
+}
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/loaders/LoaderBase.java b/src/classes/share/org/jogamp/java3d/loaders/LoaderBase.java
new file mode 100644
index 0000000..ad679a8
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/LoaderBase.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders;
+
+import java.net.URL;
+
+/**
+ * This class implements the Loader interface. To use
+ * a file loader would extend this class.
+ */
+public abstract class LoaderBase implements Loader {
+
+ /** Stores the types of objects that the user wishes to load.*/
+ protected int loadFlags = 0;
+
+ /** Stores the baseUrl for data files associated with the URL
+ * passed into load(URL).*/
+ protected URL baseUrl = null;
+
+ /** Stores the basePath for data files associated with the file
+ * passed into load(String).*/
+ protected String basePath = null;
+
+ // Constructors
+
+ /**
+ * Constructs a Loader with default values for all variables.
+ */
+ public LoaderBase() {
+ }
+
+ /**
+ * Constructs a Loader with the specified flags word.
+ */
+ public LoaderBase(int flags) {
+ loadFlags = flags;
+ }
+
+
+ // Variable get/set methods
+
+ /**
+ * This method sets the base URL name for data files associated with
+ * the file. The baseUrl should be null by default, which is an indicator
+ * to the loader that it should look for any associated files starting
+ * from the same place as the URL passed into the load(URL) method.
+ * Note: Users of setBaseUrl() would then use load(URL)
+ * as opposed to load(String).
+ */
+ @Override
+ public void setBaseUrl(URL url) {
+ baseUrl = url;
+ }
+
+ /**
+ * This method sets the base path name for data files associated with
+ * the file. The basePath should be null by default, which is an indicator
+ * to the loader that it should look for any associated files starting
+ * from the same directory as the file passed into the load(String)
+ * method.
+ * Note: Users of setBasePath() would then use load(String)
+ * as opposed to load(URL).
+ */
+ @Override
+ public void setBasePath(String pathName) {
+ basePath = pathName;
+ }
+
+ /**
+ * Returns the current base URL setting.
+ */
+ @Override
+ public URL getBaseUrl() {
+ return baseUrl;
+ }
+
+ /**
+ * Returns the current base path setting.
+ */
+ @Override
+ public String getBasePath() {
+ return basePath;
+ }
+
+ /**
+ * This method sets the load flags for the file. The flags should
+ * equal 0 by default (which tells the loader to only load geometry).
+ */
+ @Override
+ public void setFlags(int flags) {
+ loadFlags = flags;
+ }
+
+ /**
+ * Returns the current loading flags setting.
+ */
+ @Override
+ public int getFlags() {
+ return loadFlags;
+ }
+
+}
+
+
+
+
+
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/loaders/ParsingErrorException.java b/src/classes/share/org/jogamp/java3d/loaders/ParsingErrorException.java
new file mode 100644
index 0000000..05166f7
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/ParsingErrorException.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders;
+
+
+/**
+ * Exception used to indicate that the loader encountered
+ * a problem parsing the specified file.
+ */
+public class ParsingErrorException extends RuntimeException {
+
+ public ParsingErrorException() {
+ super();
+ }
+
+ public ParsingErrorException(String s) {
+ super(s);
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/loaders/Scene.java b/src/classes/share/org/jogamp/java3d/loaders/Scene.java
new file mode 100644
index 0000000..e9630be
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/Scene.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders;
+
+import java.util.Hashtable;
+
+import org.jogamp.java3d.Background;
+import org.jogamp.java3d.Behavior;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Fog;
+import org.jogamp.java3d.Light;
+import org.jogamp.java3d.Sound;
+import org.jogamp.java3d.TransformGroup;
+
+
+/**
+ * The Scene interface is a set of methods used to extract
+ * Java 3D scene graph information from a file loader utility.
+ * The interface is used to give loaders of various
+ * file formats a common public interface.
+ */
+public interface Scene {
+
+
+ /**
+ * This method returns the BranchGroup containing the overall
+ * scene loaded by the loader. All enabled items will be loaded
+ * into this scene except for Behaviors (the Behavior group must be
+ * retrieved separately so that users can choose whether and when
+ * to activate behaviors).
+ */
+ public BranchGroup getSceneGroup();
+
+ /**
+ * This method returns an array of all View Groups defined in the file.
+ * Each View Group is a TransformGroup that is already placed within
+ * the scene that is returned in the getSceneGroup() call. This
+ * TransformGroup holds the position/orientation of the view
+ * as defined by the file. A user might request these references to
+ * the groups in order to look at the data stored there or
+ * to place ViewPlatforms within these groups and allow the
+ * View to activate these ViewPlatforms so that the user would
+ * see the scene from the viewpoints defined in the file.
+ */
+ public TransformGroup[] getViewGroups();
+
+ /**
+ * This method returns an array of floats with the horizontal field
+ * of view. The entries in the array will correspond to those in the
+ * array returned by the method getViewGroups. The entries from these
+ * two arrays together provide all the information needed to recreate
+ * the viewing parameters associated with a scene graph.
+ */
+ public float[] getHorizontalFOVs();
+
+ /**
+ * This method returns an array of all Lights defined in the file.
+ * If no lights are defined, null is returned.
+ */
+ public Light[] getLightNodes();
+
+ /**
+ * This method returns a Hashtable which contains a list of all named
+ * objects in the file and their associated scene graph objects. The
+ * naming scheme for file objects is file-type dependent, but may include
+ * such names as the DEF names of Vrml or filenames of objects (as
+ * in Lightwave 3D). If no named objects are defined, null is returned.
+ */
+ public Hashtable getNamedObjects();
+
+ /**
+ * This method returns an array of all Background nodes defined in the
+ * file. IF no Background nodes are defined, null is returned.
+ */
+ public Background[] getBackgroundNodes();
+
+ /**
+ * This method returns an array of all Fog nodes defined in the
+ * file. If no fog nodes are defined, null is returned.
+ */
+ public Fog[] getFogNodes();
+
+ /**
+ * This method returns an array of all the behavior nodes
+ * in the scene. If no Behavior nodes are defined, null is returned.
+ */
+ public Behavior[] getBehaviorNodes();
+
+ /**
+ * This method returns an array of all of the Sound nodes defined
+ * in the file. If no Sound nodes are defined, null is returned.
+ */
+ public Sound[] getSoundNodes();
+
+ /**
+ * This method returns the text description of the file. If no
+ * such description exists, this method should return null.
+ */
+ public String getDescription();
+
+}
+
+
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/loaders/SceneBase.java b/src/classes/share/org/jogamp/java3d/loaders/SceneBase.java
new file mode 100644
index 0000000..8233e0a
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/SceneBase.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders;
+
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.jogamp.java3d.Background;
+import org.jogamp.java3d.Behavior;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Fog;
+import org.jogamp.java3d.Light;
+import org.jogamp.java3d.Sound;
+import org.jogamp.java3d.TransformGroup;
+
+
+/**
+ * This class implements the Scene interface and extends it to incorporate
+ * utilities that could be used by loaders. There should be little need
+ * for future loaders to subclass this, or to implement Scene directly,
+ * as the functionality of a SceneBase is fairly straightforward. This
+ * class is responsible for both the storage and retrieval of data from
+ * the Scene. The storage methods (used only by Loader writers) are all
+ * of the add* routines. The retrieval methods (used primarily by Loader
+ * users) are all of the get* routines.
+ */
+public class SceneBase implements Scene {
+
+ BranchGroup sceneGroup = null;
+ BranchGroup behaviorGroup = null;
+ Hashtable namedObjects = new Hashtable();
+ String description = null;
+
+ Vector viewVector = new Vector();
+ Vector hfovVector = new Vector();
+ Vector behaviorVector = new Vector();
+ Vector lightVector = new Vector();
+ Vector fogVector = new Vector();
+ Vector backgroundVector = new Vector();
+ Vector soundVector = new Vector();
+
+ // Add methods
+
+ /**
+ * Sets the sceneGroup to be the group that is passed in.
+ */
+ public void setSceneGroup(BranchGroup scene) {
+ sceneGroup = scene;
+ }
+
+ /**
+ * Adds the given group to the list of view groups.
+ */
+ public void addViewGroup(TransformGroup tg) {
+ viewVector.addElement(tg);
+ }
+
+ /**
+ * Adds the given field of view value to the list of field of view values.
+ */
+ public void addHorizontalFOV(float hfov) {
+ hfovVector.addElement(new Float(hfov));
+ }
+
+ /**
+ * Adds the given behavior to a list of behaviors
+ */
+ public void addBehaviorNode(Behavior b) {
+ behaviorVector.addElement(b);
+ }
+
+ /**
+ * Adds the given Light node to the list of lights.
+ */
+ public void addLightNode(Light light) {
+ lightVector.addElement(light);
+ }
+
+ /**
+ * Adds the given Background node to the list of backgrounds.
+ */
+ public void addBackgroundNode(Background background) {
+ backgroundVector.addElement(background);
+ }
+
+ /**
+ * Adds the given Sound node to the list of sounds.
+ */
+ public void addSoundNode(Sound sound) {
+ soundVector.addElement(sound);
+ }
+
+ /**
+ * Adds the given Fog node to the list of fog nodes.
+ */
+ public void addFogNode(Fog fog) {
+ fogVector.addElement(fog);
+ }
+
+ /**
+ * Sets the text description of the scene to the passed in String.
+ */
+ public void addDescription(String descriptionString) {
+ description = descriptionString;
+ }
+
+ /**
+ * Adds the given String/Object pair to the table of named objects.
+ */
+ public void addNamedObject(String name, Object object) {
+ if (namedObjects.get(name) == null)
+ namedObjects.put(name, object);
+ else {
+ // key already exists - append a unique integer to end of name
+ int nameIndex = 1;
+ boolean done = false;
+ while (!done) {
+ // Iterate starting from "[1]" until we find a unique key
+ String tempName = name + "[" + nameIndex + "]";
+ if (namedObjects.get(tempName) == null) {
+ namedObjects.put(tempName, object);
+ done = true;
+ }
+ nameIndex++;
+ }
+ }
+ }
+
+ /**
+ * This method returns the BranchGroup containing the overall
+ * scene loaded by the loader.
+ */
+ @Override
+ public BranchGroup getSceneGroup() {
+ return sceneGroup;
+ }
+
+
+ /**
+ * This method returns an array of all View Groups defined in the file.
+ * A View Group is defined as a TransformGroup which contains a
+ * ViewPlatform. The TransformGroup holds the position/orientation
+ * information for the given ViewPlatform and the ViewPlatform
+ * holds an view-specific information, such as Field of View.
+ */
+ @Override
+ public TransformGroup[] getViewGroups() {
+ if (viewVector.isEmpty())
+ return null;
+ TransformGroup[] viewGroups = new TransformGroup[viewVector.size()];
+ viewVector.copyInto(viewGroups);
+ return viewGroups;
+ }
+
+ /**
+ * This method returns an array of floats that contains the horizontal
+ * field of view values for each corresponding entry in the array of
+ * view groups returned by the method getViewGroups.
+ */
+ @Override
+ public float[] getHorizontalFOVs() {
+ if (hfovVector.isEmpty())
+ return null;
+
+ int arraySize = hfovVector.size();
+ float[] hfovs = new float[arraySize];
+ Float[] tmpFovs = new Float[hfovVector.size()];
+ hfovVector.copyInto(tmpFovs);
+
+ // copy to array of floats and delete Floats
+ for (int i=0; i
+ * Rather than describe in detail how the file is parsed for each method,
+ * I advise the user of this code to understand the lw3d file format
+ * specs, which are pretty clear.
+ */
+
+class LwoParser extends ParserObject {
+
+ LWOBFileReader theReader;
+ int currLength;
+ float coordsArray[];
+ float normalCoordsArray[];
+ int facetIndicesArray[];
+ int facetSizesArray[];
+ int normalIndicesArray[];
+ int red = 255, green = 255, blue = 255;
+ float diffuse = 0.0f, specular = 0.0f, transparency = 0.0f, luminosity = 0.0f;
+ int gloss = 128;
+ Vector surfNameList = null;
+ Vector surfaceList = new Vector(200);
+ Vector shapeList = new Vector(200);
+
+ /**
+ * Constructor: Creates file reader and calls parseFile() to actually
+ * read the file and grab the data
+ */
+ LwoParser(String fileName, int debugVals)
+ throws FileNotFoundException {
+
+ super(debugVals);
+ debugOutputLn(TRACE, "parser()");
+ long start = System.currentTimeMillis();
+ theReader = new LWOBFileReader(fileName);
+ debugOutputLn(TIME, " file opened in " +
+ (System.currentTimeMillis() - start));
+ parseFile();
+ }
+
+ LwoParser(URL url, int debugVals)
+ throws FileNotFoundException {
+ super(debugVals);
+ debugOutputLn(TRACE, "parser()");
+ try {
+ long start = System.currentTimeMillis();
+ theReader = new LWOBFileReader(url);
+ debugOutputLn(TIME, " file opened in " +
+ (System.currentTimeMillis() - start));
+ }
+ catch (IOException ex) {
+ throw new FileNotFoundException(url.toString());
+ }
+ parseFile();
+ }
+
+
+ /**
+ * Detail polygons are currently not implemented by this loader. Their
+ * structure in geometry files is a bit complex, so there's this separate
+ * method for simply parsing through and ignoring the data for detail
+ * polygons
+ */
+ int skipDetailPolygons(int numPolys) throws ParsingErrorException {
+ debugOutputLn(TRACE, "skipDetailPolygons(), numPolys = " + numPolys);
+ int lengthRead = 0;
+ int vert;
+
+ try {
+ for (int polyNum = 0; polyNum < numPolys; ++polyNum) {
+ debugOutputLn(VALUES, "polyNum = " + polyNum);
+ int numVerts = theReader.getShortInt();
+ theReader.skip(numVerts * 2 + 2); // skip indices plus surf
+ lengthRead += (numVerts * 2) + 4; // increment counter
+ }
+ }
+ catch (IOException e) {
+ debugOutputLn(EXCEPTION, "Exception in reading detail polys: " + e);
+ throw new ParsingErrorException(e.getMessage());
+ }
+ return lengthRead;
+ }
+
+ /**
+ * Returns already-existing ShapeHolder if one exists with the same
+ * surface and the same geometry type (point, line, or poly)
+ */
+ ShapeHolder getAppropriateShape(int numSurf, int numVerts) {
+ for (Enumeration e = shapeList.elements();
+ e.hasMoreElements() ;) {
+ ShapeHolder shape = (ShapeHolder)e.nextElement();
+ if (shape.numSurf == numSurf)
+ if (shape.numVerts == numVerts ||
+ (shape.numVerts > 3 &&
+ numVerts > 3))
+ return shape;
+ }
+ return null;
+ }
+
+
+ /**
+ * Parse the file for all the data for a POLS object (polygon
+ * description)
+ */
+ void getPols(int length) {
+ debugOutputLn(TRACE, "getPols(len), len = " + length);
+ int vert;
+ int lengthRead = 0;
+ int prevNumVerts = -1;
+ int prevNumSurf = 0;
+ Vector facetSizesList;
+ int facetIndicesArray[];
+ facetSizesList =
+ new Vector(length/6); // worst case size (every poly one vert)
+ // Note that our array sizes are hardcoded because we don't
+ // know until we're done how large they will be
+ facetIndicesArray = new int[length/2];
+ ShapeHolder shape = new ShapeHolder(debugPrinter.getValidOutput());
+ debugOutputLn(VALUES, "new shape = " + shape);
+ shape.coordsArray = coordsArray;
+ shape.facetSizesList = facetSizesList;
+ //shape.facetIndicesList = facetIndicesList;
+ shape.facetIndicesArray = facetIndicesArray;
+ shapeList.addElement(shape);
+
+ //long startTime = (new Date()).getTime();
+ boolean firstTime = true;
+ while (lengthRead < length) {
+ int numVerts = theReader.getShortInt();
+ lengthRead += 2;
+ int intArray[] = new int[numVerts];
+ for (int i = 0; i < numVerts; ++i) {
+ intArray[i] = theReader.getShortInt();
+ lengthRead += 2;
+ }
+
+ int numSurf = theReader.getShortInt();
+ lengthRead += 2;
+ long startTimeBuff = 0, startTimeList = 0;
+ if (!firstTime &&
+ (numSurf != prevNumSurf ||
+ ((numVerts != prevNumVerts) &&
+ ((prevNumVerts < 3) ||
+ (numVerts < 3))))) {
+ // If above true, then start new shape
+ shape = getAppropriateShape(numSurf, numVerts);
+ if (shape == null) {
+ //debugOutputLn(LINE_TRACE, "Starting new shape");
+ facetSizesList = new Vector(length/6);
+ facetIndicesArray = new int[length/2];
+ shape = new ShapeHolder(debugPrinter.getValidOutput());
+ shape.coordsArray = coordsArray;
+ shape.facetSizesList = facetSizesList;
+ //shape.facetIndicesList = facetIndicesList;
+ shape.facetIndicesArray = facetIndicesArray;
+ shape.numSurf = numSurf;
+ shape.numVerts = numVerts;
+ shapeList.addElement(shape);
+ }
+ else {
+ facetSizesList = shape.facetSizesList;
+ facetIndicesArray = shape.facetIndicesArray;
+ }
+ }
+ else {
+ shape.numSurf = numSurf;
+ shape.numVerts = numVerts;
+ }
+ prevNumVerts = numVerts;
+ prevNumSurf = numSurf;
+ facetSizesList.addElement(new Integer(numVerts));
+
+ int currPtr = 0;
+ System.arraycopy(intArray, 0,
+ facetIndicesArray, shape.currentNumIndices,
+ numVerts);
+ shape.currentNumIndices += numVerts;
+ if (numSurf < 0) { // neg number means detail poly
+ int numPolys = theReader.getShortInt();
+ lengthRead += skipDetailPolygons(numPolys);
+ shape.numSurf = ~shape.numSurf & 0xffff;
+ if (shape.numSurf == 0)
+ shape.numSurf = 1; // Can't have surface = 0
+ }
+ firstTime = false;
+ }
+ }
+
+ /**
+ * Parses file to get the names of all surfaces. Each polygon will
+ * be associated with a particular surface number, which is the index
+ * number of these names
+ */
+ void getSrfs(int length) {
+ String surfName = new String();
+ surfNameList = new Vector(length/2); // worst case size (each name 2 chars long)
+ int lengthRead = 0;
+ int stopMarker = theReader.getMarker() + length;
+
+ int surfIndex = 0;
+ while (theReader.getMarker() < stopMarker) {
+ debugOutputLn(VALUES, "marker, stop = " +
+ theReader.getMarker() + ", " + stopMarker);
+ debugOutputLn(LINE_TRACE, "About to call getString");
+ surfName = theReader.getString();
+ debugOutputLn(VALUES, "Surfname = " + surfName);
+ surfNameList.addElement(surfName);
+ }
+ }
+
+ /**
+ * Parses file to get all vertices
+ */
+ void getPnts(int length) throws ParsingErrorException {
+ int numVerts = length / 12;
+ float x, y, z;
+
+ coordsArray = new float[numVerts*3];
+ theReader.getVerts(coordsArray, numVerts);
+ }
+
+ /**
+ * Creates new LwoSurface object that parses file and gets all
+ * surface parameters for a particular surface
+ */
+ void getSurf(int length) throws FileNotFoundException {
+ debugOutputLn(TRACE, "getSurf()");
+
+ // Create LwoSurface object to read and hold each surface, then
+ // store that surface in a vector of all surfaces.
+
+ LwoSurface surf = new LwoSurface(theReader, length,
+ debugPrinter.getValidOutput());
+ surfaceList.addElement(surf);
+ }
+
+
+ /**
+ * parses entire file.
+ * return -1 on error or 0 on completion
+ */
+ int parseFile() throws FileNotFoundException, IncorrectFormatException {
+ debugOutputLn(TRACE, "parseFile()");
+ int length = 0;
+ int lengthRead = 0;
+ int fileLength = 100000;
+
+ long loopStartTime = System.currentTimeMillis();
+ // Every parsing unit begins with a four character string
+ String tokenString = theReader.getToken();
+
+ while (!(tokenString == null) &&
+ lengthRead < fileLength) {
+ long startTime = System.currentTimeMillis();
+ // Based on value of tokenString, go to correct parsing method
+ length = theReader.getInt();
+
+ lengthRead += 4;
+ //debugOutputLn(VALUES, "length, lengthRead, fileLength = " +
+ // length + ", " + lengthRead + ", " + fileLength);
+ //debugOutputLn(VALUES, "LWOB marker is at: " + theReader.getMarker());
+
+ if (tokenString.equals("FORM")) {
+ //debugOutputLn(LINE_TRACE, "got a form");
+ fileLength = length + 4;
+ length = 0;
+ tokenString = theReader.getToken();
+ lengthRead += 4;
+ if (!tokenString.equals("LWOB"))
+ throw new IncorrectFormatException(
+ "File not of FORM-length-LWOB format");
+ }
+ else if (tokenString.equals("PNTS")) {
+ //debugOutputLn(LINE_TRACE, "PNTS");
+ getPnts(length);
+ debugOutputLn(TIME, "done with " + tokenString + " in " +
+ (System.currentTimeMillis() - startTime));
+ }
+ else if (tokenString.equals("POLS")) {
+ //debugOutputLn(LINE_TRACE, "POLS");
+ getPols(length);
+ debugOutputLn(TIME, "done with " + tokenString + " in " +
+ (System.currentTimeMillis() - startTime));
+ }
+ else if (tokenString.equals("SRFS")) {
+ //debugOutputLn(LINE_TRACE, "SRFS");
+ getSrfs(length);
+ debugOutputLn(TIME, "done with " + tokenString + " in " +
+ (System.currentTimeMillis() - startTime));
+ }
+ else if (tokenString.equals("CRVS")) {
+ //debugOutputLn(LINE_TRACE, "CRVS");
+ theReader.skipLength(length);
+ //debugOutputLn(TIME, "done with " + tokenString + " in " +
+ // (System.currentTimeMillis() - startTime));
+ }
+ else if (tokenString.equals("PCHS")) {
+ //debugOutputLn(LINE_TRACE, "PCHS");
+ theReader.skipLength(length);
+ //debugOutputLn(TIME, "done with " + tokenString + " in " +
+ // (System.currentTimeMillis() - startTime));
+ }
+ else if (tokenString.equals("SURF")) {
+ //debugOutputLn(LINE_TRACE, "SURF");
+ getSurf(length);
+ //debugOutputLn(VALUES, "Done with SURF, marker = " + theReader.getMarker());
+ debugOutputLn(TIME, "done with " + tokenString + " in " +
+ (System.currentTimeMillis() - startTime));
+ }
+ else if (tokenString.equals("LWOB")) {
+ //debugOutputLn(LINE_TRACE, "LWOB");
+ }
+ else {
+ //debugOutputLn(LINE_TRACE, "Unknown object = " + tokenString);
+ theReader.skipLength(length);
+ //debugOutputLn(TIME, "done with " + tokenString + " in " +
+ // (System.currentTimeMillis() - startTime));
+ }
+ lengthRead += length;
+ if (lengthRead < fileLength) {
+ //debugOutputLn(VALUES, "end of parseFile, length, lengthRead = " +
+ // length + ", " + lengthRead);
+ tokenString = theReader.getToken();
+ lengthRead += 4;
+ //debugOutputLn(VALUES, "just got tokenString = " + tokenString);
+ }
+ }
+ debugOutputLn(TIME, "done with parseFile in " +
+ (System.currentTimeMillis() - loopStartTime));
+ return 0;
+ }
+
+ /**
+ * This method is used only for testing
+ */
+ static void main(String[] args) {
+ String fileName;
+ if (args.length == 0)
+ fileName = "cube.obj";
+ else
+ fileName = args[0];
+
+ try {
+ LwoParser theParser = new LwoParser(fileName, 0);
+ }
+ catch (FileNotFoundException e) {
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+}
+
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwoSurface.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwoSurface.java
new file mode 100644
index 0000000..24528f2
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwoSurface.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+import java.awt.Image;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Vector;
+
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Vector3f;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+import org.jogamp.java3d.loaders.IncorrectFormatException;
+import org.jogamp.java3d.loaders.ParsingErrorException;
+
+
+/**
+ * This class is responsible for retrieving the surface parameters for a
+ * particular surface from a binary Object file and turning that data
+ * into Java3D data. These surface parameters include
+ * diffuse/specular/emissive properties, color, shininess, transparency,
+ * and textures. For textures, this class instantiates a LwoTexture object
+ * to parse that data and turn it into Java3D texture data.
+ */
+
+class LwoSurface extends ParserObject {
+
+ LWOBFileReader theReader;
+ int red = 255, green = 255, blue = 255;
+ float diffuse = 0.0f, specular = 0.0f, transparency = 0.0f, luminosity = 0.0f;
+ float creaseAngle = 0.0f;
+ int gloss = 128;
+ Color3f color, diffuseColor, specularColor, emissiveColor;
+ float shininess;
+ Image theImage = null;
+ Vector3f textureCenter = null, textureSize = null;
+ int textureAxis;
+ String surfName;
+ Vector textureList = new Vector();
+
+ /**
+ * Constructor that parses surface data from the binary file
+ * and creates the necessary Java3d objects
+ */
+ LwoSurface(LWOBFileReader reader, int length, int debugVals)
+ throws FileNotFoundException {
+
+ super(debugVals);
+ debugOutputLn(TRACE, "LwoSurface()");
+ theReader = reader;
+ getSurf(length);
+ setJ3dColors();
+ }
+
+ /**
+ * Creates Java3d color objects from the lw3d surface data
+ */
+ void setJ3dColors() {
+ color = new Color3f((float)red/(float)255,
+ (float)green/(float)255,
+ (float)blue/(float)255);
+ diffuseColor = new Color3f(diffuse*color.x,
+ diffuse*color.y,
+ diffuse*color.z);
+ specularColor = new Color3f(specular*color.x,
+ specular*color.y,
+ specular*color.z);
+ emissiveColor = new Color3f(luminosity*color.x,
+ luminosity*color.y,
+ luminosity*color.z);
+ shininess = (float)(128.0 * ((float)gloss/1024.0));
+ }
+
+ Color3f getColor() {
+ return color;
+ }
+
+ Color3f getDiffuseColor() {
+ return diffuseColor;
+ }
+
+ Color3f getSpecularColor() {
+ return specularColor;
+ }
+
+ Color3f getEmissiveColor() {
+ return emissiveColor;
+ }
+
+ float getShininess() {
+ return shininess;
+ }
+
+ float getCreaseAngle() {
+ return creaseAngle;
+ }
+
+ /**
+ * Returns the LwoTexture for the surface, if any is defined. Note that
+ * lw3d allows users to define multiple textures for any surface, which
+ * is not possible through Java3d. Therefore, we just grab the first
+ * texture in any list of textures for a surface
+ */
+ LwoTexture getTexture() {
+ debugOutputLn(TRACE, "getTexture()");
+ try {
+ if (textureList.isEmpty()) {
+ return null;
+ }
+ else {
+ return (LwoTexture)textureList.elementAt(0);
+ }
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ debugOutputLn(EXCEPTION,
+ "getTexture(), exception returning first element: " + e);
+ return null;
+ }
+ }
+
+ String getSurfName() {
+ return surfName;
+ }
+
+ float getTransparency() {
+ return transparency;
+ }
+
+ /**
+ * Parses the binary file and gets all data for this surface
+ */
+ void getSurf(int length)
+ throws FileNotFoundException, IncorrectFormatException,
+ ParsingErrorException {
+
+ debugOutputLn(TRACE, "getSurf()");
+
+ // These "got*" booleans are to help use read the best version of
+ // the data - the float values for these parameters should take
+ // precedence over the other format
+ boolean gotLuminosityFloat = false;
+ boolean gotTransparencyFloat = false;
+ boolean gotDiffuseFloat = false;
+ boolean gotSpecularFloat = false;
+ int surfStopMarker = theReader.getMarker() + length;
+ surfName = theReader.getString();
+ String tokenString = theReader.getToken();
+ while (!(tokenString == null) &&
+ theReader.getMarker() < surfStopMarker) {
+ debugOutputLn(VALUES, " tokenString = " + tokenString);
+ debugOutputLn(VALUES, " marker, stop = " +
+ theReader.getMarker() + ", " + surfStopMarker);
+ String textureToken = null;
+ int fieldLength = theReader.getShortInt();
+ debugOutputLn(VALUES, " fl = " + fieldLength);
+
+ if (tokenString.equals("COLR")) {
+ debugOutputLn(LINE_TRACE, " COLR");
+ try {
+ red = theReader.read();
+ green = theReader.read();
+ blue = theReader.read();
+ theReader.read();
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ if (fieldLength != 4)
+ throw new IncorrectFormatException(
+ J3dUtilsI18N.getString("LwoSurface0"));
+ }
+ else if (tokenString.equals("FLAG")) {
+ debugOutputLn(LINE_TRACE, " FLAG");
+ theReader.skipLength(fieldLength);
+ }
+ else if (tokenString.equals("VLUM")) {
+ debugOutputLn(LINE_TRACE, " VLUM");
+ luminosity = theReader.getFloat();
+ gotLuminosityFloat = true;
+ }
+ else if (tokenString.equals("LUMI")) {
+ debugOutputLn(LINE_TRACE, " LUMI");
+ if (gotLuminosityFloat)
+ theReader.skipLength(fieldLength);
+ else
+ luminosity = (float)(theReader.getShortInt())/255;
+ }
+ else if (tokenString.equals("VDIF")) {
+ debugOutputLn(LINE_TRACE, " VDIF");
+ if (fieldLength != 4)
+ throw new IncorrectFormatException("VDIF problem");
+ diffuse = theReader.getFloat();
+ gotDiffuseFloat = true;
+ debugOutputLn(VALUES, "diff = " + diffuse);
+ }
+ else if (tokenString.equals("DIFF")) {
+ debugOutputLn(LINE_TRACE, " DIFF");
+ if (gotDiffuseFloat)
+ theReader.skipLength(fieldLength);
+ else
+ diffuse = (float)theReader.getShortInt()/255;
+ }
+ else if (tokenString.equals("VTRN")) {
+ debugOutputLn(LINE_TRACE, " VTRN");
+ transparency = theReader.getFloat();
+ gotTransparencyFloat = true;
+ }
+ else if (tokenString.equals("TRAN")) {
+ debugOutputLn(LINE_TRACE, " TRAN");
+ if (gotTransparencyFloat)
+ theReader.skipLength(fieldLength);
+ else
+ transparency = (float)theReader.getShortInt()/255;
+ }
+ else if (tokenString.equals("VSPC")) {
+ debugOutputLn(LINE_TRACE, " VSPC");
+ specular = theReader.getFloat();
+ gotSpecularFloat = true;
+ debugOutputLn(VALUES, "spec = " + specular);
+ }
+ else if (tokenString.equals("SPEC")) {
+ debugOutputLn(LINE_TRACE, " SPEC");
+ if (gotSpecularFloat)
+ theReader.skipLength(fieldLength);
+ else {
+ if (fieldLength == 4) // Bug in some LW versions
+ specular = (float)theReader.getInt()/255;
+ else
+ specular = (float)theReader.getShortInt()/255;
+ }
+ }
+ else if (tokenString.equals("GLOS")) {
+ debugOutputLn(LINE_TRACE, " GLOS");
+ if (fieldLength == 4)
+ gloss = theReader.getInt();
+ else
+ gloss = theReader.getShortInt();
+ }
+ else if (tokenString.equals("SMAN")) {
+ debugOutputLn(LINE_TRACE, " SMAN");
+ creaseAngle = theReader.getFloat();
+ }
+ else if (tokenString.endsWith("TEX")) {
+ // Textures are complex - hand off this bit to the
+ // LwoTexture class
+ LwoTexture texture =
+ new LwoTexture(theReader,
+ surfStopMarker - theReader.getMarker(),
+ tokenString,
+ debugPrinter.getValidOutput());
+ textureToken = texture.getNextToken();
+ if (texture.isHandled())
+ textureList.addElement(texture);
+ debugOutputLn(WARNING, "val = " + tokenString);
+ }
+ else {
+ debugOutputLn(WARNING,
+ "unrecognized token: " + tokenString);
+ theReader.skipLength(fieldLength);
+ }
+ if (theReader.getMarker() < surfStopMarker) {
+ if (textureToken == null)
+ tokenString = theReader.getToken();
+ else
+ tokenString = textureToken;
+ }
+ }
+ }
+
+}
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwoTexture.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwoTexture.java
new file mode 100644
index 0000000..6f06cc9
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwoTexture.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Hashtable;
+
+import org.jogamp.java3d.Texture;
+import org.jogamp.java3d.Texture2D;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Vector3f;
+
+import org.jogamp.java3d.loaders.ParsingErrorException;
+import org.jogamp.java3d.utils.image.TextureLoader;
+
+/**
+ * This class is responsible for parsing the binary data in an Object file
+ * that describes a texture for a particular surface and turning that data
+ * into Java3D texture data. If the texture is coming from a file (which
+ * is the only type of texture handled by the loader currently; other
+ * types of texture definitions are ignored), then this class instantiates
+ * a TargaReader object to read the data in that file. Once all of the
+ * data has been read, the class creates a Java3D Texture object by first
+ * scaling the image using the ImageScaler class (since all textures must
+ * have width/height = power of 2; Note: this functionality is now built
+ * into the TextureLoader class, so it could be removed from this loader)
+ * and then creating a Texture with that image.
+ */
+
+class LwoTexture extends ParserObject {
+
+ LWOBFileReader theReader;
+ int red = 255, green = 255, blue = 255;
+ Color3f color, diffuseColor, specularColor, emissiveColor;
+ Image theImage = null;
+ String imageFile = null;
+ Vector3f textureSize = new Vector3f(1f, 1f, 1f);;
+ Vector3f textureCenter = new Vector3f(0f, 0f, 0f);
+ int textureAxis;
+ int flags = 0;
+ String type;
+ String mappingType;
+ String nextToken = null;
+ static Hashtable imageTable = new Hashtable();
+ static Hashtable textureTable = new Hashtable();
+
+ /**
+ * Constructor: calls readTexture() to parse the file and retrieve
+ * texture parameters
+ */
+ LwoTexture(LWOBFileReader reader, int length, String typename,
+ int debugVals) throws FileNotFoundException {
+ super(debugVals);
+ debugOutputLn(TRACE, "Constructor");
+ theReader = reader;
+ type = typename;
+ readTexture(length);
+ }
+
+ String getNextToken() {
+ return nextToken;
+ }
+
+ /**
+ * The loader currently only handles CTEX and DTEX texture types
+ * (These either represent the surface color like a decal (CTEX)
+ * or modify the diffuse color (DTEX)
+ */
+ boolean isHandled() {
+ if ((type.equals("CTEX") ||
+ type.equals("DTEX")) &&
+ theImage != null)
+ return true;
+ debugOutputLn(LINE_TRACE, "failed isHandled(), type, theImage = " +
+ type + ", " + theImage);
+ return false;
+ }
+
+ /**
+ * Return the actual Texture object associated with the current image.
+ * If we've already created a texture for this image, return that;
+ * otherwise create a new Texture
+ */
+ Texture getTexture() {
+ debugOutputLn(TRACE, "getTexture()");
+ if (theImage == null)
+ return null;
+ Texture2D t2d = (Texture2D)textureTable.get(theImage);
+ if (t2d == null) {
+ ImageScaler scaler = new ImageScaler((BufferedImage)theImage);
+ BufferedImage scaledImage = (BufferedImage)scaler.getScaledImage();
+ TextureLoader tl = new TextureLoader(scaledImage);
+ t2d = (Texture2D)tl.getTexture();
+ textureTable.put(theImage, t2d);
+ }
+
+ return t2d;
+ }
+
+ String getType() {
+ return type;
+ }
+
+ Color3f getColor() {
+ return color;
+ }
+
+ Image getImage() {
+ return theImage;
+ }
+
+ Vector3f getTextureSize() {
+ return textureSize;
+ }
+
+ int getTextureAxis() {
+ return textureAxis;
+ }
+
+ Vector3f getTextureCenter() {
+ return textureCenter;
+ }
+
+ String getMappingType() {
+ return mappingType;
+ }
+
+ /**
+ * Parse the binary file to retrieve all texture parameters for this
+ * surface. If/when we encounter a TIMG parameter, which contains the
+ * filename of an image, then create a new TargaReader object to
+ * read that image file
+ */
+ void readTexture(int length)
+ throws FileNotFoundException, ParsingErrorException {
+
+ debugOutputLn(TRACE, "readTexture()");
+
+ int surfStopMarker = theReader.getMarker() + length;
+ mappingType = theReader.getString();
+ debugOutputLn(VALUES, "mappingType = " + mappingType);
+ String tokenString = theReader.getToken();
+ while (!(tokenString == null) && theReader.getMarker() < surfStopMarker) {
+
+ debugOutputLn(VALUES, " tokenString = " + tokenString);
+ debugOutputLn(VALUES, " marker, stop = " + theReader.getMarker() + ", " + surfStopMarker);
+
+ if (tokenString.endsWith("TEX") ||
+ (!tokenString.startsWith("T") || tokenString.equals("TRAN"))) {
+ nextToken = tokenString;
+ return;
+ }
+
+ int fieldLength = theReader.getShortInt();
+ debugOutputLn(VALUES, " fl = " + fieldLength);
+
+ if (tokenString.equals("TFLG")) {
+ debugOutputLn(WARNING, "Not yet handling: " + tokenString);
+ flags = theReader.getShortInt();
+ textureAxis = flags & 0x07;
+ debugOutputLn(WARNING, "val = " + flags);
+ }
+ else if (tokenString.equals("TCLR")) {
+ debugOutputLn(WARNING, "Not yet handling: " + tokenString);
+ try {
+ red = theReader.read();
+ green = theReader.read();
+ blue = theReader.read();
+ theReader.read();
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ debugOutputLn(WARNING, "val = " + red + ", " + green +
+ ", " + blue);
+ }
+ else if (tokenString.equals("TIMG")) {
+ debugOutputLn(WARNING, "Not yet handling: " + tokenString);
+ imageFile = theReader.getString();
+ debugOutputLn(VALUES, "imageFile = " + imageFile);
+ if (imageFile.indexOf("none") == -1) {
+ if ((theImage =
+ (Image)imageTable.get(imageFile)) == null) {
+ try {
+ TargaReader tr =
+ new TargaReader(imageFile,
+ debugPrinter.getValidOutput());
+ theImage = tr.getImage();
+ imageTable.put(imageFile, theImage);
+ }
+ catch (FileNotFoundException e) {
+ // Ignore texture if can't find it
+ debugOutputLn(WARNING, "Image File skipped: " +
+ imageFile);
+ }
+ }
+ }
+ debugOutputLn(WARNING, "val = __" + imageFile + "__");
+ }
+ else if (tokenString.equals("TWRP")) {
+ debugOutputLn(WARNING, "Not yet handling: " + tokenString);
+ int widthWrap = theReader.getShortInt();
+ int heightWrap = theReader.getShortInt();
+ debugOutputLn(WARNING, "val = " + widthWrap + ", " +
+ heightWrap);
+ }
+ else if (tokenString.equals("TCTR")) {
+ debugOutputLn(WARNING, "Not yet handling: " + tokenString);
+ textureCenter.x = theReader.getFloat();
+ textureCenter.y = theReader.getFloat();
+ textureCenter.z = theReader.getFloat();
+ debugOutputLn(WARNING, "val = " + textureCenter);
+ }
+ else if (tokenString.equals("TSIZ")) {
+ debugOutputLn(WARNING, "Not yet handling: " + tokenString);
+ textureSize.x = theReader.getFloat();
+ textureSize.y = theReader.getFloat();
+ textureSize.z = theReader.getFloat();
+ debugOutputLn(WARNING, "val = " + textureSize);
+ }
+ else {
+ debugOutputLn(WARNING,
+ "unrecognized token: " + tokenString);
+ theReader.skipLength(fieldLength);
+ }
+ if (theReader.getMarker() < surfStopMarker) {
+ tokenString = theReader.getToken();
+ }
+ }
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsBackground.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsBackground.java
new file mode 100644
index 0000000..93592e0
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsBackground.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+
+
+import java.io.IOException;
+import java.io.StreamTokenizer;
+
+import org.jogamp.java3d.Background;
+import org.jogamp.java3d.BoundingSphere;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Point3d;
+
+import org.jogamp.java3d.loaders.ParsingErrorException;
+
+
+/**
+ * This class creates a Background object (solid color only, no geometry)
+ * according to some of the data stored in a Scene file. Note: Lightwave
+ * defines much more complex backgrounds that the loader currently
+ * handles. It should be possible to se Background Geometry to handle
+ * most of these cases, if there's time and will to work on the problem.
+ */
+
+class LwsBackground extends TextfileParser {
+
+ // data from the file
+ int solidBackdrop;
+ Color3f color, zenithColor, skyColor, groundColor, nadirColor;
+ Background backgroundObject = null;
+
+
+ /**
+ * Constructor: parses stream and retrieves all Background-related data
+ */
+ LwsBackground(StreamTokenizer st, int debugVals)
+ throws ParsingErrorException {
+
+ debugPrinter.setValidOutput(debugVals);
+ debugOutput(TRACE, "LwsBackground()");
+ color = new Color3f(0f, 0f, 0f);
+ zenithColor = new Color3f(0f, 0f, 0f);
+ skyColor = new Color3f(0f, 0f, 0f);
+ groundColor = new Color3f(0f, 0f, 0f);
+ nadirColor = new Color3f(0f, 0f, 0f);
+
+ solidBackdrop = (int)getNumber(st);
+ while (!isCurrentToken(st, "FogType")) {
+ debugOutputLn(LINE_TRACE, "currentToken = " + st.sval);
+
+ if (isCurrentToken(st, "BackdropColor")) {
+ color.x = (float)getNumber(st)/255f;
+ color.y = (float)getNumber(st)/255f;
+ color.z = (float)getNumber(st)/255f;
+ }
+ else if (isCurrentToken(st, "NadirColor")) {
+ nadirColor.x = (float)getNumber(st)/255f;
+ nadirColor.y = (float)getNumber(st)/255f;
+ nadirColor.z = (float)getNumber(st)/255f;
+ }
+ else if (isCurrentToken(st, "SkyColor")) {
+ skyColor.x = (float)getNumber(st)/255f;
+ skyColor.y = (float)getNumber(st)/255f;
+ skyColor.z = (float)getNumber(st)/255f;
+ }
+ else if (isCurrentToken(st, "GroundColor")) {
+ groundColor.x = (float)getNumber(st)/255f;
+ groundColor.y = (float)getNumber(st)/255f;
+ groundColor.z = (float)getNumber(st)/255f;
+ }
+ else if (isCurrentToken(st, "NadirColor")) {
+ nadirColor.x = (float)getNumber(st)/255f;
+ nadirColor.y = (float)getNumber(st)/255f;
+ nadirColor.z = (float)getNumber(st)/255f;
+ }
+ try {
+ st.nextToken();
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ }
+ st.pushBack(); // push token back on stack
+ }
+
+ /**
+ * Creates Java3d objects from the background data. Note that there
+ * are plenty of lw3d background attributes that the loader currently
+ * ignores. Some of these may best be handled by creating background
+ * geometry rather than a solid background color
+ */
+ void createJava3dObject() {
+ // TODO: there are various attributes of
+ // backdrops that we're not currently handling. In
+ // particular, if the file calls for a gradient background
+ // (solidBackdrop == 0), we ignore the request and just
+ // create a solid background from the sky color instead.
+ // We should be able to do something with the
+ // various colors specified, perhaps by creating
+ // background geometry with the appropriate vertex
+ // colors?
+
+ if (solidBackdrop != 0) {
+ backgroundObject = new Background(color);
+ debugOutput(VALUES, "Background color = " + color);
+ }
+ else {
+ backgroundObject = new Background(skyColor);
+ debugOutput(VALUES, "Background color = " + skyColor);
+ }
+ BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100000.0);
+ backgroundObject.setApplicationBounds(bounds);
+ }
+
+ Background getObjectNode() {
+ return backgroundObject;
+ }
+
+ void printVals() {
+ debugOutputLn(VALUES, " BACKGROUND vals: ");
+ }
+
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsCamera.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsCamera.java
new file mode 100644
index 0000000..dc8ff51
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsCamera.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+
+
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.util.Vector;
+
+import org.jogamp.java3d.Behavior;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.vecmath.Matrix4d;
+
+import org.jogamp.java3d.loaders.ParsingErrorException;
+
+/**
+ * This class parses the data in a Scene file related to the camera and
+ * creates Java3D TransformGroup that holds the data for positioning
+ * and orienting the view according to the camera specifications.
+ */
+
+class LwsCamera extends TextfileParser implements LwsPrimitive {
+
+ // data from the file
+ String fileName;
+ String objName;
+ LwsMotion motion;
+ int parent;
+ TransformGroup objectTransform;
+ Vector objectBehavior;
+
+ /**
+ * Constructor: parses camera info and creates LwsMotion object for
+ * keyframe data
+ */
+ LwsCamera(StreamTokenizer st, int firstFrame,
+ int totalFrames, float totalTime,
+ int debugVals) throws ParsingErrorException {
+ debugPrinter.setValidOutput(debugVals);
+ parent = -1;
+ getNumber(st); // Skip ShowCamera parameters
+ getNumber(st);
+ getAndCheckString(st, "CameraMotion");
+ motion = new LwsMotion(st, firstFrame, totalFrames, totalTime,
+ debugPrinter.getValidOutput());
+
+ // TODO: buggy way to stop processing the camera. Should actually
+ // process required/optional fields in order and stop when there's
+ // no more.
+
+ while (!isCurrentToken(st, "DepthOfField")) {
+ debugOutputLn(LINE_TRACE, "currentToken = " + st.sval);
+
+ if (isCurrentToken(st, "ParentObject")) {
+ parent = (int)getNumber(st);
+ }
+ try {
+ st.nextToken();
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ }
+ getNumber(st); // skip shadow type parameter
+ }
+
+ /**
+ * Returns parent of the camera object
+ */
+ int getParent() {
+ return parent;
+ }
+
+ /**
+ * Creates Java3D items from the camera data. These objects consist
+ * of: a TransformGroup to hold the view platform, and the behaviors
+ * (if any) that act upon the view's TransformGroup.
+ */
+ void createJava3dObject(int loadBehaviors)
+ {
+ Matrix4d mat = new Matrix4d();
+ mat.setIdentity();
+ // Set the node's transform matrix according to the first frame
+ // of the object's motion
+ LwsFrame firstFrame = motion.getFirstFrame();
+ firstFrame.setMatrix(mat);
+ debugOutputLn(VALUES, " Camera Matrix = \n" + mat);
+ Transform3D t1 = new Transform3D();
+ Matrix4d m = new Matrix4d();
+ double scale = .1;
+ m.setColumn(0, scale, 0, 0, 0); // setScale not yet implemented
+ m.setColumn(1, 0, scale, 0, 0);
+ m.setColumn(2, 0, 0, scale, 0);
+ m.setColumn(3, 0, 0, 0, 1);
+ Transform3D scaleTrans = new Transform3D(m);
+ TransformGroup scaleGroup = new TransformGroup(scaleTrans);
+ scaleGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+ scaleGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
+ // mat.mul(m);
+ t1.set(mat);
+ objectTransform = new TransformGroup(t1);
+ objectTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+ objectBehavior = new Vector();;
+ if (loadBehaviors != 0) {
+ motion.createJava3dBehaviors(objectTransform);
+ Behavior b = motion.getBehaviors();
+ if (b != null)
+ objectBehavior.addElement(b);
+ }
+ }
+
+ /**
+ * Returns TransformGroup of camera
+ */
+ @Override
+ public TransformGroup getObjectNode()
+ {
+ return objectTransform;
+ }
+
+ /**
+ * Returns animation behaviors for camera
+ */
+ @Override
+ public Vector getObjectBehaviors()
+ {
+ debugOutputLn(TRACE, "getObjectBehaviors()");
+ return objectBehavior;
+ }
+
+ /**
+ * This is a debuggin utility, not currently activated. It prints
+ * out the camera values
+ */
+ void printVals()
+ {
+ System.out.println(" objName = " + objName);
+ motion.printVals();
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsEnvelope.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsEnvelope.java
new file mode 100644
index 0000000..f2fc836
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsEnvelope.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+import java.io.IOException;
+import java.io.StreamTokenizer;
+
+import org.jogamp.java3d.Behavior;
+import org.jogamp.java3d.TransformGroup;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+import org.jogamp.java3d.loaders.IncorrectFormatException;
+import org.jogamp.java3d.loaders.ParsingErrorException;
+
+/**
+ * This class is a superclass for any implementation of envelopes; the
+ * only subclass currently is LwsEnvelopeLightIntensity. LwsEnvelope
+ * parses the data in a Scene file and extracts the envelope data.
+ */
+
+class LwsEnvelope extends TextfileParser {
+
+ // data from the file
+ String name;
+ LwsEnvelopeFrame frames[];
+ int numFrames;
+ int numChannels;
+ boolean loop;
+ float totalTime;
+ int totalFrames;
+ Behavior behaviors;
+
+ /**
+ * Constructor: calls getEnvelope() to parse the stream for the
+ * envelope data
+ */
+ LwsEnvelope(StreamTokenizer st, int frames, float time) {
+ numFrames = 0;
+ totalTime = time;
+ totalFrames = frames;
+ name = getName(st);
+ getEnvelope(st);
+ }
+
+ /**
+ * Parses the stream to retrieve all envelope data. Creates
+ * LwsEnvelopeFrame objects for each keyframe of the envelope
+ * (these frames differ slightly from LwsFrame objects because
+ * envelopes contain slightly different data)
+ */
+ void getEnvelope(StreamTokenizer st)
+ throws IncorrectFormatException, ParsingErrorException
+ {
+ debugOutputLn(TRACE, "getEnvelope()");
+ numChannels = (int)getNumber(st);
+ if (numChannels != 1) {
+ throw new IncorrectFormatException(
+ J3dUtilsI18N.getString("LwsEnvelope0"));
+ }
+ debugOutputLn(LINE_TRACE, "got channels");
+
+ numFrames = (int)getNumber(st);
+ frames = new LwsEnvelopeFrame[numFrames];
+ debugOutputLn(VALUES, "got frames" + numFrames);
+
+ for (int i = 0; i < numFrames; ++i) {
+ frames[i] = new LwsEnvelopeFrame(st);
+ }
+ debugOutput(LINE_TRACE, "got all frames");
+
+ try {
+ st.nextToken();
+ while (!isCurrentToken(st, "EndBehavior")) {
+ // There is an undocumented "FrameOffset" in some files
+ st.nextToken();
+ }
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ int repeatVal = (int)getNumber(st);
+ if (repeatVal == 1)
+ loop = false;
+ else
+ loop = true;
+ }
+
+ /**
+ * This superclass does nothing here - if the loader understands
+ * how to deal with a particular type of envelope, it will use
+ * a subclass of LwsEnvelope that will override this method
+ */
+ void createJava3dBehaviors(TransformGroup target) {
+ behaviors = null;
+ }
+
+ Behavior getBehaviors() {
+ return behaviors;
+ }
+
+
+ LwsEnvelopeFrame getFirstFrame() {
+ if (numFrames > 0)
+ return frames[0];
+ else
+ return null;
+ }
+
+
+ void printVals() {
+ debugOutputLn(VALUES, " name = " + name);
+ debugOutputLn(VALUES, " numChannels = " + numChannels);
+ debugOutputLn(VALUES, " numFrames = " + numFrames);
+ debugOutputLn(VALUES, " loop = " + loop);
+ for (int i = 0; i < numFrames; ++i) {
+ debugOutputLn(VALUES, " FRAME " + i);
+ frames[i].printVals();
+ }
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsEnvelopeFrame.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsEnvelopeFrame.java
new file mode 100644
index 0000000..9eef98a
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsEnvelopeFrame.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+
+
+import java.io.StreamTokenizer;
+
+/**
+ * This class represents one keyframe in an envelope sequence.
+ */
+
+class LwsEnvelopeFrame extends TextfileParser {
+
+ // data from the file
+ double value;
+ double frameNumber;
+ int linearValue;
+ double tension, continuity, bias;
+
+
+ /**
+ * Constructor: parses stream and stores data for one keyframe of
+ * an envelope sequence
+ */
+ LwsEnvelopeFrame(StreamTokenizer st) {
+ value = getNumber(st);
+ debugOutputLn(VALUES, "value = " + value);
+ frameNumber = (int)getNumber(st);
+ linearValue = (int)getNumber(st);
+ debugOutputLn(VALUES, "framenum, linear " + frameNumber + " , " + linearValue);
+ tension = getNumber(st);
+ continuity = getNumber(st);
+ bias = getNumber(st);
+ debugOutputLn(VALUES, "tension, cont, bias = " + tension + ", " + continuity + ", " + bias);
+ //System.out.println(" FRAME VALS");
+ //printVals();
+ }
+
+
+ double getValue() {
+ return value;
+ }
+
+
+ double getFrameNum() {
+ return frameNumber;
+ }
+
+
+ void printVals() {
+ debugOutputLn(VALUES, " value = " + value);
+ debugOutputLn(VALUES, " frameNum = " + frameNumber);
+ debugOutputLn(VALUES, " lin = " + linearValue);
+ debugOutputLn(VALUES, " tension = " + tension);
+ debugOutputLn(VALUES, " continuity = " + continuity);
+ debugOutputLn(VALUES, " bias = " + bias);
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsEnvelopeLightIntensity.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsEnvelopeLightIntensity.java
new file mode 100644
index 0000000..6c131c5
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsEnvelopeLightIntensity.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+
+
+import java.io.StreamTokenizer;
+
+import org.jogamp.java3d.Alpha;
+import org.jogamp.java3d.Behavior;
+import org.jogamp.java3d.BoundingSphere;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.vecmath.Point3d;
+
+
+/**
+ * This class creates a LightIntensityPathInterpolator object from the
+ * keyframe-based envelope specified in a Scene file.
+ */
+
+class LwsEnvelopeLightIntensity extends LwsEnvelope {
+
+
+ /**
+ * Constructor: Calls superclass, which will parse the stream
+ * and store the envelope data
+ */
+ LwsEnvelopeLightIntensity(StreamTokenizer st,
+ int frames, float time) {
+ super(st, frames, time);
+ }
+
+ /**
+ * Creates Java3d behaviors given the stored envelope data. The
+ * Behavior created is a LightIntensityPathInterpolator
+ */
+ void createJava3dBehaviors(Object target) {
+ if (numFrames <= 1)
+ behaviors = null;
+ else {
+ long alphaAtOne = 0;
+ int loopCount;
+ if (loop)
+ loopCount = -1;
+ else
+ loopCount = 1;
+ // Note: hardcoded to always loop...
+ loopCount = -1;
+ debugOutputLn(VALUES, "totalTime = " + totalTime);
+ debugOutputLn(VALUES, "loopCount = " + loopCount);
+ float animTime = 1000.0f * totalTime *
+ (float)(frames[numFrames-1].getFrameNum()/(float)totalFrames);
+ debugOutputLn(VALUES, " anim time: " + animTime);
+ debugOutputLn(VALUES, " totalFrames = " + totalFrames);
+ debugOutputLn(VALUES, " lastFrame = " +
+ frames[numFrames-1].getFrameNum());
+ if (!loop)
+ alphaAtOne = (long)(1000.0*totalTime - animTime);
+ Alpha theAlpha =
+ new Alpha(loopCount, Alpha.INCREASING_ENABLE,
+ 0, 0, (long)animTime, 0,
+ alphaAtOne, 0, 0, 0);
+ float knots[] = new float[numFrames];
+ float values[] = new float[numFrames];
+ for (int i=0; i < numFrames; ++i) {
+ values[i] = (float)frames[i].getValue();
+ knots[i] = (float)(frames[i].getFrameNum())/
+ (float)(frames[numFrames-1].getFrameNum());
+ debugOutputLn(VALUES, "value, knot = " +
+ values[i] + ", " + knots[i]);
+ }
+ LightIntensityPathInterpolator l = new
+ LightIntensityPathInterpolator(theAlpha,
+ knots,
+ values,
+ target);
+ if (l != null) {
+ behaviors = l;
+ BoundingSphere bounds =
+ new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0);
+ behaviors.setSchedulingBounds(bounds);
+ ((TransformGroup)target).setCapability
+ (TransformGroup.ALLOW_TRANSFORM_WRITE);
+ ((TransformGroup)target).addChild(behaviors);
+ }
+ }
+ }
+
+
+ @Override
+ Behavior getBehaviors() {
+ return behaviors;
+ }
+
+
+ @Override
+ LwsEnvelopeFrame getFirstFrame() {
+ if (numFrames > 0)
+ return frames[0];
+ else
+ return null;
+ }
+
+
+ @Override
+ void printVals() {
+ debugOutputLn(VALUES, " name = " + name);
+ debugOutputLn(VALUES, " numChannels = " + numChannels);
+ debugOutputLn(VALUES, " numFrames = " + numFrames);
+ debugOutputLn(VALUES, " loop = " + loop);
+ for (int i = 0; i < numFrames; ++i) {
+ debugOutputLn(VALUES, " FRAME " + i);
+ frames[i].printVals();
+ }
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsFog.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsFog.java
new file mode 100644
index 0000000..b79583c
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsFog.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+
+
+import java.io.IOException;
+import java.io.StreamTokenizer;
+
+import org.jogamp.java3d.BoundingSphere;
+import org.jogamp.java3d.Fog;
+import org.jogamp.java3d.LinearFog;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Point3d;
+
+import org.jogamp.java3d.loaders.ParsingErrorException;
+
+
+/**
+ * This class creates a Fog object from the data in a Scene file.
+ */
+
+class LwsFog extends TextfileParser {
+
+ // data from the file
+ float minDist, maxDist, minAmount, maxAmount;
+ int backdropFog;
+ Color3f color;
+ int type;
+ Fog fogObject = null;
+
+ /**
+ * Constructor: parses stream and stores fog data
+ */
+ LwsFog(StreamTokenizer st, int debugVals) throws ParsingErrorException {
+ debugPrinter.setValidOutput(debugVals);
+ debugOutput(TRACE, "LwsFog()");
+ color = new Color3f(0f, 0f, 0f);
+
+ while (!isCurrentToken(st, "DitherIntensity")) {
+ debugOutputLn(LINE_TRACE, "currentToken = " + st.sval);
+
+ if (isCurrentToken(st, "FogMinDist")) {
+ minDist = (float)getNumber(st);
+ }
+ else if (isCurrentToken(st, "FogMaxDist")) {
+ maxDist = (float)getNumber(st);
+ }
+ else if (isCurrentToken(st, "FogMinAmount")) {
+ minAmount = (float)getNumber(st);
+ }
+ else if (isCurrentToken(st, "FogMaxAmount")) {
+ maxAmount = (float)getNumber(st);
+ }
+ else if (isCurrentToken(st, "BackdropFog")) {
+ backdropFog = (int)getNumber(st);
+ }
+ else if (isCurrentToken(st, "FogColor")) {
+ color.x = (float)getNumber(st)/255f;
+ color.y = (float)getNumber(st)/255f;
+ color.z = (float)getNumber(st)/255f;
+ }
+ try {
+ st.nextToken();
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ }
+ st.pushBack(); // push token back on stack
+ }
+
+ /**
+ * Creates Java3d Fog object given the fog parameters in the file.
+ * Note that various fog parameters in lw3d are not currently handled.
+ */
+ void createJava3dObject() {
+ // TODO: there are various attributes of lw fog that
+ // we're not currently handing, including non-linear fog
+ // (need to understand the two different types - these may
+ // map onto java3d's expontential fog node), non-solid
+ // backdrop colors (how to handle this?), min/max amount
+ // (j3d only handles 0 -> 1 case)
+
+ fogObject = new LinearFog(color, minDist, maxDist);
+ debugOutputLn(VALUES,
+ "just set linearFog with color, minDist, maxDist = " +
+ color + ", " +
+ minDist + ", " +
+ maxDist);
+ BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100000.0);
+ fogObject.setInfluencingBounds(bounds);
+ }
+
+ Fog getObjectNode()
+ {
+ return fogObject;
+ }
+
+ void printVals()
+ {
+ debugOutputLn(VALUES, " FOG vals: ");
+ }
+
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsFrame.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsFrame.java
new file mode 100644
index 0000000..3222fd4
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsFrame.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+
+
+import java.io.StreamTokenizer;
+
+import org.jogamp.vecmath.Matrix4d;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3d;
+
+/**
+ * This class is responsible for parsing the data in a Scene file
+ * associated with a single keyframe. This data includes the position,
+ * orientation, and scaling information, in addition to the frame number
+ * of that keyframe and some spline controls which are currently
+ * ignored.
+ */
+
+class LwsFrame extends TextfileParser {
+
+ // data from the file
+ double x, y, z;
+ double heading, pitch, bank;
+ double xScale, yScale, zScale;
+ double frameNumber;
+ int linearValue;
+ double tension, continuity, bias;
+
+ /**
+ * Constructor: parses and stores all data associated with a particular
+ * keyframe
+ */
+ LwsFrame(StreamTokenizer st) {
+ x = getNumber(st);
+ y = getNumber(st);
+ z = -getNumber(st);
+ debugOutputLn(VALUES, "x, y, z " + x + ", " + y + ", " + z);
+ heading = getNumber(st);
+ pitch = getNumber(st);
+ bank = getNumber(st);
+ debugOutputLn(VALUES, "(degrees) h, p, b = " + heading + ", " + pitch + ", " + bank);
+ heading *= (Math.PI / 180.0); // Java3d works with radians
+ pitch *= (Math.PI / 180.0);
+ bank *= (Math.PI / 180.0);
+ debugOutputLn(VALUES, "(radians) h, p, b = " + heading + ", " + pitch + ", " + bank);
+ debugOutputLn(LINE_TRACE, "got pos and ori");
+ xScale = getNumber(st);
+ yScale = getNumber(st);
+ zScale = getNumber(st);
+ debugOutputLn(VALUES, "xs, ys, zs " + xScale +", " + yScale + ", " + zScale);
+ frameNumber = (int)getNumber(st);
+ // Note: The following spline controls are ignored
+ linearValue = (int)getNumber(st);
+ debugOutputLn(VALUES, "framenum, linear " + frameNumber + " , " + linearValue);
+ tension = getNumber(st);
+ continuity = getNumber(st);
+ bias = getNumber(st);
+ debugOutputLn(VALUES, "tension, cont, bias = " + tension + ", " + continuity + ", " + bias);
+ }
+
+
+
+ /**
+ * Construct new frame that's in-between two given frames
+ * Ratio gives the interpolation value for how far in-between
+ * the new frame should be (0.5 is half-way, etc)
+ */
+ LwsFrame(LwsFrame prevFrame, LwsFrame nextFrame, double ratio) {
+
+ x = prevFrame.x + (nextFrame.x - prevFrame.x) * ratio;
+ y = prevFrame.y + (nextFrame.y - prevFrame.y) * ratio;
+ z = prevFrame.z + (nextFrame.z - prevFrame.z) * ratio;
+
+ heading = prevFrame.heading +
+ (nextFrame.heading - prevFrame.heading) * ratio;
+ pitch = prevFrame.pitch +
+ (nextFrame.pitch - prevFrame.pitch) * ratio;
+ bank = prevFrame.bank +
+ (nextFrame.bank - prevFrame.bank) * ratio;
+ xScale = prevFrame.xScale +
+ (nextFrame.xScale - prevFrame.xScale) * ratio;
+ yScale = prevFrame.yScale +
+ (nextFrame.yScale - prevFrame.yScale) * ratio;
+ zScale = prevFrame.zScale +
+ (nextFrame.zScale - prevFrame.zScale) * ratio;
+ frameNumber = prevFrame.frameNumber +
+ (nextFrame.frameNumber - prevFrame.frameNumber) * ratio;
+
+ // The following are not interpolated
+ linearValue = prevFrame.linearValue;
+ tension = prevFrame.tension;
+ continuity = prevFrame.continuity;
+ bias = prevFrame.bias;
+ }
+
+ /**
+ * Using hermite interpolation construct a new frame that's
+ * in-between two given frames. We also need to be given a
+ * frame before the first frame and a frame after the second
+ * frame. The calling function will make sure that we get the
+ * four appropriate frames.
+ *
+ * Ratio gives the interpolation value for how far in-between
+ * the new frame should be. (.5 is half-way, etc.)
+ */
+ LwsFrame(LwsFrame prevFrame, LwsFrame frame1,
+ LwsFrame frame2, LwsFrame nextFrame, double u,
+ double adj0, double adj1) {
+
+ double h1, h2, h3, h4;
+ double dd0a, dd0b, ds1a, ds1b;
+
+ // pre-compute spline coefficients
+ double u2, u3, z1;
+ u2 = u * u;
+ u3 = u2 *u;
+ z1 = 3.0f *u2 - u3 - u3;
+ h1 = 1.0f - z1;
+ h2 = z1;
+ h3 = u3 - u2 - u2 + u;
+ h4 = u3 - u2;
+
+ dd0a = (1.0f - frame1.tension) * (1.0f + frame1.continuity)
+ * (1.0f + frame1.bias);
+
+ dd0b = (1.0f - frame1.tension) * (1.0f - frame1.continuity)
+ * (1.0f - frame1.bias);
+
+ ds1a = (1.0f - frame2.tension) * (1.0f - frame2.continuity)
+ * (1.0f + frame2.bias);
+
+ ds1b = (1.0f - frame2.tension) * (1.0f + frame2.continuity)
+ * (1.0f - frame2.bias);
+
+ double[] v = new double[4];
+
+ // interpolate x, y, z
+ v[0] = prevFrame.x; v[1] = frame1.x;
+ v[2] = frame2.x; v[3] = nextFrame.x;
+ x = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
+ adj0, adj1, h1, h2, h3, h4);
+ v[0] = prevFrame.y; v[1] = frame1.y;
+ v[2] = frame2.y; v[3] = nextFrame.y;
+ y = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
+ adj0, adj1, h1, h2, h3, h4);
+ v[0] = prevFrame.z; v[1] = frame1.z;
+ v[2] = frame2.z; v[3] = nextFrame.z;
+ z = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
+ adj0, adj1, h1, h2, h3, h4);
+
+ // interpolate heading pitch and bank
+ v[0] = prevFrame.heading; v[1] = frame1.heading;
+ v[2] = frame2.heading ; v[3] = nextFrame.heading;
+ heading = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
+ adj0, adj1, h1, h2, h3, h4);
+
+ v[0] = prevFrame.pitch; v[1] = frame1.pitch;
+ v[2] = frame2.pitch; v[3] = nextFrame.pitch;
+ pitch = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
+ adj0, adj1, h1, h2, h3, h4);
+
+ v[0] = prevFrame.bank; v[1] = frame1.bank;
+ v[2] = frame2.bank; v[3] = nextFrame.bank;
+ bank = computeInterpolation (v, dd0a, dd0b, ds1a, ds1b,
+ adj0, adj1, h1, h2, h3, h4);
+
+ // interpolate scale - scale interpolation is assumed to be linear
+ xScale = frame1.xScale + (frame2.xScale - frame1.xScale) * u;
+ yScale = frame1.yScale + (frame2.yScale - frame1.yScale) * u;
+ zScale = frame1.zScale + (frame2.zScale - frame1.zScale) * u;
+
+ // interpolate frame number
+ frameNumber = frame1.frameNumber +
+ (frame2.frameNumber - frame1.frameNumber) * u;
+
+ // The following are not interpolated
+ linearValue = frame2.linearValue;
+
+ // We need to keep the spline smooth between knot points
+ tension = 0.0;
+ continuity = 0.0;
+ bias = 0.0;
+ }
+
+
+ double computeInterpolation(double[] value, double dd0a,
+ double dd0b, double ds1a,
+ double ds1b, double adj0,
+ double adj1, double h1,
+ double h2, double h3, double h4) {
+
+ double dd0, ds1;
+ double delta = value[2] - value[1] ;
+ double result;
+
+ // if adj != 0
+ if (adj0 < -0.0001 || adj0 > 0.0001)
+ dd0 = adj0 * (dd0a * (value[1] - value[0]) + dd0b * delta);
+ else
+ dd0 = 0.5f * (dd0a + dd0b) * delta;
+
+ // if adj != 0
+ if (adj1 < -0.0001 || adj1 > 0.0001)
+ ds1 = adj1 * (ds1a * delta + ds1b * (value[3] - value[2]));
+ else
+ ds1 = 0.5f * (ds1a + ds1b) * delta;
+
+ result = value[1] * h1 + value[2] * h2 + dd0 * h3 + ds1 * h4;
+
+ return (result);
+ }
+
+ double getHeading() {
+ return heading;
+ }
+
+ double getPitch() {
+ return pitch;
+ }
+
+ double getBank() {
+ return bank;
+ }
+
+ /**
+ * Sets the given matrix to contain the position, orientation, and
+ * scale values for the keyframe
+ */
+ void setMatrix(Matrix4d mat) {
+ setRotationMatrix(mat);
+ mat.setTranslation(new Vector3d(x, y, z));
+ Matrix4d m = new Matrix4d();
+ m.setColumn(0, xScale, 0, 0, 0); // setScale not yet implemented
+ m.setColumn(1, 0, yScale, 0, 0);
+ m.setColumn(2, 0, 0, zScale, 0);
+ m.setColumn(3, 0, 0, 0, 1);
+ mat.mul(m);
+ }
+
+ /**
+ * Sets the given matrix to contain the orientation for this keyframe
+ */
+ void setRotationMatrix(Matrix4d mat)
+ {
+ debugOutputLn(TRACE, "setRotMat()");
+ debugOutputLn(VALUES, " p, h, b = " +
+ pitch + ", " +
+ heading + ", " +
+ bank);
+ Matrix4d pitchMat = new Matrix4d();
+ pitchMat.rotX(-pitch);
+ Matrix4d bankMat = new Matrix4d();
+ bankMat.rotZ(bank);
+ mat.rotY(-heading);
+ mat.mul(pitchMat);
+ mat.mul(bankMat);
+ debugOutputLn(VALUES, "setRotMat(), mat = " + mat);
+ }
+
+ Point3f getPosition() {
+ return (new Point3f((float)x, (float)y, (float)z));
+ }
+
+ Point3f getScale() {
+ // Make sure we don't have zero scale components
+ if ((xScale < -0.0001 || xScale > 0.0001) &&
+ (yScale < -0.0001 || yScale > 0.0001) &&
+ (zScale < -0.0001 || zScale > 0.0001)) {
+ return (new Point3f((float)xScale, (float)yScale, (float)zScale));
+ } else {
+ return (new Point3f(1.0f, 1.0f, 1.0f));
+ }
+ }
+
+ double getFrameNum() {
+ return frameNumber;
+ }
+
+ void printVals() {
+ debugOutputLn(VALUES, " x = " + x);
+ debugOutputLn(VALUES, " y = " + y);
+ debugOutputLn(VALUES, " z = " + z);
+ debugOutputLn(VALUES, " xScale = " + xScale);
+ debugOutputLn(VALUES, " yScale = " + yScale);
+ debugOutputLn(VALUES, " zScale = " + zScale);
+ debugOutputLn(VALUES, " heading = " + heading);
+ debugOutputLn(VALUES, " pitch = " + pitch);
+ debugOutputLn(VALUES, " bank = " + bank);
+ debugOutputLn(VALUES, " frameNum = " + frameNumber);
+ debugOutputLn(VALUES, " lin = " + linearValue);
+ debugOutputLn(VALUES, " tension = " + tension);
+ debugOutputLn(VALUES, " continuity = " + continuity);
+ debugOutputLn(VALUES, " bias = " + bias);
+ }
+
+}
+
+
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsLight.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsLight.java
new file mode 100644
index 0000000..f48cb75
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsLight.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+
+
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.util.Vector;
+
+import org.jogamp.java3d.Behavior;
+import org.jogamp.java3d.BoundingSphere;
+import org.jogamp.java3d.DirectionalLight;
+import org.jogamp.java3d.Light;
+import org.jogamp.java3d.PointLight;
+import org.jogamp.java3d.SpotLight;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Matrix4d;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3f;
+
+import org.jogamp.java3d.loaders.ParsingErrorException;
+
+/**
+ * This class creates a light object from the data in a Scene file. It
+ * instantiates an LwsMotion object to create any associated
+ * animations.
+ */
+
+class LwsLight extends TextfileParser implements LwsPrimitive {
+
+ // data from the file
+ String fileName;
+ String objName;
+ LwsMotion motion;
+ int parent;
+ TransformGroup objectTransform;
+ Vector objectBehavior;
+ Color3f color;
+ int type;
+ Point3f attenuation = new Point3f(1.0f, 0.0f, 0.0f);
+ float spotConeAngle = (float)(Math.PI);
+ // Meta object, used for holding light and
+ LwLightObject lwLight;
+ // light parameters
+ LwsEnvelopeLightIntensity intensityEnvelope = null;
+ Light light = null;
+ final static int DIRECTIONAL = 0, POINT = 1, SPOT = 2;
+
+ /**
+ * Constructor: parses stream and creates data structures for all
+ * light parameters currently handled by the loader
+ */
+ LwsLight(StreamTokenizer st, int totalFrames, float totalTime,
+ int debugVals) throws ParsingErrorException {
+
+ debugPrinter.setValidOutput(debugVals);
+
+ debugOutput(TRACE, "LwsLight()");
+ color = new Color3f(1f, 1f, 1f);
+ lwLight = new LwLightObject(null, 0.0f, null);
+
+ parent = -1;
+ debugOutputLn(LINE_TRACE, "about to get LightName");
+ getAndCheckString(st, "LightName");
+ debugOutputLn(LINE_TRACE, "about to get LightName value");
+ objName = getName(st);
+ debugOutputLn(LINE_TRACE, "got LightName");
+ skip(st, "ShowLight", 2);
+ debugOutputLn(LINE_TRACE, "got ShowLight");
+ getAndCheckString(st, "LightMotion");
+ debugOutputLn(LINE_TRACE, "got LightMotion");
+ motion = new LwsMotion(st, totalFrames, totalTime);
+ debugOutputLn(LINE_TRACE, "got motions");
+
+ // TODO: buggy way to stop processing the light. Should actually
+ // process required/optional fields in order and stop when there's
+ // no more. However, spec says "ShadowCasing" but the files say
+ // "ShadowType".
+
+ while (!isCurrentToken(st, "ShowCamera") &&
+ !isCurrentToken(st, "AddLight")) {
+ // TODO:
+ // Things that we're not yet processing (and should):
+ // - EdgeAngle: for spotlights, this is the angle which
+ // contains the linear falloff toward the edge of the
+ // ConeAngle. This doesn't directly map to J3d's
+ // "concentration" value, so it's left out for now.
+
+ debugOutputLn(LINE_TRACE, "currentToken = " + st.sval);
+
+ if (isCurrentToken(st, "ParentObject")) {
+ parent = (int)getNumber(st);
+ }
+ else if (isCurrentToken(st, "LightColor")) {
+ color.x = (float)getNumber(st)/255f;
+ color.y = (float)getNumber(st)/255f;
+ color.z = (float)getNumber(st)/255f;
+ lwLight.setColor(color);
+ }
+ else if (isCurrentToken(st, "LgtIntensity")) {
+ // TODO: must be able to handle envelopes here
+ String className = getClass().getName();
+ int classIndex = className.lastIndexOf('.');
+ String packageName;
+ if (classIndex < 0)
+ packageName = "";
+ else
+ packageName = className.substring(0, classIndex) + ".";
+ EnvelopeHandler env =
+ new EnvelopeHandler(st, totalFrames, totalTime,
+ packageName + "LwsEnvelopeLightIntensity");
+ if (env.hasValue) {
+ float intensity = (float)env.theValue;
+ color.x *= intensity;
+ color.y *= intensity;
+ color.z *= intensity;
+ lwLight.setIntensity(intensity);
+ }
+ else {
+ intensityEnvelope =
+ (LwsEnvelopeLightIntensity)env.theEnvelope;
+ }
+ }
+ else if (isCurrentToken(st, "LightType")) {
+ type = (int)getNumber(st);
+ }
+ else if (isCurrentToken(st, "Falloff")) {
+ float falloff = (float)getNumber(st);
+ attenuation.y = 1.0f/(1.0f - falloff) - 1.0f;
+ }
+ else if (isCurrentToken(st, "ConeAngle")) {
+ spotConeAngle = (float)getNumber(st) * (float)(Math.PI / 180.0);
+ }
+ try {
+ st.nextToken();
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ }
+ st.pushBack(); // push "ShowCamera" or "AddLight" back on stack
+ }
+
+ int getParent() {
+ return parent;
+ }
+
+ /**
+ * Create Java3D objects from the data we got from the file
+ */
+ void createJava3dObject(int loadBehaviors) {
+ Matrix4d mat = new Matrix4d();
+ mat.setIdentity();
+ // Set the node's transform matrix according to the first frame
+ // of the object's motion
+ LwsFrame firstFrame = motion.getFirstFrame();
+ firstFrame.setMatrix(mat);
+ debugOutputLn(VALUES, "Light transform = " + mat);
+ Transform3D t1 = new Transform3D();
+ t1.set(mat);
+ objectTransform = new TransformGroup(t1);
+ objectTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+ Vector3f defaultDir = new Vector3f(0f, 0f, -1f);
+ Point3f defaultPos = new Point3f(0f, 0f, 0f);
+
+ switch (type) {
+ case DIRECTIONAL:
+ light = new DirectionalLight(color, defaultDir);
+ break;
+ case POINT:
+ light = new PointLight(color, defaultPos, attenuation);
+ break;
+ case SPOT:
+ // Note: spotConeAngle in lw3d is half that of Java3d...
+ light = new SpotLight(color, defaultPos, attenuation, defaultDir,
+ 2 * spotConeAngle, 0.0f);
+ break;
+ default:
+ // Shouldn't get here
+ break;
+ }
+
+ light.setCapability(Light.ALLOW_COLOR_WRITE);
+ if (light != null) {
+ lwLight.setLight(light);
+ BoundingSphere bounds =
+ new BoundingSphere(new Point3d(0.0,0.0,0.0), 100000.0);
+ light.setInfluencingBounds(bounds);
+ objectTransform.addChild(light);
+
+ // load behaviors if we have to
+ objectBehavior = new Vector();
+ if (loadBehaviors != 0) {
+ Behavior b;
+ b = null;
+ motion.createJava3dBehaviors(objectTransform);
+ b = motion.getBehaviors();
+ if (b != null)
+ objectBehavior.addElement(b);
+
+ if (intensityEnvelope != null) {
+ b = null;
+ intensityEnvelope.createJava3dBehaviors(lwLight);
+ b = intensityEnvelope.getBehaviors();
+ if (b != null)
+ objectBehavior.addElement(b);
+ }
+ }
+ }
+ }
+
+ @Override
+ public TransformGroup getObjectNode()
+ {
+ return objectTransform;
+ }
+
+ Light getLight() {
+ return light;
+ }
+
+ @Override
+ public Vector getObjectBehaviors()
+ {
+ debugOutputLn(TRACE, "getObjectBehaviors()");
+ return objectBehavior;
+ }
+
+
+ void printVals()
+ {
+ debugOutputLn(VALUES, " LIGHT vals: ");
+ debugOutputLn(VALUES, " objName = " + objName);
+ motion.printVals();
+ }
+
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsMotion.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsMotion.java
new file mode 100644
index 0000000..2d3df74
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsMotion.java
@@ -0,0 +1,693 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+import java.io.StreamTokenizer;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.jogamp.java3d.Alpha;
+import org.jogamp.java3d.Behavior;
+import org.jogamp.java3d.BoundingSphere;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.vecmath.Matrix4d;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Quat4f;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+import org.jogamp.java3d.loaders.IncorrectFormatException;
+import org.jogamp.java3d.loaders.ParsingErrorException;
+import org.jogamp.java3d.utils.behaviors.interpolators.KBKeyFrame;
+import org.jogamp.java3d.utils.behaviors.interpolators.KBRotPosScaleSplinePathInterpolator;
+
+/**
+ * This class is responsible for parsing the data in a Scene file related to
+ * an object's animation and constructing the appropriate Java3D
+ * Behavior objects. For each keyframe defined for the animation in the
+ * Lightwave file, this class creates a LwsFrame object to parse that
+ * keyframe data and create the appropriate data structures. Then for
+ * each of those LwsFrame objects created, LwsMotion creates a knot
+ * value for a PathInterpolator and fills in the appropriate field. Finally,
+ * the class creates a RotPosScalePathInterpolator with all of the data
+ * from the animation. There are also some utility functions in this
+ * class for dealing with special cases of animations, such as animations
+ * that begin after the first frame of the scene and animations that
+ * define frames in a way that Java3D cannot easily interpret.
+ */
+
+class LwsMotion extends TextfileParser {
+
+ // data from the file
+ String motionName;
+ LwsFrame frames[];
+ int numFrames;
+ int numChannels;
+ boolean loop;
+ float totalTime;
+ int firstFrame;
+ int totalFrames;
+ Behavior behaviors;
+
+ /**
+ * Constructor
+ */
+ LwsMotion(StreamTokenizer st, int frames, float time) {
+ this(st, 0, frames, time, EXCEPTION);
+
+ }
+
+ /**
+ * Constructor: takes tokenizer, 1st frame of this animation, total
+ * number of frames, total time of animation, and the debug settings
+ */
+ LwsMotion(StreamTokenizer st, int firstFrame,
+ int frames, float time, int debugVals)
+ throws ParsingErrorException, IncorrectFormatException {
+
+ debugPrinter.setValidOutput(debugVals);
+ numFrames = 0;
+ totalTime = time;
+ this.firstFrame = firstFrame;
+ totalFrames = frames;
+ debugOutputLn(LINE_TRACE, "about to get motion name");
+ motionName = getName(st);
+ debugOutputLn(LINE_TRACE, "about to get motion");
+ getMotion(st);
+ }
+
+ /**
+ * This method parses the tokenizer and creates the data structures
+ * that hold the data from that file. For each separate keyframe,
+ * this method calls LwsFrame to parse and interpret that data.
+ */
+ void getMotion(StreamTokenizer st)
+ throws ParsingErrorException, IncorrectFormatException
+ {
+ debugOutputLn(TRACE, "getMotion()");
+ numChannels = (int)getNumber(st);
+ if (numChannels != 9) {
+ throw new IncorrectFormatException(
+ J3dUtilsI18N.getString("LwsMotion0"));
+ }
+ debugOutputLn(LINE_TRACE, "got channels");
+
+ numFrames = (int)getNumber(st);
+ frames = new LwsFrame[numFrames];
+ debugOutputLn(VALUES, "got frames" + numFrames);
+
+ for (int i = 0; i < numFrames; ++i) {
+ frames[i] = new LwsFrame(st);
+ }
+
+ debugOutput(LINE_TRACE, "got all frames");
+
+ getAndCheckString(st, "EndBehavior");
+ int repeatVal = (int)getNumber(st);
+ if (repeatVal == 1)
+ loop = false;
+ else
+ loop = true;
+
+ // need to make sure frame info is in sycn with j3d
+ // fixFrames();
+ }
+
+ /**
+ * The previous version of this method looked for sucessive frames with
+ * the same rotation value (mod 2PI). If it found such frames, it would
+ * divide that interval into 4 separate frames.
+ * This fix is not sufficient for various rotation cases, though. For
+ * instance, if the rotation difference between two frames is more than
+ * 2PI, the rotation will not case a flag to be fixed and the resulting
+ * rotation will only be between the delta of the two rotations, mod 2PI.
+ * The real fix should behave as follows:
+ * - Iterate through all sucessive frames
+ * - For any two frames that have rotation components that differ by more
+ * than PI/2 (one quarter rotation - no reason for this, but let's pick a
+ * small value to give our resulting path interpolations a better chance
+ * of behaving correctly), figure out how many frames we need to create to
+ * get increments of <= PI/2 between each frame.
+ * - Create these new frames
+ * - Set the odl frames pointer to the new frames structures.
+ */
+
+ void fixFrames() {
+
+ boolean addedFrames = false;
+ Vector newFramesList = new Vector();
+ double halfPI = (float)(Math.PI/2);
+ LwsFrame finalFrame = null;
+
+ for (int i = 1 ; i < numFrames; ++i) {
+ LwsFrame prevFrame;
+ LwsFrame lastFrame = frames[i-1];
+ LwsFrame thisFrame = frames[i];
+ LwsFrame nextFrame;
+
+ finalFrame = thisFrame;
+ newFramesList.add(lastFrame);
+
+ double largestAngleDifference = 0;
+ double thisAngle = thisFrame.getHeading();
+ double lastAngle = lastFrame.getHeading();
+ double angleDifference = Math.abs(thisAngle - lastAngle);
+ if (angleDifference > largestAngleDifference)
+ largestAngleDifference = angleDifference;
+
+ thisAngle = thisFrame.getPitch();
+ lastAngle = lastFrame.getPitch();
+ angleDifference = Math.abs(thisAngle - lastAngle);
+ if (angleDifference > largestAngleDifference)
+ largestAngleDifference = angleDifference;
+
+ thisAngle = thisFrame.getBank();
+ lastAngle = lastFrame.getBank();
+ angleDifference = Math.abs(thisAngle - lastAngle);
+ if (angleDifference > largestAngleDifference)
+ largestAngleDifference = angleDifference;
+
+ if (largestAngleDifference > halfPI) {
+ // Angles too big - create new frames
+ addedFrames = true;
+ int numNewFrames = (int)(largestAngleDifference/halfPI);
+ double increment = 1.0/(double)(numNewFrames+1);
+ double currentRatio = increment;
+
+ double totalf = frames[numFrames-1].getFrameNum();
+ double tlength = (thisFrame.getFrameNum() -
+ lastFrame.getFrameNum())/totalf;
+ double adj0;
+ double adj1;
+
+ // get the previous and next frames
+ if ((i-1) < 1) {
+ prevFrame = frames[i-1];
+ adj0 = 0.0;
+ } else {
+ prevFrame = frames[i-2];
+ adj0 = tlength/((thisFrame.getFrameNum() -
+ prevFrame.getFrameNum())/totalf);
+ }
+
+ if ((i+1) < numFrames) {
+ nextFrame = frames[i+1];
+ adj1 = tlength/((nextFrame.getFrameNum()-
+ lastFrame.getFrameNum())/totalf);
+ } else {
+ nextFrame = frames[i];
+ adj1 = 1.0;
+ }
+
+ for (int j = 0; j < numNewFrames; ++j) {
+
+ LwsFrame newFrame;
+
+ // if linear interpolation
+ if (thisFrame.linearValue == 1) {
+ newFrame = new LwsFrame(lastFrame,
+ thisFrame, currentRatio);
+
+ // if spline interpolation
+ } else {
+ newFrame = new LwsFrame(prevFrame, lastFrame,
+ thisFrame, nextFrame,
+ currentRatio, adj0, adj1);
+ }
+
+ currentRatio += increment;
+ newFramesList.add(newFrame);
+ }
+ }
+ }
+
+ // Now add in final frame
+ if (finalFrame != null)
+ newFramesList.add(finalFrame);
+ if (addedFrames) {
+
+ // Recreate frames array from newFramesList
+ LwsFrame newFrames[] = new LwsFrame[newFramesList.size()];
+ Enumeration elements = newFramesList.elements();
+ int index = 0;
+ while (elements.hasMoreElements()) {
+ newFrames[index++] = (LwsFrame)elements.nextElement();
+ }
+ frames = newFrames;
+ numFrames = frames.length;
+ for (int i = 0; i < numFrames; ++i) {
+ debugOutputLn(VALUES, "frame " + i + " = " + frames[i]);
+ frames[i].printVals();
+ }
+ }
+ }
+
+ /**
+ * Utility for getting integer mod value
+ */
+ int intMod(int divisee, int divisor) {
+ int tmpDiv = divisee;
+ int tmpDivisor = divisor;
+ if (tmpDiv < 0)
+ tmpDiv = -tmpDiv;
+ if (tmpDivisor < 0)
+ tmpDivisor = -tmpDivisor;
+ while (tmpDiv > tmpDivisor) {
+ tmpDiv -= tmpDivisor;
+ }
+ return tmpDiv;
+ }
+
+ /**
+ * Class that associates a particular frame with its effective frame
+ * number (which accounts for animations that start after frame 1)
+ */
+ class FrameHolder {
+ double frameNumber;
+ LwsFrame frame;
+
+ FrameHolder(LwsFrame theFrame, double number) {
+ frame = theFrame;
+ frameNumber = number;
+ }
+ }
+
+
+ /**
+ * This method was added to account for animations that start after
+ * the first frame (e.g., Juggler.lws starts at frame 30). We need
+ * to alter some of the information for the frames in this "frame subset"
+ */
+ void playWithFrameTimes(Vector framesVector) {
+ debugOutputLn(TRACE, "playWithFrameTimes: firstFrame = " +
+ firstFrame);
+ if (firstFrame == 1) {
+ return;
+ }
+ else if (frames[numFrames-1].getFrameNum() < totalFrames) {
+ // First, create a vector that holds all LwsFrame's in frame
+ // increasing order (where order is started at firstFrame Modulo
+ // this motion's last frame
+ int motionLastFrame =
+ (int)(frames[numFrames-1].getFrameNum() + .4999999);
+ int newFirstFrame = intMod(firstFrame, motionLastFrame);
+ int newLastFrame = intMod(totalFrames, motionLastFrame);
+ int index = 0;
+ while (index < numFrames) {
+ if (frames[index].getFrameNum() >= newFirstFrame)
+ break;
+ ++index;
+ }
+ int startIndex = index;
+ if (frames[startIndex].getFrameNum() > firstFrame &&
+ startIndex > 0)
+ startIndex--; // Actually, should interpolate
+ index = startIndex;
+ if (newFirstFrame < newLastFrame) {
+ while (index < numFrames &&
+ frames[index].getFrameNum() <= newLastFrame) {
+ FrameHolder frameHolder =
+ new FrameHolder(frames[index],
+ frames[index].getFrameNum() -
+ newFirstFrame);
+ framesVector.addElement(frameHolder);
+ ++index;
+ }
+ }
+ else {
+ double currentNewFrameNumber = -1.0;
+ while (index < numFrames) {
+ currentNewFrameNumber = frames[index].getFrameNum() -
+ newFirstFrame;
+ FrameHolder frameHolder =
+ new FrameHolder(frames[index],
+ currentNewFrameNumber);
+ framesVector.addElement(frameHolder);
+ ++index;
+ }
+ index = 0;
+ while (index <= startIndex &&
+ frames[index].getFrameNum() <= newLastFrame) {
+ if (index == 0) {
+ LwsFrame newFrame =
+ new LwsFrame(frames[index],
+ frames[index+1],
+ 1.0/(frames[index+1].getFrameNum() -
+ frames[index].getFrameNum()));
+ FrameHolder frameHolder =
+ new FrameHolder(newFrame,
+ newFrame.getFrameNum() +
+ currentNewFrameNumber);
+ framesVector.addElement(frameHolder);
+ }
+ else {
+ FrameHolder frameHolder =
+ new FrameHolder(frames[index],
+ frames[index].getFrameNum() +
+ currentNewFrameNumber);
+ framesVector.addElement(frameHolder);
+ }
+ ++index;
+ }
+ }
+ }
+ else {
+ int index = 0;
+ while (index < numFrames) {
+ if (frames[index].getFrameNum() >= firstFrame)
+ break;
+ ++index;
+ }
+ int startIndex = index;
+ if (frames[startIndex].getFrameNum() > firstFrame &&
+ startIndex > 0) {
+ // Interpolate to first frame
+ double ratio = (double)firstFrame /
+ (frames[startIndex].getFrameNum() -
+ frames[startIndex-1].getFrameNum());
+ LwsFrame newFrame = new LwsFrame(frames[startIndex-1],
+ frames[startIndex],
+ ratio);
+ FrameHolder frameHolder =
+ new FrameHolder(newFrame, newFrame.getFrameNum() -
+ firstFrame);
+ framesVector.addElement(frameHolder);
+ }
+ index = startIndex;
+ while (index < numFrames &&
+ frames[index].getFrameNum() <= totalFrames) {
+ FrameHolder frameHolder =
+ new FrameHolder(frames[index],
+ frames[index].getFrameNum() -
+ firstFrame);
+ framesVector.addElement(frameHolder);
+ ++index;
+ }
+ if (frames[index-1].getFrameNum() < totalFrames) {
+ // Interpolate to last frame
+ double ratio = (double)(totalFrames -
+ frames[index-1].getFrameNum()) /
+ (frames[index].getFrameNum() -
+ frames[index-1].getFrameNum());
+ LwsFrame newFrame = new LwsFrame(frames[index-1],
+ frames[index],
+ ratio);
+ FrameHolder frameHolder =
+ new FrameHolder(newFrame, totalFrames - firstFrame);
+ framesVector.addElement(frameHolder);
+ }
+ }
+ }
+
+ /**
+ * Normally, we just create j3d behaviors from the frames. But if the
+ * animation's first frame is after frame number one, then we have to
+ * shuffle things around to account for playing/looping on this subset
+ * of the total frames of the animation
+ */
+ void createJava3dBehaviorsForFramesSubset(TransformGroup target) {
+
+ debugOutputLn(TRACE, "createJava3dBehaviorsForFramesSubset");
+ Vector frameHolders = new Vector();
+ playWithFrameTimes(frameHolders);
+ long alphaAtOne = 0;
+
+ // determine looping
+ int loopCount;
+ if (loop)
+ loopCount = -1;
+ else
+ loopCount = 1;
+ loopCount = -1;
+
+ int numFrames = frameHolders.size();
+
+ debugOutputLn(VALUES, "totalTime = " + totalTime);
+ debugOutputLn(VALUES, "loopCount = " + loopCount);
+
+ FrameHolder lastFrameHolder =
+ (FrameHolder)frameHolders.elementAt(frameHolders.size() - 1);
+ LwsFrame lastFrame = lastFrameHolder.frame;
+ float animTime = 1000.0f * totalTime *
+ (float)(lastFrameHolder.frameNumber/(float)(totalFrames -
+ firstFrame));
+ debugOutputLn(VALUES, " anim time: " + animTime);
+ debugOutputLn(VALUES, " totalFrames = " + totalFrames);
+
+ if (!loop)
+ alphaAtOne = (long)(1000.0*totalTime - animTime);
+ Alpha theAlpha =
+ new Alpha(loopCount, Alpha.INCREASING_ENABLE,
+ 0, 0, (long)animTime, 0,
+ alphaAtOne, 0, 0, 0);
+
+ float knots[] = new float[numFrames];
+ Point3f[] positions = new Point3f[numFrames];
+ Quat4f[] quats = new Quat4f[numFrames];
+ Point3f[] scales = new Point3f[numFrames];
+ Transform3D yAxis = new Transform3D();
+ Matrix4d mat = new Matrix4d();
+ KBKeyFrame[] keyFrames = new KBKeyFrame[numFrames];
+
+ for (int i=0; i < numFrames; ++i) {
+
+ FrameHolder frameHolder = (FrameHolder)frameHolders.elementAt(i);
+ LwsFrame frame = frameHolder.frame;
+
+ // copy position
+ positions[i] = frame.getPosition();
+
+ // copy scale
+ // Used to hardcode no-scale: scales[i] = 1.0f, 1.0f, 1.0f;
+ // Note that we can't do non-uniform scaling in the current Path
+ // interpolators. The interpolator just uses the x scale.
+ // getScale makes sure that we don't have any zero scale component
+ scales[i] = frame.getScale();
+
+ // copy rotation information
+ frame.setRotationMatrix(mat);
+ debugOutputLn(VALUES, "LwsMotion::createj3dbeh, mat = " + mat);
+ quats[i] = new Quat4f();
+ quats[i].set(mat);
+ debugOutputLn(VALUES, " and quat = " + quats[i]);
+
+ // calculate knot points from frame numbers
+ if (i == 0)
+ knots[i] = 0.0f;
+ else
+ knots[i] = (float)(frameHolder.frameNumber)/
+ (float)(lastFrameHolder.frameNumber);
+
+ // Create KB key frames
+ keyFrames[i] = new KBKeyFrame(knots[i], frame.linearValue,
+ positions[i],
+ (float)frame.heading,
+ (float)frame.pitch,
+ (float)frame.bank,
+ scales[i],
+ (float)frame.tension,
+ (float)frame.continuity,
+ (float)frame.bias);
+
+ debugOutputLn(VALUES, "pos, knots, quat = " +
+ positions[i] + knots[i] + quats[i]);
+ }
+
+ // Pass the KeyFrames to the interpolator an let it do its thing
+ KBRotPosScaleSplinePathInterpolator b = new
+ KBRotPosScaleSplinePathInterpolator(theAlpha,
+ target,
+ yAxis,
+ keyFrames);
+ if (b != null) {
+ behaviors = b;
+ BoundingSphere bounds =
+ new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0);
+ b.setSchedulingBounds(bounds);
+ target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+ target.addChild(behaviors);
+ }
+ }
+
+ /**
+ * Create j3d behaviors for the data stored in this animation. This is
+ * done by creating a RotPosScalePathInterpolator object that contains
+ * all of the position, orientation, scale data for each keyframe.
+ */
+ void createJava3dBehaviors(TransformGroup target) {
+
+ if (numFrames <= 1)
+ behaviors = null;
+ else {
+ if (firstFrame > 1) {
+ createJava3dBehaviorsForFramesSubset(target);
+ return;
+ }
+
+ long alphaAtOne = 0;
+
+ // determine looping
+ int loopCount;
+ if (loop)
+ loopCount = -1;
+ else
+ loopCount = 1;
+ loopCount = -1;
+
+ debugOutputLn(VALUES, "totalTime = " + totalTime);
+ debugOutputLn(VALUES, "loopCount = " + loopCount);
+
+ float animTime = 1000.0f * totalTime *
+ (float)(frames[numFrames-1].getFrameNum()/(float)totalFrames);
+
+ debugOutputLn(VALUES, " anim time: " + animTime);
+ debugOutputLn(VALUES, " totalFrames = " + totalFrames);
+ debugOutputLn(VALUES, " lastFrame = " +
+ frames[numFrames-1].getFrameNum());
+
+ if (!loop)
+ alphaAtOne = (long)(1000.0*totalTime - animTime);
+ Alpha theAlpha =
+ new Alpha(loopCount, Alpha.INCREASING_ENABLE,
+ 0, 0, (long)animTime, 0,
+ alphaAtOne, 0, 0, 0);
+
+ float knots[] = new float[numFrames];
+ Point3f[] positions = new Point3f[numFrames];
+ Quat4f[] quats = new Quat4f[numFrames];
+ Point3f[] scales = new Point3f[numFrames];
+ Transform3D yAxis = new Transform3D();
+ Matrix4d mat = new Matrix4d();
+ KBKeyFrame[] keyFrames = new KBKeyFrame[numFrames];
+
+ for (int i=0; i < numFrames; ++i) {
+
+ // copy position
+ positions[i] = frames[i].getPosition();
+
+ // copy scale
+ // Used to hardcode no-scale: scales[i] = 1.0f, 1.0f, 1.0f;
+ // Note that we can't do non-uniform scaling in the current Path
+ // interpolators. The interpolator just uses the x scale.
+ // getScale makes sure that we don't have any 0 scale component
+ scales[i] = frames[i].getScale();
+
+ // copy rotation information
+ frames[i].setRotationMatrix(mat);
+ debugOutputLn(VALUES, "LwsMotion::createj3dbeh, mat = " + mat);
+ quats[i] = new Quat4f();
+ quats[i].set(mat);
+ debugOutputLn(VALUES, " and quat = " + quats[i]);
+
+ // calculate knot points from frame numbers
+ if (i == 0)
+ knots[i] = 0.0f;
+ else
+ knots[i] = (float)(frames[i].getFrameNum())/
+ (float)(frames[numFrames-1].getFrameNum());
+
+ // Create KB key frames
+ keyFrames[i] = new KBKeyFrame(knots[i],frames[i].linearValue,
+ positions[i],
+ (float)frames[i].heading,
+ (float)frames[i].pitch,
+ (float)frames[i].bank,
+ scales[i],
+ (float)frames[i].tension,
+ (float)frames[i].continuity,
+ (float)frames[i].bias);
+
+
+ debugOutputLn(VALUES, "pos, knots, quat = " +
+ positions[i] + knots[i] + quats[i]);
+ }
+
+ // Pass the KeyFrames to the interpolator an let it do its thing
+ KBRotPosScaleSplinePathInterpolator b = new
+ KBRotPosScaleSplinePathInterpolator(theAlpha,
+ target,
+ yAxis,
+ keyFrames);
+ if (b != null) {
+ behaviors = b;
+ BoundingSphere bounds =
+ new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0);
+ b.setSchedulingBounds(bounds);
+ target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+ target.addChild(behaviors);
+ }
+ }
+
+ }
+
+ /**
+ * Returns the Behavior object created for this animation
+ */
+ Behavior getBehaviors() {
+ return behaviors;
+ }
+
+ /**
+ * Returns the first LwsFrame object (which contains the initial
+ * setup for a given object)
+ */
+ LwsFrame getFirstFrame() {
+ if (numFrames > 0)
+ return frames[0];
+ else
+ return null;
+ }
+
+ /**
+ * Utility function for printing values
+ */
+ void printVals() {
+ debugOutputLn(VALUES, " motionName = " + motionName);
+ debugOutputLn(VALUES, " numChannels = " + numChannels);
+ debugOutputLn(VALUES, " numFrames = " + numFrames);
+ debugOutputLn(VALUES, " loop = " + loop);
+ for (int i = 0; i < numFrames; ++i) {
+ debugOutputLn(VALUES, " FRAME " + i);
+ frames[i].printVals();
+ }
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsObject.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsObject.java
new file mode 100644
index 0000000..7529bbc
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsObject.java
@@ -0,0 +1,573 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.jogamp.java3d.Behavior;
+import org.jogamp.java3d.Group;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.vecmath.Matrix4d;
+import org.jogamp.vecmath.Vector3f;
+
+import org.jogamp.java3d.loaders.IncorrectFormatException;
+import org.jogamp.java3d.loaders.ParsingErrorException;
+
+/**
+ * An LwsObject is passed a handle to the text file that contains the scene
+ * and is responsible for parsing a particular section of that file that
+ * describes a single object. This section defines the type of object
+ * (either a group or some geometry specified by an Object file) and
+ * some keyframe data that describes the an animation of the
+ * orientation/position/scale of the object. For geometry objects, this
+ * class instantiates a J3dLwoParser object to parse the binary data file.
+ * For the keyframe data, the class instantiates an LwsMotion object to
+ * parse and store that data.
+ */
+
+class LwsObject extends TextfileParser implements LwsPrimitive {
+
+ // data from the file
+ String fileName;
+ String objName;
+ LwsMotion motion;
+ int parent;
+ TransformGroup objectTransform;
+ Vector objectBehavior;
+ Vector shapeList = null;
+ boolean hasPivot = false;
+ TransformGroup pivotTransGroup = null;
+
+ URL urlName;
+ String protocol;
+ int fileType;
+
+ /**
+ * Constructor: parses object section of this scene file and
+ * creates all appropriate data structures to hold the information
+ * @param st StreamTokenizer for scene file
+ * @param loadObject boolean specifying that object is not a lw3d Null
+ * object
+ * @param firstFrame int holding the first frame of the scene's animation
+ * @param totalFrames int holding the total number of frames in the scene
+ * @param totalTime float holding the total time of the animation
+ * @param loader Lw3dLoader loader object that was created by user
+ * @param debugVals in holding current debug flags
+ */
+ LwsObject(StreamTokenizer st, boolean loadObject,
+ int firstFrame, int totalFrames, float totalTime,
+ Lw3dLoader loader, int debugVals)
+ throws java.io.FileNotFoundException,
+ ParsingErrorException {
+ debugPrinter.setValidOutput(debugVals);
+ parent = -1;
+
+ fileType = loader.getFileType();
+
+ try {
+ if (loadObject) {
+ // If this is true, then the object is actually described
+ // in an external geometry file. Get that filename
+ fileName = getString(st);
+ String path = null;
+ switch (loader.getFileType()) {
+ case Lw3dLoader.FILE_TYPE_FILENAME:
+ // No other case is current implemented in this loader
+ path = loader.getBasePath();
+ if (path == null)
+ path = loader.getInternalBasePath();
+ if (path != null) {
+ // It's not sufficient to just use the base path.
+ // Lightwave scene files tend to embed path names
+ // to object files that are only correct if you
+ // start from a certain directory. For example, a
+ // scene file in data/ may point to an object in
+ // data/Objects - but in this case
+ // getInternalBasePath() would be data/, so you'd
+ // look for the object in data/data/Objects...
+ // To attempt to overcome this confusing state of
+ // affairs, let's check path/filename
+ // first, then iterate all the way up the path
+ // until there are no more members of path. This
+ // will ensure that we'll at least pick up data
+ // files if they exist off of one of the parent
+ // directories of wherever the scene file is
+ // stored.
+ // No, I don't really like this solution, but I don't
+ // know of a better general approach for now...
+
+ fileName = getQualifiedFilename(path, fileName);
+ }
+ break;
+ case Lw3dLoader.FILE_TYPE_URL:
+ path = "";
+ URL pathUrl = loader.getBaseUrl();
+ if (pathUrl != null) {
+ path = pathUrl.toString();
+ // store the protocol
+ protocol = pathUrl.getProtocol();
+ }
+ else {
+ path = loader.getInternalBaseUrl();
+ // store the protocol
+ protocol = (new URL(path)).getProtocol();
+ }
+
+ urlName = getQualifiedURL(path, fileName);
+ break;
+ }
+ }
+ else
+ // else the object is a lw3d Null object; essentially a group
+ // which contains other objects
+ objName = getString(st);
+ skip(st, "ShowObject", 2);
+ debugOutputLn(LINE_TRACE,
+ "skipped showobject, about to get objectmotion");
+ getAndCheckString(st, "ObjectMotion");
+ debugOutputLn(LINE_TRACE, "got string " + st.sval);
+ // Create an LwsMotion object to parse the animation data
+ motion = new LwsMotion(st, firstFrame, totalFrames,
+ totalTime, debugVals);
+ debugOutputLn(LINE_TRACE, "got motion");
+ boolean hasParent = false; // keeps bones prim from reassigning par
+
+ // TODO: This isn't the greatest way to stop parsing an object
+ // (keying on the ShowOptions parameter), but it seems to be valid
+ // for the current lw3d format
+ while (!isCurrentToken(st, "ShadowOptions")) {
+ if (!hasParent &&
+ isCurrentToken(st, "ParentObject")) {
+ parent = (int)getNumber(st);
+ hasParent = true;
+ }
+ else if (isCurrentToken(st, "PivotPoint")) {
+ // PivotPoint objects are tricky - they make the object
+ // rotate about this new point instead of the default
+ // So setup transform groups such that this happens
+ // correctly.
+ hasPivot = true;
+ float x = (float)getNumber(st);
+ float y = (float)getNumber(st);
+ float z = (float)getNumber(st);
+ Vector3f pivotPoint = new Vector3f(-x, -y, z);
+ Transform3D pivotTransform = new Transform3D();
+ pivotTransform.set(pivotPoint);
+ pivotTransGroup = new TransformGroup(pivotTransform);
+ pivotTransGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+ }
+
+ else if (isCurrentToken(st, "ObjDissolve")) {
+ // Just handle it for now, don't care about value
+ EnvelopeHandler env =
+ new EnvelopeHandler(st, totalFrames, totalTime);
+ }
+ st.nextToken();
+ }
+ getNumber(st); // skip shadow options parameter
+ debugOutputLn(LINE_TRACE, "done with LwsObject constructor");
+ }
+ catch (MalformedURLException e) {
+ throw new FileNotFoundException(e.getMessage());
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ catch (NumberFormatException e) {
+ throw new ParsingErrorException("Expected a number, got " +
+ e.getMessage());
+ }
+ }
+
+ /**
+ * This method takes the given path and filename and checks whether
+ * that file exists. If not, it chops off the last part of pathname
+ * and recurse to try again. This has the effect of searching all the
+ * way up a given pathname for the existence of the file anywhere
+ * along that path. This is somewhat of a hack to get around the
+ * constraining way that Lightwave uses to define its data object
+ * locations in its scene files.
+ *
+ * If the filename is absolute, it will use the path information from
+ * the filename first, then the path information from the lws file.
+ * If the file can not be found in these locations, the local directory
+ * will be searched.
+ * In addition, it will look for filenames converted to lowercase to
+ * make it easier to use between Windows and Unix.
+ */
+
+ String getQualifiedFilename(String pathname, String filename)
+ throws java.io.FileNotFoundException {
+
+ int index;
+ String pathname2 = "";
+
+ // System.out.println ("pathname:"+pathname+" filename:"+filename);
+
+ // Do we have an absolute filename ?
+ if (filename.indexOf (File.separator) == 0) {
+ if ((index = filename.lastIndexOf (File.separator)) != -1) {
+ pathname2 = filename.substring (0, index+1);
+ filename = filename.substring (index+1);
+ }
+ else {
+ return null; // something out of the ordinary happened
+ }
+ }
+
+ // See if we can find the file
+ // ---------------------------
+
+ // Try pathname from absolute filename
+ try {
+ if (new File(pathname2 + filename).exists()) {
+ return (pathname2 + filename);
+ }
+ }
+ catch (NullPointerException ex) {
+ ex.printStackTrace();
+ }
+ // Try lowercase filename
+ if (new File(pathname2 + filename.toLowerCase()).exists()) {
+ return (pathname2 + filename.toLowerCase());
+ }
+
+ // Try original pathname
+ if (new File(pathname + filename).exists()) {
+ return (pathname + filename);
+ }
+ // Try lowercase filename
+ if (new File(pathname + filename.toLowerCase()).exists()) {
+ return (pathname + filename.toLowerCase());
+ }
+
+ // Finally, let's check the local directory
+ if (new File(filename).exists()) {
+ return (filename);
+ }
+ // Try lowercase filename
+ if (new File(filename.toLowerCase()).exists()) {
+ return (filename.toLowerCase());
+ }
+
+ // Conditions that determine when we give up on the recursive search
+ if ((pathname.equals(File.separator)) ||
+ (pathname == null) ||
+ (pathname.equals(""))) {
+
+ throw new java.io.FileNotFoundException(filename);
+ }
+
+ // Try to find the file in the upper directories
+ // Chop off the last directory from pathname and recurse
+ StringBuffer newPathName = new StringBuffer(128);
+ StringTokenizer st = new StringTokenizer(pathname, File.separator);
+ int tokenCount = st.countTokens() - 1;
+ if (pathname.startsWith(java.io.File.separator))
+ newPathName.append(File.separator);
+ for (int i = 0; i < tokenCount; ++i) {
+ String directory = st.nextToken();
+ newPathName.append(directory);
+ newPathName.append(File.separator);
+ }
+
+ String newPath = newPathName.toString();
+ return getQualifiedFilename(newPath, filename);
+ }
+
+ URL getQualifiedURL(String path, String file)
+ throws MalformedURLException {
+
+ URL url = null;
+
+ // try the path and the file -- this is the lightwave spec
+ try {
+ // create url
+ url = new URL(path + file);
+ // see if file exists
+ url.getContent();
+ // return url if no exception is thrown
+ return url;
+ }
+ catch (IOException e) {
+ // Ignore - try something different
+ }
+
+ // try a couple other options, but trying to open connections is slow,
+ // so don't try as many options as getQualifiedFilename
+
+ // try absolute path
+ try {
+ url = new URL(file);
+ url.getContent();
+ }
+ catch (IOException ex) {
+ // Ignore - try something different
+ }
+
+ // try the absolute path with the protocol
+ try {
+ url = new URL(protocol + ":" + file);
+ url.getContent();
+ return url;
+ }
+ catch (IOException ex) {
+ // Nothing else to try so give up
+ throw new MalformedURLException(path + file);
+ }
+ }
+
+ /**
+ * Returns parent object
+ */
+ int getParent() {
+ return parent;
+ }
+
+ /**
+ * Adds the given child to the transform of this node (its parent).
+ */
+ void addChild(LwsPrimitive child) {
+ debugOutputLn(TRACE, "addChild()");
+ if (objectTransform != null) {
+ debugOutputLn(LINE_TRACE, "objectTransform = " + objectTransform);
+ if (child.getObjectNode() != null) {
+ debugOutputLn(LINE_TRACE, "child has object node");
+ if (hasPivot)
+ pivotTransGroup.addChild(child.getObjectNode());
+ else
+ objectTransform.addChild(child.getObjectNode());
+ }
+/*
+ if (child.getObjectBehaviors() != null) {
+ debugOutputLn(LINE_TRACE, "child has behaviors");
+ Group bg = child.getObjectBehaviors();
+ debugOutputLn(VALUES, " child behaviors = " + bg);
+ // TODO: should remove intermediate group nodes
+ objectBehavior.addChild(bg);
+ }
+*/
+ }
+ }
+
+ /**
+ * Creates Java3d objects from the data stored for this object.
+ * The objects created consist of: A TransformGroup that holds the
+ * transform specified by the first keyframe, a Behavior that acts
+ * on the TransformGroup if there are more than 1 keyframes, and
+ * some geometry (created by J3dLwoParser) from an external geometry
+ * file (if the object wasn't an lw3d Null object (group)).
+ */
+ void createJava3dObject(LwsObject cloneObject, int loadBehaviors)
+ throws IncorrectFormatException, ParsingErrorException,
+ FileNotFoundException
+ {
+ String seqToken = new String("_sequence_");
+ Matrix4d mat = new Matrix4d();
+ mat.setIdentity();
+ // Set the node's transform matrix according to the first frame
+ // of the object's motion
+ LwsFrame firstFrame = motion.getFirstFrame();
+ firstFrame.setMatrix(mat);
+ Transform3D t1 = new Transform3D();
+ t1.set(mat);
+ objectTransform = new TransformGroup(t1);
+ objectTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+
+ // This following bit is a hack and should probably be removed.
+ // It was put in here in order to handle the "Tloop" functionality
+ // of holosketch, which was needed for the 1998 Javaone conference
+ // (the HighNoon demo, in particular). Having the code here, or
+ // using it, means that some object file names are tagged as special
+ // because they contain the phrase "_sequence_", which tells this
+ // object file reader that that object file is, in fact, a
+ // sequence file. It then creates a SequenceReader object to
+ // read that file and create an animation from the objects defined
+ // in that file.
+ // See SequenceReader.java for more information on this.
+ // By the way, a better/fuller implementation of this functionality
+ // would involve investigating a standard Plug-In for Lightwave
+ // that allows the writing out of sequence files from Bones data.
+ // i think it would be better to base any Tloop stuff on that
+ // standard than on some proprietary hack of our own.
+
+ if (fileName != null && fileName.indexOf(seqToken) != -1) { // Tloop
+
+ int index = fileName.indexOf(seqToken);
+ index += seqToken.length();
+ String seqFilename = fileName.substring(index);
+ int endIndex = seqFilename.indexOf(".lwo");
+ if (endIndex != -1)
+ seqFilename = seqFilename.substring(0, endIndex);
+ if ((new File(seqFilename)).exists()) {
+ SequenceReader sr =
+ new SequenceReader(seqFilename,
+ motion.totalTime,
+ (int)motion.totalFrames);
+ sr.printLines();
+ sr.createJava3dObjects(debugPrinter.getValidOutput(),
+ loadBehaviors);
+ Group g = sr.getObjectNode();
+ if (g != null)
+ objectTransform.addChild(g);
+
+ // Sequence reader's getObjectBehaviors creates new Vector
+ objectBehavior = sr.getObjectBehaviors();
+
+ return;
+ }
+ }
+
+ // Okay, now that that hack is out of the way, let's get on with
+ // "normal" Lightwave object files.
+ if (fileName != null || urlName != null) {
+ // If this object refers to an obj file, load it and create
+ // geometry from it.
+ if (cloneObject == null) {
+ debugOutputLn(VALUES,
+ "About to load binary file for " + fileName);
+ // Create a J3dLwoParser object to parse the geometry file
+ // and create the appropriate geometry
+ J3dLwoParser objParser = null;
+ switch (fileType) {
+ case Lw3dLoader.FILE_TYPE_FILENAME:
+ objParser =
+ new J3dLwoParser(fileName,
+ debugPrinter.getValidOutput());
+ break;
+ case Lw3dLoader.FILE_TYPE_URL:
+ objParser = new J3dLwoParser(urlName,
+ debugPrinter.getValidOutput());
+ break;
+ }
+ objParser.createJava3dGeometry();
+ // pivot points change the parent transform
+ if (hasPivot) {
+ objectTransform.addChild(pivotTransGroup);
+ }
+ if (objParser.getJava3dShapeList() != null) {
+ shapeList = objParser.getJava3dShapeList();
+ for (Enumeration e = shapeList.elements() ;
+ e.hasMoreElements() ;) {
+ if (!hasPivot || pivotTransGroup == null)
+ objectTransform.addChild((Shape3D)e.nextElement());
+ else
+ pivotTransGroup.addChild((Shape3D)e.nextElement());
+ }
+ }
+ }
+ else {
+ // Already read that file: Clone original object
+ debugOutputLn(LINE_TRACE, "Cloning shapes");
+ Vector cloneShapeList = cloneObject.getShapeList();
+ for (Enumeration e = cloneShapeList.elements() ;
+ e.hasMoreElements() ;) {
+ debugOutputLn(LINE_TRACE, " shape clone");
+ Shape3D shape = (Shape3D)e.nextElement();
+ Shape3D cloneShape = (Shape3D)shape.cloneTree();
+ objectTransform.addChild(cloneShape);
+ }
+ }
+ }
+
+ // Create j3d behaviors for the object's animation
+ objectBehavior = new Vector();
+ if (loadBehaviors != 0) {
+ motion.createJava3dBehaviors(objectTransform);
+ Behavior b = motion.getBehaviors();
+ if (b != null)
+ objectBehavior.addElement(b);
+ }
+ }
+
+ /**
+ * Return list of Shape3D objects for this object file. This is used
+ * when cloning objects (if the scene file requests the same object file
+ * more than once, that object will be cloned instead of recreated each
+ * time).
+ */
+ Vector getShapeList() {
+ return shapeList;
+ }
+
+ /**
+ * Return the TransformGroup that holds this object file
+ */
+ @Override
+ public TransformGroup getObjectNode() {
+ return objectTransform;
+ }
+
+ /**
+ * Return the Group that holds this object's behaviors. The behaviors
+ * are grouped separately from the geometry so that they can be handled
+ * differently by the parent application.
+ */
+ @Override
+ public Vector getObjectBehaviors()
+ {
+ debugOutputLn(TRACE, "getObjectBehaviors()");
+ return objectBehavior;
+ }
+
+
+ /**
+ * Utiliy function to print some of the object values. Used in
+ * debugging.
+ */
+ void printVals()
+ {
+ debugOutputLn(VALUES, " OBJECT vals: ");
+ debugOutputLn(VALUES, " fileName = " + fileName);
+ debugOutputLn(VALUES, " objName = " + objName);
+ motion.printVals();
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsPrimitive.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsPrimitive.java
new file mode 100644
index 0000000..9ca455a
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/LwsPrimitive.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+
+
+import java.util.Vector;
+
+import org.jogamp.java3d.TransformGroup;
+
+/**
+ * This is an interface which is implemented by LwsObject,
+ * LwsFog, LwsBackground, LwsLight, etc. It provides a generic method
+ * for objects to access some of the common data in these classes.
+ */
+
+interface LwsPrimitive {
+
+ // interface from which other Lws types (Object, Camera, etc.)
+ // inherit methods
+
+ public Vector getObjectBehaviors();
+
+ public TransformGroup getObjectNode();
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/ParserObject.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/ParserObject.java
new file mode 100644
index 0000000..63dcc66
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/ParserObject.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+/**
+ * This class is a superclass of the binary parsing classes. It provides
+ * some basic debugging utilities.
+ */
+
+class ParserObject {
+
+
+ final static int TRACE = DebugOutput.TRACE, VALUES = DebugOutput.VALUES;
+ final static int MISC = DebugOutput.MISC, LINE_TRACE = DebugOutput.LINE_TRACE;
+ final static int NONE = DebugOutput.NONE, EXCEPTION = DebugOutput.EXCEPTION;
+ final static int TIME = DebugOutput.TIME, WARNING = DebugOutput.WARNING;
+
+ protected DebugOutput debugPrinter;
+
+
+ ParserObject() {
+ debugPrinter = new DebugOutput(EXCEPTION);
+ }
+
+ ParserObject(int debugVals) {
+ this();
+ debugPrinter.setValidOutput(debugVals);
+ }
+
+
+ protected void debugOutputLn(int outputType, String theOutput) {
+ if (theOutput.equals(""))
+ debugPrinter.println(outputType, theOutput);
+ else
+ debugPrinter.println(outputType,
+ getClass().getName() + "::" + theOutput);
+ }
+
+ protected void debugOutput(int outputType, String theOutput) {
+ debugPrinter.print(outputType, theOutput);
+ }
+
+
+
+}
+
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/SequenceLine.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/SequenceLine.java
new file mode 100644
index 0000000..5c475dd
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/SequenceLine.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.jogamp.java3d.Alpha;
+import org.jogamp.java3d.Behavior;
+import org.jogamp.java3d.BoundingSphere;
+import org.jogamp.java3d.Group;
+import org.jogamp.java3d.Link;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.java3d.SharedGroup;
+import org.jogamp.java3d.Switch;
+import org.jogamp.java3d.SwitchValueInterpolator;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.vecmath.Point3d;
+
+import org.jogamp.java3d.loaders.IncorrectFormatException;
+import org.jogamp.java3d.loaders.ParsingErrorException;
+
+/**
+ * This class was created to handle "sequence files", which allow
+ * holosketch-type Tloop sequences to be loaded through the lw3d loader.
+ * The class reads a sequence file line by line and uses SequenceLine to
+ * load the file specified in each line.
+ * Idea behind the Tloop process:
+ * Artist creates "tloops" (animations with each keyframe's
+ * geometry saved out explicitly) where the geometries are spaced
+ * one frame apart. Then I can automatically create a SwitchValueInterpolator
+ * based on this spacing. If the number of frames in the sequence is
+ * greater than the number of frames in the tloop, then it will automatically
+ * loop until the end of the sequence.
+ * Process:
+ * 1) Artist creates an animation of a null group that has a child with some
+ * special name, such as "bucket_sequence_bucketsequence.txt.lwo", which tells
+ * the lw3d loader that it should look for a sequence file by the name of
+ * bucketsequence.txt. What happens to this object is irrelevant (as far as
+ * the loader is concerned); all animation information is taken from its
+ * parent instead.
+ * 2) Artist saves out the geometry of the bucket at whatever frames she wants
+ * to. If she's saving a tloop (a sequence of frames), she should save them
+ * under the names
+ * 3) Artist creates the sequence file, which lists all saved geometry files
+ * (except sequences - these can be referred to simply by the first file
+ * (...000.lwo)), along with their associated start/end frames. She also lists
+ * the number of files in the sequence, although this parameter is implied
+ * anyway, through the existence of the sequence files and their naming
+ * convention. Maybe we should trash this guy.
+ * 4) In the lw3d loader, when LwsObject encounters an object with the
+ * filename "..._sequence_
+ * 5) Each SequenceLine creates a Java3D group containing its objects. This
+ * is either a plain-old-Group (if there is only one object) or a Switch group
+ * with a SwitchValueInterpolator.
+ * 6) SequenceReader constructs a Switch group and adds all SequenceLine groups
+ * to this new group. It also creates a SwitchPathInterpolator (child of
+ * PathInterolator) that contsructs an Alpha based on the startFrame values of
+ * each SequenceLine. It creates a group and adds the SwitchPathInterpolator
+ * plus any SequenceLine SwitchValueInterpolators to this group.
+ * 7) LwsObject adds the SequenceReader Switch group to its objectTransform.
+ * It does a getBehaviors() from SequenceReader and adds the result (the
+ * SwitchPathInterpolator group) to its objectBehaviors group.
+ * 8) Done.
+ */
+
+class SequenceLine {
+
+ int startFrame;
+ int endFrame;
+ String fileName;
+
+ Group geometryGroup = null;
+ Behavior behaviors;
+ int numFrames;
+ float totalTime;
+ int totalFrames;
+
+ // storedRefList keeps references to already loaded objects
+ static Hashtable storedRefList = new Hashtable();
+
+ SequenceLine(StreamTokenizer st, float time, int frames)
+ throws ParsingErrorException {
+ try {
+ totalTime = time;
+ totalFrames = frames;
+ startFrame = (int)st.nval;
+ st.nextToken();
+ endFrame = (int)st.nval;
+ st.nextToken();
+ fileName = st.sval;
+ numFrames = endFrame - startFrame + 1;
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ }
+
+ /**
+ * Creates a SwitchValueInterpolator which is used to switch between
+ * the objects specified for the sequence. This is done for files
+ * that end in "000", meaning that there are a sequence of files
+ * with that same base name that should specify every frame of a
+ * sequence for an object. The Switch node is used to hold all of the
+ * files and the Switch Behavior node is used to activate switching
+ * at the right time and to the right object.
+ */
+ private void createSwitchBehavior(Switch target) {
+
+ int loopCount = -1;
+ float animTime = 1000.0f * totalTime *
+ (float)(target.numChildren())/(float)totalFrames;
+ float startTime = 1000f * totalTime *
+ (float)startFrame/(float)totalFrames;
+ Alpha theAlpha =
+ new Alpha(-1, (long)startTime, 0, (long)animTime, 0, 0);
+
+ SwitchValueInterpolator b=new SwitchValueInterpolator(theAlpha,target);
+ behaviors = b;
+ BoundingSphere bounds =
+ new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0);
+ b.setSchedulingBounds(bounds);
+ target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+ target.addChild(behaviors);
+
+ }
+
+ /**
+ * Create Java3d objects from the data in the sequence line. This
+ * means that for a tloop file (ends in "000"), we're going to create
+ * the appropriate geometry for each file, put them all in a Switch
+ * node, then create a SwitchValueInterpolator to swap between the
+ * frames of the tloop. If it's not a tloop, then we're just going to
+ * create the geometry for that file.
+ */
+ void createJava3dObjects(int debugVals, int loadBehaviors)
+ throws IncorrectFormatException, FileNotFoundException {
+ if (fileName.indexOf("000") != -1) { // Tloop
+ int index = fileName.indexOf("000");
+ String fileNameBase = fileName.substring(0, index);
+ Switch s = new Switch();
+ s.setCapability(Switch.ALLOW_SWITCH_READ);
+ s.setCapability(Switch.ALLOW_SWITCH_WRITE);
+ String tempFileName = fileName;
+ int fileNum = 0;
+ while ((new File(tempFileName)).exists()) {
+ if (storedRefList.get(tempFileName) != null) {
+ // System.out.println("retrieve stored version of " +
+ // tempFileName);
+ SharedGroup storedGroup =
+ (SharedGroup)storedRefList.get(tempFileName);
+ Link newLink = new Link(storedGroup);
+ s.addChild(newLink);
+ }
+ else {
+ // System.out.println("reading " + tempFileName);
+ J3dLwoParser objParser = new J3dLwoParser(tempFileName,
+ debugVals);
+ objParser.createJava3dGeometry();
+ TransformGroup t = new TransformGroup();
+ SharedGroup newSharedGroup = new SharedGroup();
+ storedRefList.put(tempFileName, newSharedGroup);
+ newSharedGroup.addChild(t);
+ Link newLink = new Link(newSharedGroup);
+ s.addChild(newLink);
+ if (objParser.getJava3dShapeList() != null) {
+ for (Enumeration e =
+ objParser.getJava3dShapeList().elements() ;
+ e.hasMoreElements() ;) {
+ t.addChild((Shape3D)e.nextElement());
+ }
+ }
+ }
+ ++fileNum;
+ String fileNumString = String.valueOf(fileNum);
+ if (fileNum < 10)
+ fileNumString = "00" + fileNumString;
+ else if (fileNum < 100)
+ fileNumString = "0" + fileNumString;
+ tempFileName = fileNameBase + fileNumString + ".lwo";
+ }
+ behaviors = null;
+ if (loadBehaviors != 0) {
+ createSwitchBehavior(s);
+ }
+ geometryGroup = (Group)s;
+ }
+ else {// Not a tloop, just a file
+ geometryGroup = new Group();
+ if (storedRefList.get(fileName) != null) {
+ // System.out.println("getting old ref to " + fileName);
+ SharedGroup storedGroup =
+ (SharedGroup)storedRefList.get(fileName);
+ Link newLink = new Link(storedGroup);
+ geometryGroup.addChild(newLink);
+ }
+ else {
+ // System.out.println("reading " + fileName);
+ J3dLwoParser objParser = new J3dLwoParser(fileName,
+ debugVals);
+ objParser.createJava3dGeometry();
+ TransformGroup t = new TransformGroup();
+ if (objParser.getJava3dShapeList() != null) {
+ for (Enumeration e = objParser.getJava3dShapeList().elements() ;
+ e.hasMoreElements() ;) {
+ t.addChild((Shape3D)e.nextElement());
+ }
+ }
+ SharedGroup newSharedGroup = new SharedGroup();
+ newSharedGroup.addChild(t);
+ Link newLink = new Link(newSharedGroup);
+ geometryGroup.addChild(newLink);
+ storedRefList.put(fileName, newSharedGroup);
+ }
+ }
+ }
+
+ Group getGeometry() {
+ return geometryGroup;
+ }
+
+ Behavior getBehavior() {
+ return behaviors;
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/SequenceReader.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/SequenceReader.java
new file mode 100644
index 0000000..c774918
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/SequenceReader.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.jogamp.java3d.Alpha;
+import org.jogamp.java3d.BoundingSphere;
+import org.jogamp.java3d.Switch;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.vecmath.Point3d;
+
+import org.jogamp.java3d.loaders.ParsingErrorException;
+
+/**
+ * This class was created to read a special file format devised for
+ * JavaOne '98 that allowed Tloop functionality inside of Lightwave. It
+ * would be best to find a more standard solution, including using some
+ * plug-in for lw3d that I've heard of that allows artists to automatically
+ * save out the geometry for a file at every frame.
+ */
+
+class SequenceReader {
+
+
+ Vector sequenceLines;
+ float totalTime;
+ int totalFrames;
+
+ TransformGroup objectTransform;
+ Vector behaviorVector;
+
+ /**
+ * Constructor: parses a sequence file and creates a new SequenceLine
+ * object to read in every line of the file
+ */
+ SequenceReader(String filename, float time, int frames)
+ throws ParsingErrorException {
+ totalTime = time;
+ totalFrames = frames;
+ sequenceLines = new Vector();
+ try {
+ // System.out.println("reading sequence from " + filename);
+ StreamTokenizer st = new StreamTokenizer(new BufferedReader(
+ new FileReader(filename)));
+ st.wordChars('_', '_');
+ st.wordChars('/', '/');
+ int type = st.nextToken();
+ while (st.ttype != StreamTokenizer.TT_EOF) {
+ sequenceLines.addElement(new SequenceLine(st,
+ totalTime,
+ totalFrames));
+ st.nextToken();
+ }
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ }
+
+ /**
+ * Creates Java3D objects from the data defined in the sequence
+ * file. Calls each sequenceLine object to create its own
+ * j3d objects, then puts all of those objects in a single Switch
+ * node. Finally, it creates a SwitchPathInterpolator object which
+ * handles switching between each object/s defined by each line
+ */
+ void createJava3dObjects(int debugVals, int loadBehaviors)
+ throws FileNotFoundException {
+
+ objectTransform = new TransformGroup();
+ behaviorVector = new Vector();
+ Enumeration e = sequenceLines.elements();
+ Switch switchNode = new Switch();
+ switchNode.setCapability(Switch.ALLOW_SWITCH_READ);
+ switchNode.setCapability(Switch.ALLOW_SWITCH_WRITE);
+ objectTransform.addChild(switchNode);
+ while (e.hasMoreElements()) {
+ SequenceLine line = (SequenceLine)e.nextElement();
+ line.createJava3dObjects(debugVals, loadBehaviors);
+ if (line.getGeometry() != null)
+ switchNode.addChild(line.getGeometry());
+ //objectTransform.addChild(line.getGeometry());
+ if (line.getBehavior() != null) {
+ behaviorVector.addElement(line.getBehavior());
+ }
+ }
+ float knots[] = new float[sequenceLines.size() + 1];
+ for (int i = 0; i < knots.length-1; ++i) {
+ SequenceLine sl = (SequenceLine)sequenceLines.elementAt(i);
+ knots[i] = (float)sl.startFrame/(float)totalFrames;
+ }
+ knots[knots.length-1] = 1.0f;
+ Alpha theAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE,
+ 0, 0, (long)(1000f * totalTime), 0,
+ 0, 0, 0, 0);
+
+ SwitchPathInterpolator switchPath =
+ new SwitchPathInterpolator(theAlpha,
+ knots,
+ switchNode);
+ BoundingSphere bounds =
+ new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000000.0);
+ switchPath.setSchedulingBounds(bounds);
+ switchNode.addChild(switchPath);
+ behaviorVector.addElement(switchPath);
+ }
+
+ TransformGroup getObjectNode() {
+ return objectTransform;
+ }
+
+ Vector getObjectBehaviors() {
+ return behaviorVector;
+ }
+
+ void printLines() {
+ Enumeration e = sequenceLines.elements();
+ while (e.hasMoreElements()) {
+ SequenceLine line = (SequenceLine)e.nextElement();
+ }
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/ShapeHolder.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/ShapeHolder.java
new file mode 100644
index 0000000..dac091d
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/ShapeHolder.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+import java.util.Vector;
+
+import org.jogamp.vecmath.Vector3f;
+
+
+/**
+ * This class holds all of the vertex/facet/normal/surface-reference
+ * data for a particular object. It has utilities to calculate facet normals,
+ * but this is no longer in use since using the new GeomInfo utilities.
+ */
+
+class ShapeHolder extends ParserObject {
+
+
+ Vector facetSizesList;
+ Vector facetIndicesList;
+ int facetIndicesArray[];
+ int currentNumIndices = 0;
+ int numSurf;
+ int numVerts;
+ int facetIndices[];
+ int facetSizes[];
+ int normalIndices[];
+ float normalCoords[];
+ float coordsArray[];
+
+ ShapeHolder() {
+ }
+
+ ShapeHolder(int debugVals) {
+ super(debugVals);
+ }
+
+
+ /**
+ * Print out (to stdout) the geometry data (coords, indices,
+ * and facet sizes). This is a debugging utility.
+ */
+ void printGeometryData(LwoSurface surface) {
+ int i, j;
+ int indicesIndex = 0;
+ System.out.println("\nPolygon Data:");
+ System.out.println(" Surface color = " + surface.color);
+ System.out.println(" Surface diffuse = " + surface.diffuseColor);
+ for (i = 0; i < facetSizes.length; ++i) {
+ int polySize = facetSizes[i];
+ System.out.println("Facet of size " + polySize);
+ for (j = 0; j < polySize; ++j) {
+ int coordIndex = 3 * facetIndices[indicesIndex++];
+ System.out.println("x, y, z = " +
+ coordsArray[coordIndex] + ", " +
+ coordsArray[coordIndex+1] + ", " +
+ coordsArray[coordIndex+2]);
+ }
+ }
+ }
+
+ /**
+ * Constructs geometry arrays given a winding rule (it turns out that
+ * lw3d winding is opposite of j3d winding, so this is always set to
+ * true in J3dLwoParser)
+ */
+ void createArrays(boolean reverseWinding) {
+ debugOutputLn(TRACE, "createArrays()");
+ // debugOutputLn(VALUES, "facetIndices, faceSizesList = " +
+ // facetIndicesList + facetSizesList);
+ //debugOutputLn(VALUES, "ind and sizes size " +
+ // facetIndicesList.size() + ", " +
+ // facetSizesList.size());
+ //facetIndices =
+ // new int[facetIndicesList.size()];
+ facetIndices = new int[currentNumIndices];
+ if (reverseWinding) {
+ int facetBeginIndex = 0;
+ for (int facetIndex = 0;
+ facetIndex < facetSizesList.size();
+ ++facetIndex) {
+ int currFaceSize =
+ ((Integer)facetSizesList.elementAt(facetIndex)).intValue();
+ int tempFace[] = new int[currFaceSize];
+ for (int j = 0; j < currFaceSize; ++j) {
+ facetIndices[facetBeginIndex + j] =
+ facetIndicesArray[facetBeginIndex +
+ currFaceSize - j - 1];
+ }
+ facetBeginIndex += currFaceSize;
+ }
+
+ }
+ else {
+ for (int i = 0; i < facetIndices.length; ++i) {
+ facetIndices[i] = facetIndicesArray[i];
+ }
+ }
+
+ debugOutputLn(LINE_TRACE, "facetIndices.len and coordsArray.len = " +
+ facetIndices.length + ", " + coordsArray.length);
+ if (((Integer)facetSizesList.elementAt(0)).intValue() < 3) {
+ // if we're dealing with point/line primitives, then let's abandon
+ // the indexed route and simply construct a new coordsArray
+ // that holds the direct values we need for a GeometryArray
+ // object
+ debugOutputLn(LINE_TRACE, "Using direct geometry because " +
+ "facetIndices is of size " +
+ facetIndices.length +
+ " and coordsArray is of length "+
+ coordsArray.length);
+ float newCoordsArray[] = new float[facetIndices.length * 3];
+ int newCoordsIndex = 0;
+ for (int i = 0; i < facetIndices.length; ++i) {
+ newCoordsArray[newCoordsIndex++] =
+ coordsArray[facetIndices[i]*3];
+ newCoordsArray[newCoordsIndex++] =
+ coordsArray[facetIndices[i]*3+1];
+ newCoordsArray[newCoordsIndex++] =
+ coordsArray[facetIndices[i]*3+2];
+ }
+ coordsArray = newCoordsArray;
+ facetIndices = null;
+ }
+
+ facetSizes =
+ new int[facetSizesList.size()];
+ for (int i = 0; i < facetSizes.length; ++i) {
+ facetSizes[i] =
+ ((Integer)facetSizesList.elementAt(i)).intValue();
+ }
+
+ facetSizesList = null; // Force garbage collection on Vectors
+ facetIndicesList = null;
+ facetIndicesArray = null;
+ }
+
+ /**
+ * Force gc on all array objects
+ */
+ void nullify() {
+ facetSizesList = null; // Force garbage collection on everything
+ facetIndicesList = null;
+ facetIndicesArray = null;
+ facetSizes = null;
+ facetIndices = null;
+ normalCoords = null;
+ normalIndices = null;
+ }
+
+ /**
+ * This method calculates facet normals for the geometry. It is no
+ * longer used, as we're now using the GeometryInfo utility to calculate
+ * smooth normals
+ */
+ void calcNormals() {
+ debugOutputLn(TRACE, "calcNormals()");
+ debugOutputLn(LINE_TRACE, "coordsLength, facetsizes.len = " +
+ coordsArray.length + ", " + facetSizes.length);
+ if (facetSizes[0] > 2) {
+ // points and lines don't need normals, polys do
+ if (facetIndices != null) {
+ normalIndices = new int[facetIndices.length];
+ normalCoords = new float[facetIndices.length * 3];
+ }
+ else {
+ normalCoords = new float[coordsArray.length];
+ }
+ debugOutputLn(LINE_TRACE, "normalCoords, incides len = " +
+ normalCoords.length + ", " +
+ ((facetIndices == null) ? 0 : normalIndices.length));
+ int facetIndex = 0;
+ int tempIndex = -1;
+ for (int i = 0; i < facetSizes.length; i += 1) {
+ Vector3f norm;
+ int currFacetSize = facetSizes[i];
+ //debugOutputLn(LINE_TRACE, " i, facetIndex, currSize = " +
+ // i + ", " + facetIndex + ", " + currFacetSize);
+ if (currFacetSize < 3) {
+ // This shouldn't occur
+ norm = new Vector3f(0f, 0f, 1f);
+ }
+ else {
+ Vector3f v1, v2;
+ int index1, index2, index3;
+ if (facetIndices != null) {
+ index1 = facetIndices[facetIndex];
+ index2 = facetIndices[facetIndex+1];
+ index3 = facetIndices[facetIndex+2];
+ //debugOutputLn(VALUES, " index123 = " +
+ // index1 + ", " + index2 + ", " + index3);
+ }
+ else {
+ index1 = facetIndex;
+ index2 = facetIndex+1;
+ index3 = facetIndex+2;
+ }
+ v1 = new
+ Vector3f(coordsArray[index2*3] - coordsArray[index1*3],
+ coordsArray[index2*3+1] - coordsArray[index1*3+1],
+ coordsArray[index2*3+2] - coordsArray[index1*3+2]);
+ v2 = new
+ Vector3f(coordsArray[index3*3] - coordsArray[index1*3],
+ coordsArray[index3*3+1] - coordsArray[index1*3+1],
+ coordsArray[index3*3+2] - coordsArray[index1*3+2]);
+ //debugOutputLn(VALUES, "v1, v2 = " + v1 + v2);
+ norm = new Vector3f();
+ norm.cross(v1, v2);
+ norm.normalize(norm);
+ }
+
+ for (int j = 0; j < currFacetSize; ++j) {
+ int normIndex = facetIndex + j;
+ normalCoords[normIndex*3] = norm.x;
+ normalCoords[normIndex*3+1] = norm.y;
+ normalCoords[normIndex*3+2] = norm.z;
+ if (facetIndices != null)
+ normalIndices[normIndex] = normIndex;
+ }
+ facetIndex += currFacetSize;
+ }
+ }
+ debugOutputLn(TRACE, "done with calcNormals()");
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/SwitchPathInterpolator.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/SwitchPathInterpolator.java
new file mode 100644
index 0000000..218ebbf
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/SwitchPathInterpolator.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+ package org.jogamp.java3d.loaders.lw3d;
+
+
+import java.util.Enumeration;
+
+import org.jogamp.java3d.Alpha;
+import org.jogamp.java3d.Switch;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+/**
+ * This class was used in conjunction with SequenceReader to create
+ * Tloop functionality inside of Lightwave files. This behavior handles
+ * the switching between objects defined in separate lines of a
+ * sequence file. That is, each line in a sequence file has the name
+ * of an object (or an object sequence, if the name ends in "000")
+ * and details the start and end frames that that object should be active.
+ * This class determines which object/s defined in the file should be active
+ * at any given time during the animation.
+ */
+
+class SwitchPathInterpolator extends FloatValueInterpolator {
+
+ Switch target;
+ int firstSwitchIndex;
+ int lastSwitchIndex;
+ int currentChild;
+ int childCount;
+
+ /**
+ * Constructs a new SwitchPathInterpolator object.
+ * @param alpha the alpha object for this interpolator
+ * @param knots an array of knot values that specify a spline
+ */
+ SwitchPathInterpolator(Alpha alpha, float knots[], Switch target) {
+
+ super(alpha, knots, new float[knots.length]);
+
+ if (knots.length != (target.numChildren() + 1))
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("SwitchPathInterpolator0"));
+
+ this.target = target;
+ firstSwitchIndex = 0;
+ lastSwitchIndex = target.numChildren() - 1;
+ childCount = lastSwitchIndex + 1;
+ }
+
+ /**
+ * This method sets the correct child for the Switch node according
+ * to alpha
+ * @param criteria enumeration of criteria that have triggered this wakeup
+ */
+
+ @Override
+ public void processStimulus(Enumeration criteria) {
+
+ int child;
+
+ // Handle stimulus
+ if (this.getAlpha() != null) {
+
+ // Let PathInterpolator calculate the correct
+ // interpolated knot point
+ computePathInterpolation();
+
+ if (currentKnotIndex > 0)
+ child = currentKnotIndex - 1;
+ else
+ child = 0;
+
+ if (target.getWhichChild() != child) {
+ target.setWhichChild(child);
+ }
+
+ if ((this.getAlpha()).finished())
+ return;
+ }
+
+ wakeupOn(defaultWakeupCriterion);
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/TargaReader.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/TargaReader.java
new file mode 100644
index 0000000..55232a6
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/TargaReader.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import org.jogamp.java3d.loaders.IncorrectFormatException;
+import org.jogamp.java3d.loaders.ParsingErrorException;
+
+/**
+ * This class parses a standard Targa file and retrieves the image stored
+ * therein, storing the pixel data in a BufferedImage.
+ */
+
+class TargaReader extends ParserObject {
+
+ BufferedInputStream bufferedReader;
+ Image theImage = null;
+
+ /**
+ * Constructor: creates file reader and calls parseFile() to do the real
+ * work
+ */
+ TargaReader(String fileName, int debugVals) throws FileNotFoundException {
+ super(debugVals);
+ debugOutputLn(TRACE, "constructor");
+ bufferedReader = new BufferedInputStream(
+ new DataInputStream(new FileInputStream(fileName)));
+ if (bufferedReader != null)
+ parseFile();
+ }
+
+ /**
+ * Returns the image that was created from parsing the targa file (null
+ * if the file reading failed)
+ */
+ Image getImage() {
+ return theImage;
+ }
+
+ /**
+ * This method parses the file and stores the pixel data in a
+ * BufferedImage. The basic file format is:
+ * Byte Description
+ *
+ * 0 Image ID Length
+ * 1 Colormap type
+ * 2 Image Type
+ * 3-4 Colormap spec: 1st entry index
+ * 5-6 Colormap spec: length
+ * 7 Colormap spec: entry size
+ * 8-9 X-origin of lower-left corner
+ * 10-11 Y-origin of lower-left corner
+ * 12-13 Image width
+ * 14-15 Image height
+ * 16 Pixel depth
+ * 17 00(origin)(alpha)
+ * first 2 bytes 0, next 2 starting corner,
+ * last four number of overlay bits per pixel
+ * 18- Image ID
+ * ?? Colormap data
+ * ?? Image Data
+ * ?? Developer Area
+ * ?? Extension Area
+ * ?? File Footer
+ *
+ * We're going to make some assumptions about the format of files we're
+ * asked to load. In particular, we're not going to do any colormpa-based
+ * images: the images need to be either 24-bit or 32-bit true color.
+ * We're also going to ignore vaiours parameters in the header block, since
+ * they complicate life and don't appear to be used in Lightwave image
+ * files. In particular, the following fields will be ignored:
+ * Image ID, colormap info, xy origins, and alpha/overlay bits.
+ */
+
+ void parseFile()
+ throws IncorrectFormatException, ParsingErrorException {
+ try {
+ int idLength = bufferedReader.read();
+ int colormapPresent = bufferedReader.read();
+ int imageType = bufferedReader.read();
+ bufferedReader.skip(9); // skipping camp and xy origin data
+ int width = bufferedReader.read() | bufferedReader.read() << 8;
+ int height = bufferedReader.read() | bufferedReader.read() << 8;
+ int depth = bufferedReader.read();
+ int flags = bufferedReader.read();
+ boolean bottomToTop = ((flags & 0x20) == 0);
+ boolean leftToRight = ((flags & 0x10) == 0);
+ bufferedReader.skip(idLength);
+
+ // Check on the file parameters to see whether we should punt
+ if ((colormapPresent == 1) ||
+ imageType != 2 ||
+ (depth != 24 &&
+ depth != 32)) {
+ // Punt
+ throw new IncorrectFormatException(
+ "This format is not readable by the Lightwave " +
+ "loader. Only 24- or 32-bit true-color " +
+ "uncompressed Targa images will work");
+ }
+
+ // Image format must be okay for us to read
+ BufferedImage bImage =
+ new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ int[] imageBits =
+ ((DataBufferInt)bImage.getRaster().getDataBuffer()).getData();
+
+ int row;
+ int column;
+
+ for (int i = 0; i < height; ++i) {
+ if (bottomToTop)
+ row = (height - i - 1);
+ else
+ row = i;
+ for (int j = 0; j < width; ++j) {
+
+ if (leftToRight)
+ column = j;
+ else
+ column = (width - j - 1);
+
+ int blue = bufferedReader.read();
+ int green = bufferedReader.read();
+ int red = bufferedReader.read();
+ int alpha = 0xff;
+ if (depth == 32)
+ alpha = bufferedReader.read();
+ imageBits[row*width + column] = alpha << 24 |
+ red << 16 |
+ green << 8 |
+ blue;
+ }
+ }
+ theImage = bImage;
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ }
+
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/TextfileParser.java b/src/classes/share/org/jogamp/java3d/loaders/lw3d/TextfileParser.java
new file mode 100644
index 0000000..6cbf522
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/TextfileParser.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.loaders.lw3d;
+
+import java.io.IOException;
+import java.io.StreamTokenizer;
+
+import org.jogamp.java3d.loaders.ParsingErrorException;
+
+/**
+ * This class is a superclass for most of the Lws* Scene-file parsing
+ * classes. It provides some debugging utilities, as well as utilities for
+ * reading the types of data common to this loader.
+ */
+
+class TextfileParser {
+
+ // class variables
+ static int WORD = StreamTokenizer.TT_WORD;
+ static int NUMBER = StreamTokenizer.TT_NUMBER;
+ int currentLevel = 3;
+ final static int TRACE = DebugOutput.TRACE, VALUES = DebugOutput.VALUES;
+ final static int MISC = DebugOutput.MISC, LINE_TRACE = DebugOutput.LINE_TRACE;
+ final static int NONE = DebugOutput.NONE, EXCEPTION = DebugOutput.EXCEPTION;
+ final static int TIME = DebugOutput.TIME;
+ protected DebugOutput debugPrinter;
+ char lineSeparatorChar = 0;
+
+ TextfileParser() {
+ debugPrinter = new DebugOutput(EXCEPTION);
+ String lineSeparator = System.getProperty("line.separator");
+ lineSeparatorChar = lineSeparator.charAt(0);
+ debugOutputLn(VALUES, "lineSeparatorChar = " + (int)lineSeparatorChar);
+ }
+
+
+ protected void debugOutputLn(int outputType, String theOutput) {
+ if (theOutput.equals(""))
+ debugPrinter.println(outputType, theOutput);
+ else {
+ debugPrinter.println(outputType,
+ getClass().getName() + "::" + theOutput);
+ }
+ }
+
+ protected void debugOutput(int outputType, String theOutput) {
+ debugPrinter.print(outputType, theOutput);
+ }
+
+ /**
+ * Utility method to advance the tokenizer until we see the given
+ * string. This is used to skip by various parameters that we
+ * currently ignore in the loader.
+ */
+ void skipUntilString(StreamTokenizer st, String theString)
+ throws ParsingErrorException {
+ boolean done = false;
+ try {
+ while (!done) {
+ st.nextToken();
+ if (st.ttype == WORD &&
+ st.sval.equals(theString))
+ done = true;
+ }
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ }
+
+
+ /**
+ * Returns number from the tokenizer. Note that we don't recognize
+ * numbers in the tokenizer automatically because numbers might be in
+ * scientific notation, which isn't processed correctly by
+ * StreamTokenizer
+ */
+ double getNumber(StreamTokenizer st)
+ throws ParsingErrorException, NumberFormatException {
+ try {
+ int token = st.nextToken();
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ checkType(st, WORD);
+ return ((Double.valueOf(st.sval)).doubleValue());
+ }
+
+ /**
+ * Returns String from the tokenizer
+ */
+ String getString(StreamTokenizer st) throws ParsingErrorException {
+ try {
+ st.nextToken();
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ checkType(st, WORD);
+ return (st.sval);
+ }
+
+ /**
+ * Returns a "name" from the stream. This is different from simply a
+ * String because the name could contain whitespace characters
+ * (such as "object 1" or "objectname (sequence)") that would confuse
+ * the string parser. So we just grab all characters until EOL and
+ * concatenate them together to form the name
+ */
+ String getName(StreamTokenizer st) throws ParsingErrorException {
+ String theName = "";
+ st.ordinaryChar(lineSeparatorChar);
+ st.ordinaryChar('\n');
+ st.ordinaryChar('\r');
+ try {
+ st.nextToken();
+ while (st.ttype != lineSeparatorChar &&
+ st.ttype != '\r' &&
+ st.ttype != '\n') {
+ if (st.ttype != '(' &&
+ st.ttype != ')')
+ theName += st.sval;
+ st.nextToken();
+ }
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ st.whitespaceChars(lineSeparatorChar, lineSeparatorChar);
+ st.whitespaceChars('\n', '\n');
+ st.whitespaceChars('\r', '\r');
+ debugOutputLn(VALUES, "name = " + theName);
+ return theName;
+ }
+
+ /**
+ * Gets the next token and ensures that it is the string we were
+ * expecting to see
+ */
+ void getAndCheckString(StreamTokenizer st, String expectedValue)
+ throws ParsingErrorException {
+ try {
+ st.nextToken();
+ checkString(st, expectedValue);
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ }
+
+ /**
+ * Error checking routine - makes sure the current token is the string
+ * we were expecting
+ */
+ void checkString(StreamTokenizer st, String theString) throws
+ ParsingErrorException {
+ if (!(st.ttype == StreamTokenizer.TT_WORD) ||
+ !st.sval.equals(theString))
+ throw new ParsingErrorException(
+ "Bad String Token (wanted " + theString + ", got " + st.sval +
+ ": " + st.toString());
+ }
+
+ /**
+ * Error checking routine - makes sure the current token is of the right
+ * type
+ */
+ void checkType(StreamTokenizer st, int theType)
+ throws ParsingErrorException {
+ if (!(st.ttype == theType))
+ throw new ParsingErrorException(
+ "Bad Type Token, Expected " + theType + " and received" +
+ st.ttype);
+ }
+
+ /**
+ * Utility routine - gets next token, checks it against our expectation,
+ * then skips a given number of tokens. This can be used to parse
+ * through (and ignore) certain parameter/value sets in the files
+ */
+ void skip(StreamTokenizer st, String tokenString, int skipVals)
+ throws ParsingErrorException {
+ try {
+ st.nextToken();
+ checkString(st, tokenString);
+ for (int i = 0; i < skipVals; ++i) {
+ st.nextToken();
+ }
+ }
+ catch (IOException e) {
+ throw new ParsingErrorException(e.getMessage());
+ }
+ }
+
+ /**
+ * Utility method- used to check whether the current token is equal
+ * to the given string
+ */
+ boolean isCurrentToken(StreamTokenizer st, String tokenString) {
+ if (st.ttype == WORD)
+ return (st.sval.equals(tokenString));
+ return false;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/loaders/lw3d/package.html b/src/classes/share/org/jogamp/java3d/loaders/lw3d/package.html
new file mode 100644
index 0000000..241bf5b
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/loaders/lw3d/package.html
@@ -0,0 +1,11 @@
+
+
+
+
+ v float float float
vn float float float
+ * vt float float
+ * f int int int . . .
+ * f int/int int/int int/int . . .
+ * f int/int/int int/int/int int/int/int . . .
+ * g name
+ * s int
+ * s off
+ * usemtl name
+ * + * amber amber_trans aqua aqua_filter + * archwhite archwhite2 bflesh black + * blondhair blue_pure bluegrey bluetint + * blugrn blutan bluteal bone + * bone1 bone2 brass brnhair + * bronze brown brownlips brownskn + * brzskin chappie charcoal deepgreen + * default dkblue dkblue_pure dkbrown + * dkdkgrey dkgreen dkgrey dkorange + * dkpurple dkred dkteal emerald + * fgreen flaqua flblack flblonde + * flblue_pure flbrown fldkblue_pure fldkdkgrey + * fldkgreen fldkgreen2 fldkgrey fldkolivegreen + * fldkpurple fldkred flesh fleshtransparent + * flgrey fllime flltbrown flltgrey + * flltolivegreen flmintgreen flmustard florange + * flpinegreen flpurple flred fltan + * flwhite flwhite1 flyellow glass + * glassblutint glasstransparent gold green + * greenskn grey hair iris + * jetflame lavendar lcdgreen lighttan + * lighttan2 lighttan3 lighttannew lightyellow + * lime lips ltbrown ltgrey + * meh metal mintgrn muscle + * navy_blue offwhite.cool offwhite.warm olivegreen + * orange pale_green pale_pink pale_yellow + * peach periwinkle pink pinktan + * plasma purple red redbrick + * redbrown redorange redwood rubber + * ruby sand_stone sapphire shadow + * ship2 silver skin sky_blue + * smoked_glass tan taupe teeth + * violet white yellow yellow_green + * yellowbrt yelloworng + *+ *
mtllib filename
+ * newmtl name
+ * Ka float float float
+ * Kd float float float
+ * Ks float float float
+ * illum (0, 1, or 2)
+ * Ns float
+ * map_Kd filename
+ * Provides a Java 3D loader for Wavefront .obj files.
+ + diff --git a/src/classes/share/org/jogamp/java3d/loaders/package.html b/src/classes/share/org/jogamp/java3d/loaders/package.html new file mode 100644 index 0000000..c7a9f12 --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/loaders/package.html @@ -0,0 +1,11 @@ + + + + +Provides interfaces and abstract classes for writing Java 3D loaders.
+ + diff --git a/src/classes/share/org/jogamp/java3d/utils/applet/JMainFrame.java b/src/classes/share/org/jogamp/java3d/utils/applet/JMainFrame.java new file mode 100644 index 0000000..80270d6 --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/applet/JMainFrame.java @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +// JMainFrame - run an Applet as an application +// +// Copyright (C) 1996 by Jef Poskanzer+// Using this class you can add a trivial main program to any Applet +// and run it directly, as well as from a browser or the appletviewer. +// And unlike some versions of this concept, MainFrame implements both +// images and sound. +//
+// Sample main program: +//
+// The only methods you need to know about are the constructors. +//+// public static void main( String[] args ) +// { +// new Acme.MainFrame( new ThisApplet(), args, 400, 400 ); +// } +//
+// You can specify Applet parameters on the command line, as name=value. +// For instance, the equivalent of: +//
+// would just be: +//+// <PARAM NAME="pause" VALUE="200"> +//
+// You can also specify three special parameters: +//+// pause=200 +//
+//+// width=N Width of the Applet. +// height=N Height of the Applet. +// barebones=true Leave off the menu bar and status area. +//
+// Fetch the software.
+// Fetch the entire Acme package.
+
+public class MainFrame extends Frame implements
+ Runnable, AppletStub, AppletContext
+{
+
+ private String[] args = null;
+ private static int instances = 0;
+ private String name;
+ private boolean barebones = true;
+ private Applet applet;
+ private Label label = null;
+ private Dimension appletSize;
+
+ private static final String PARAM_PROP_PREFIX = "parameter.";
+
+ /// Constructor with everything specified.
+ public MainFrame(Applet applet, String[] args,
+ int width, int height) {
+ build(applet, args, width, height);
+ }
+
+ /// Constructor with no default width/height.
+ public MainFrame(Applet applet, String[] args ) {
+ build(applet, args, -1, -1);
+ }
+
+ /// Constructor with no arg parsing.
+ public MainFrame(Applet applet, int width, int height) {
+ build( applet, null, width, height );
+ }
+
+ // Internal constructor routine.
+ private void build( Applet applet, String[] args,
+ int width, int height) {
+ ++instances;
+ this.applet = applet;
+ this.args = args;
+ applet.setStub( this );
+ name = applet.getClass().getName();
+ setTitle( name );
+
+ // Set up properties.
+ Properties props = System.getProperties();
+ props.put( "browser", "Acme.MainFrame" );
+ props.put( "browser.version", "11jul96" );
+ props.put( "browser.vendor", "Acme Laboratories" );
+ props.put( "browser.vendor.url", "http://www.acme.com/" );
+
+ // Turn args into parameters by way of the properties list.
+ if ( args != null )
+ parseArgs( args, props );
+
+ // If width and height are specified in the parameters, override
+ // the compiled-in values.
+ String widthStr = getParameter( "width" );
+ if ( widthStr != null ) {
+ width = Integer.parseInt( widthStr );
+ }
+
+ String heightStr = getParameter( "height" );
+ if ( heightStr != null ) {
+ height = Integer.parseInt( heightStr );
+ }
+
+ // Were width and height specified somewhere?
+ if ((width == -1) || (height == -1)) {
+ System.err.println( "Width and height must be specified." );
+ return;
+ }
+
+ // Do we want to run bare-bones?
+ String bonesStr = getParameter( "barebones" );
+ if ((bonesStr != null) && bonesStr.equals( "true" )) {
+ barebones = true;
+ }
+
+ // Lay out components.
+ setLayout( new BorderLayout() );
+ add( "Center", applet );
+
+ // Set up size.
+ pack();
+ validate();
+ appletSize = applet.getSize();
+ applet.setSize( width, height );
+ setVisible(true);
+
+
+ /*
+ Added WindowListener inner class to detect close events.
+ */
+ SecurityManager sm = System.getSecurityManager();
+ boolean doExit = true;
+
+ if (sm != null) {
+ try {
+ sm.checkExit(0);
+ } catch (SecurityException e) {
+ doExit = false;
+ }
+ }
+
+ final boolean _doExit = doExit;
+
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent winEvent) {
+ if (MainFrame.this.applet != null) {
+ MainFrame.this.applet.destroy();
+ }
+ Window w = winEvent.getWindow();
+ w.hide();
+ try {
+ w.dispose();
+ } catch (IllegalStateException e) {}
+
+ if (_doExit) {
+ System.exit(0);
+ }
+ }
+ });
+
+ // Start a separate thread to call the applet's init() and start()
+ // methods, in case they take a long time.
+ (new Thread( this )).start();
+ }
+
+ // Turn command-line arguments into Applet parameters, by way of the
+ // properties list.
+ private static void parseArgs( String[] args, Properties props) {
+ String arg;
+
+ for (int i = 0; i < args.length; ++i) {
+ arg = args[i];
+ int ind = arg.indexOf( '=' );
+ if ( ind == -1 ) {
+ props.put(PARAM_PROP_PREFIX + arg.toLowerCase(), "" );
+ } else {
+ props.put(PARAM_PROP_PREFIX + arg.substring( 0, ind ).toLowerCase(),
+ arg.substring( ind + 1 ) );
+ }
+ }
+ }
+
+ // Methods from Runnable.
+
+ /// Separate thread to call the applet's init() and start() methods.
+ @Override
+ public void run() {
+ showStatus( name + " initializing..." );
+ applet.init();
+ validate();
+ showStatus( name + " starting..." );
+ applet.start();
+ validate();
+ showStatus( name + " running..." );
+ }
+
+
+ // Methods from AppletStub.
+ @Override
+ public boolean isActive() {
+ return true;
+ }
+
+ @Override
+ public URL getDocumentBase() {
+ // Returns the current directory.
+ String dir = System.getProperty( "user.dir" );
+ String urlDir = dir.replace( File.separatorChar, '/' );
+ try {
+ return new URL( "file:" + urlDir + "/");
+ } catch ( MalformedURLException e ) {
+ return null;
+ }
+ }
+
+ @Override
+ public URL getCodeBase() {
+ // Hack: loop through each item in CLASSPATH, checking if
+ // the appropriately named .class file exists there. But
+ // this doesn't account for .zip files.
+ String path = System.getProperty( "java.class.path" );
+ Enumeration st = new StringTokenizer( path, ":" );
+ while ( st.hasMoreElements() ) {
+ String dir = (String) st.nextElement();
+ String filename = dir + File.separatorChar + name + ".class";
+ File file = new File( filename );
+ if (file.exists()) {
+ String urlDir = dir.replace( File.separatorChar, '/' );
+ try {
+ return new URL( "file:" + urlDir + "/" );
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getParameter(String name) {
+ // Return a parameter via the munged names in the properties list.
+ return System.getProperty( PARAM_PROP_PREFIX + name.toLowerCase() );
+ }
+
+ @Override
+ public void appletResize(int width, int height) {
+ // Change the frame's size by the same amount that the applet's
+ // size is changing.
+ Dimension frameSize = getSize();
+ frameSize.width += width - appletSize.width;
+ frameSize.height += height - appletSize.height;
+ setSize( frameSize );
+ appletSize = applet.getSize();
+ }
+
+ @Override
+ public AppletContext getAppletContext() {
+ return this;
+ }
+
+
+ // Methods from AppletContext.
+ @Override
+ public AudioClip getAudioClip( URL url ) {
+ // This is an internal undocumented routine. However, it
+ // also provides needed functionality not otherwise available.
+ // I suspect that in a future release, JavaSoft will add an
+ // audio content handler which encapsulates this, and then
+ // we can just do a getContent just like for images.
+ return new sun.applet.AppletAudioClip( url );
+ }
+
+ @Override
+ public Image getImage( URL url ) {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ try {
+ ImageProducer prod = (ImageProducer) url.getContent();
+ return tk.createImage( prod );
+ } catch ( IOException e ) {
+ return null;
+ }
+ }
+
+ @Override
+ public Applet getApplet(String name) {
+ // Returns this Applet or nothing.
+ if (name.equals( this.name )) {
+ return applet;
+ }
+ return null;
+ }
+
+ @Override
+ public Enumeration getApplets() {
+ // Just yields this applet.
+ Vector v = new Vector();
+ v.addElement( applet );
+ return v.elements();
+ }
+
+ @Override
+ public void showDocument( URL url ) {
+ // Ignore.
+ }
+
+ @Override
+ public void showDocument( URL url, String target ) {
+ // Ignore.
+ }
+
+ @Override
+ public void showStatus( String status ) {
+ if (label != null) {
+ label.setText(status);
+ }
+ }
+
+ @Override
+ public void setStream( String key, java.io.InputStream stream ) {
+ throw new RuntimeException("Not Implemented");
+ // TODO implement setStream method
+ }
+
+ @Override
+ public java.io.InputStream getStream( String key ) {
+ throw new RuntimeException("Not Implemented");
+ // TODO implement getStream method
+ }
+
+ @Override
+ public java.util.Iterator getStreamKeys() {
+ throw new RuntimeException("Not Implemented");
+ // TODO implement getStreamKeys method
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/applet/package.html b/src/classes/share/org/jogamp/java3d/utils/applet/package.html
new file mode 100644
index 0000000..17fd1b1
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/applet/package.html
@@ -0,0 +1,12 @@
+
+
+
Provides utility classes for running applets as stand-alone +applications.
+ + diff --git a/src/classes/share/org/jogamp/java3d/utils/audio/DistanceAttenuation.java b/src/classes/share/org/jogamp/java3d/utils/audio/DistanceAttenuation.java new file mode 100644 index 0000000..8f14ff2 --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/audio/DistanceAttenuation.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + + /* + * Sound Distance Attenuation utilities + * + * Various methods to create PointSound and ConeSound distance attenuation + * arrays. + */ + +package org.jogamp.java3d.utils.audio; + +import org.jogamp.java3d.SoundException; +import org.jogamp.vecmath.Point2f; + +import org.jogamp.java3d.internal.J3dUtilsI18N; + +public class DistanceAttenuation +{ + // private fields + + // public fields + /** + * Equation types + */ + static final int DOUBLE_DISTANCE_HALF_GAIN = 1; + + // methods + /** + * Fill a Distance Attenuation array + * + * recommend that the distance attenuation Point2f array is defined to + * be allocated to be 10 for DOUBLE_DISTANCE_HALF_GAIN - since 1/(2^10) + * exceeds 1/1000 scale that is agreed to be affective zero gain + * + * First method assumes that: + * type is half gain for every double of distance + * inner radius is 0.0 but region between 0th and 1st elements is constant + * since gains for these two elements are the same + * min gain approches zero. + */ + public void fillDistanceAttenuation( + float unitDistance, float unitGain, + Point2f[] distanceAttenuation ) { + if (distanceAttenuation == null) + throw new SoundException(J3dUtilsI18N.getString("DistanceAttenuation0")); + + int length = distanceAttenuation.length; + distanceAttenuation[0].x = 0.0f; + distanceAttenuation[0].y = unitGain; + float nextDistance = unitDistance; + float nextGain = unitGain; + + for (int i=1; iProvides audio utility classes.
+ + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/CubicSplineCurve.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/CubicSplineCurve.java new file mode 100644 index 0000000..6854c7f --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/CubicSplineCurve.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.interpolators; + +import org.jogamp.java3d.internal.J3dUtilsI18N; + +/** + * CubicSplineCurve is a container class that holds a number of + * cubicSplineSegments + * + * @since Java3D 1.1 + */ + +public class CubicSplineCurve { + + private float totalCurveLength; + private CubicSplineSegment[] cubicSplineSegment; + public int numSegments; + + + /** + * Default constructor + */ + CubicSplineCurve () { + numSegments = 0; + totalCurveLength = 0f; + } + + /** + * This method takes a list of key frames and creates spline segments + * from it. It requires at least four key frames to be passed to it. + * Given n key frames, it creates n-3 CubicSplineSegments. + * @param keys the list of key frames that specify the motion path + */ + + CubicSplineCurve (TCBKeyFrame keys[]) { + + int keyLength = keys.length; + // Require at least 4 key frames for cubic spline curve + if (keyLength < 4) + throw new IllegalArgumentException(J3dUtilsI18N.getString("CubicSplineCurve0")); + + numSegments = keyLength - 3; + this.cubicSplineSegment = new CubicSplineSegment[numSegments]; + + // intialize and calculate coefficients for each segment + int k0 = 0; int k1 = 1; int k2 = 2; int k3 = 3; + for (; k0 < numSegments; k0++, k1++, k2++, k3++) { + this.cubicSplineSegment[k0] = new CubicSplineSegment + (keys[k0], keys[k1], keys[k2], keys[k3]); + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method takes a list of spline segments creates the + * CubicSplineCurve. + * @param the list of segments that comprise the complete motion path + */ + + CubicSplineCurve (CubicSplineSegment s[]) { + + cubicSplineSegment = new CubicSplineSegment[s.length]; + numSegments = cubicSplineSegment.length; + for (int i = 0; i < numSegments; i++) { + this.cubicSplineSegment[i] = s[i]; + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method takes a list of spline segments to replace the existing + * set of CubicSplineSegments that comprise the current CubicSplineCurve + * motion path. + * @param s the list of segments that comprise the complete motion path + */ + + public void setSegments (CubicSplineSegment s[]) { + + cubicSplineSegment = new CubicSplineSegment[s.length]; + numSegments = cubicSplineSegment.length; + for (int i = 0; i < numSegments; i++) { + this.cubicSplineSegment[i] = s[i]; + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method returns the CubicSplineSegments pointed to by index + * @param index the index of the CubicSplineSegment required + * @return index the CubicSplineSegment pointed to by index + */ + public CubicSplineSegment getSegment (int index) { + + return this.cubicSplineSegment[index]; + + } + + + // computes the total length of the curve + private void computeTotalCurveLength () { + + totalCurveLength = 0f; + for (int i = 0; i < numSegments; i++) { + totalCurveLength += cubicSplineSegment[i].length; + } + + } + + /** + * This method returns the total length of the entire CubicSplineCurve + * motion path. + * + * @return the length of the CubicSplineCurve motion path + */ + + public float getTotalCurveLength () { + + return this.totalCurveLength; + + } + +} + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/CubicSplineSegment.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/CubicSplineSegment.java new file mode 100644 index 0000000..6330474 --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/CubicSplineSegment.java @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.interpolators; + +import org.jogamp.vecmath.Point3f; +import org.jogamp.vecmath.Quat4f; +import org.jogamp.vecmath.Vector3f; + + +/** + * The CubicSplineSegment class creates the representation of a + * TCB (Kochanek-Bartels Spline). This class takes 4 key frames as + * its input (using TCBKeyFrame). If interpolating between the ith + * and (i+1)th key frame then the four key frames that need to + * be specified are the (i-1)th, ith, (i+1)th + * and (i+2)th keyframes in order. The CubicSegmentClass + * then pre-computes the hermite interpolation basis coefficients if the + * (i+1)th frame has the linear flag set to zero. These are used to + * calculate the interpolated position, scale and quaternions when they + * requested by the user using the getInterpolated* methods. If the the + * (i+1)th frame's linear flag is set to 1 then the class uses + * linear interpolation to calculate the interpolated position, sccale and + * quaternions it returns through the getInterpolated* methods. + * + * @since Java3D 1.1 + */ + +public class CubicSplineSegment { + + // Legendre polynomial information for Gaussian quadrature of speed + // for the domain [0,u], 0 <= u <= 1. + + // Legendre roots mapped to (root+1)/2 + static final double modRoot[] = + { + 0.046910077, + 0.230765345, + 0.5, + 0.769234655, + 0.953089922 + }; + + // original coefficients divided by 2 + static final double modCoeff[] = + { + 0.118463442, + 0.239314335, + 0.284444444, + 0.239314335, + 0.118463442 + }; + + // Key Frames + TCBKeyFrame[] keyFrame = new TCBKeyFrame[4]; + + // H.C + Point3f c0, c1, c2, c3; // coefficients for position + Point3f e0, e1, e2, e3; // coefficients for scale + + // variables for destination derivative + float one_minus_t_in; + float one_minus_c_in; + float one_minus_b_in; + float one_plus_c_in; + float one_plus_b_in; + float ddb; + float dda; + + // variables for source derivative + float one_minus_t_out; + float one_minus_c_out; + float one_minus_b_out; + float one_plus_c_out; + float one_plus_b_out; + float dsb; + float dsa; + + // Length of the spline segment + float length; + + // interpolation type + int linear; + + /** + * Default constructor + */ + CubicSplineSegment () { + + length = 0; + + } + + /** + * Creates a cubic spline segment between two key frames using the + * key frames provided. If creating a spline between the ith frame and + * the (i+1)th frame then send down the (i - 1)th, + * ith , (i+1)th and the (i+2)th key + * frames. + * + * @param kf0 (i - 1)th Key Frame + * @param kf1 ith Key Frame + * @param kf2 (i + 1)th Key Frame + * @param kf3 (i + 2)th Key Frame + */ + + CubicSplineSegment (TCBKeyFrame kf0, TCBKeyFrame kf1, TCBKeyFrame kf2, + TCBKeyFrame kf3) { + + // Copy KeyFrame information + keyFrame[0] = new TCBKeyFrame(kf0); + keyFrame[1] = new TCBKeyFrame(kf1); + keyFrame[2] = new TCBKeyFrame(kf2); + keyFrame[3] = new TCBKeyFrame(kf3); + + // if linear interpolation is requested then just set linear flag + // if spline interpolation is needed then compute spline coefficients + if (kf2.linear == 1) { + this.linear = 1; + } else { + this.linear = 0; + computeCommonCoefficients (kf0, kf1, kf2, kf3); + computeHermiteCoefficients (kf0, kf1, kf2, kf3); + } + + length = computeLength (1.0f); + // System.out.println ("Segment length = " + length); + + } + + // compute the common coefficients + private void computeCommonCoefficients (TCBKeyFrame kf0, + TCBKeyFrame kf1, + TCBKeyFrame kf2, + TCBKeyFrame kf3) { + + // variables for destination derivative + float one_minus_t_in = 1.0f - kf1.tension; + float one_minus_c_in = 1.0f - kf1.continuity; + float one_minus_b_in = 1.0f - kf1.bias; + float one_plus_c_in = 1.0f + kf1.continuity; + float one_plus_b_in = 1.0f + kf1.bias; + + // coefficients for the incoming Tangent + ddb = one_minus_t_in * one_minus_c_in * one_minus_b_in; + dda = one_minus_t_in * one_plus_c_in * one_plus_b_in; + + // variables for source derivative + float one_minus_t_out = 1.0f - kf2.tension; + float one_minus_c_out = 1.0f - kf2.continuity; + float one_minus_b_out = 1.0f - kf2.bias; + float one_plus_c_out = 1.0f + kf2.continuity; + float one_plus_b_out = 1.0f + kf2.bias; + + // coefficients for the outgoing Tangent + dsb = one_minus_t_in * one_plus_c_in * one_minus_b_in; + dsa = one_minus_t_in * one_minus_c_in * one_plus_b_in; + } + + + // compute the hermite interpolation basis coefficients + private void computeHermiteCoefficients (TCBKeyFrame kf0, + TCBKeyFrame kf1, + TCBKeyFrame kf2, + TCBKeyFrame kf3) { + + + Point3f deltaP = new Point3f(); + Point3f deltaS = new Point3f(); + + // Find the difference in position and scale + deltaP.x = kf2.position.x - kf1.position.x; + deltaP.y = kf2.position.y - kf1.position.y; + deltaP.z = kf2.position.z - kf1.position.z; + + deltaS.x = kf2.scale.x - kf1.scale.x; + deltaS.y = kf2.scale.y - kf1.scale.y; + deltaS.z = kf2.scale.z - kf1.scale.z; + + // Incoming Tangent + Point3f dd_pos = new Point3f(); + Point3f dd_scale = new Point3f(); + + // If this is the first keyframe of the animation + if (kf0.knot == kf1.knot) { + + float ddab = 0.5f * (dda + ddb); + + // Position + dd_pos.x = ddab * deltaP.x; + dd_pos.y = ddab * deltaP.y; + dd_pos.z = ddab * deltaP.z; + + // Scale + dd_scale.x = ddab * deltaS.x; + dd_scale.y = ddab * deltaS.y; + dd_scale.z = ddab * deltaS.z; + + } else { + + float adj0 = (kf1.knot - kf0.knot)/(kf2.knot - kf0.knot); + + // Position + dd_pos.x = adj0 * + ((ddb * deltaP.x) + (dda * (kf1.position.x - kf0.position.x))); + dd_pos.y = adj0 * + ((ddb * deltaP.y) + (dda * (kf1.position.y - kf0.position.y))); + dd_pos.z = adj0 * + ((ddb * deltaP.z) + (dda * (kf1.position.z - kf0.position.z))); + + // Scale + dd_scale.x = adj0 * + ((ddb * deltaS.x) + (dda * (kf1.scale.x - kf0.scale.x))); + dd_scale.y = adj0 * + ((ddb * deltaS.y) + (dda * (kf1.scale.y - kf0.scale.y))); + dd_scale.z = adj0 * + ((ddb * deltaS.z) + (dda * (kf1.scale.z - kf0.scale.z))); + } + + // Outgoing Tangent + Point3f ds_pos = new Point3f(); + Point3f ds_scale = new Point3f(); + + // If this is the last keyframe of the animation + if (kf2.knot == kf3.knot) { + + float dsab = 0.5f * (dsa + dsb); + + // Position + ds_pos.x = dsab * deltaP.x; + ds_pos.y = dsab * deltaP.y; + ds_pos.z = dsab * deltaP.z; + + // Scale + ds_scale.x = dsab * deltaS.x; + ds_scale.y = dsab * deltaS.y; + ds_scale.z = dsab * deltaS.z; + + } else { + + float adj1 = (kf2.knot - kf1.knot)/(kf3.knot - kf1.knot); + + // Position + ds_pos.x = adj1 * + ((dsb * (kf3.position.x - kf2.position.x)) + (dsa * deltaP.x)); + ds_pos.y = adj1 * + ((dsb * (kf3.position.y - kf2.position.y)) + (dsa * deltaP.y)); + ds_pos.z = adj1 * + ((dsb * (kf3.position.z - kf2.position.z)) + (dsa * deltaP.z)); + + // Scale + ds_scale.x = adj1 * + ((dsb * (kf3.scale.x - kf2.scale.x)) + (dsa * deltaS.x)); + ds_scale.y = adj1 * + ((dsb * (kf3.scale.y - kf2.scale.y)) + (dsa * deltaS.y)); + ds_scale.z = adj1 * + ((dsb * (kf3.scale.z - kf2.scale.z)) + (dsa * deltaS.z)); + } + + // Calculate the coefficients of the polynomial for position + c0 = new Point3f(); + c0.x = kf1.position.x; + c0.y = kf1.position.y; + c0.z = kf1.position.z; + + c1 = new Point3f(); + c1.x = dd_pos.x; + c1.y = dd_pos.y; + c1.z = dd_pos.z; + + c2 = new Point3f(); + c2.x = 3*deltaP.x - 2*dd_pos.x - ds_pos.x; + c2.y = 3*deltaP.y - 2*dd_pos.y - ds_pos.y; + c2.z = 3*deltaP.z - 2*dd_pos.z - ds_pos.z; + + c3 = new Point3f(); + c3.x = -2*deltaP.x + dd_pos.x + ds_pos.x; + c3.y = -2*deltaP.y + dd_pos.y + ds_pos.y; + c3.z = -2*deltaP.z + dd_pos.z + ds_pos.z; + + // Calculate the coefficients of the polynomial for scale + e0 = new Point3f(); + e0.x = kf1.scale.x; + e0.y = kf1.scale.y; + e0.z = kf1.scale.z; + + e1 = new Point3f(); + e1.x = dd_scale.x; + e1.y = dd_scale.y; + e1.z = dd_scale.z; + + e2 = new Point3f(); + e2.x = 3*deltaS.x - 2*dd_scale.x - ds_scale.x; + e2.y = 3*deltaS.y - 2*dd_scale.y - ds_scale.y; + e2.z = 3*deltaS.z - 2*dd_scale.z - ds_scale.z; + + e3 = new Point3f(); + e3.x = -2*deltaS.x + dd_scale.x + ds_scale.x; + e3.y = -2*deltaS.y + dd_scale.y + ds_scale.y; + e3.z = -2*deltaS.z + dd_scale.z + ds_scale.z; + } + + + /** + * Computes the length of the curve at a given point between + * key frames. + * @param u specifies the point between keyframes where 0 <= u <= 1. + */ + + public float computeLength (float u) { + + float result = 0f; + + // if linear interpolation + if (linear == 1) { + result = u*keyFrame[2].position.distance(keyFrame[1].position); + } else { + // Need to transform domain [0,u] to [-1,1]. If 0 <= x <= u + // and -1 <= t <= 1, then x = u*(t+1)/2. + int degree = 5; + for (int i = 0; i < degree; i++) + result += (float)modCoeff[i]*computeSpeed(u*(float)modRoot[i]); + result *= u; + } + + return result; + } + + // Velocity along curve + private float computeSpeed (float u) { + Point3f v = new Point3f(); + + v.x = c1.x + u * (2 * c2.x + 3 * u * c3.x); + v.y = c1.y + u * (2 * c2.y + 3 * u * c3.y); + v.z = c1.z + u * (2 * c2.z + 3 * u * c3.z); + + return (float)(Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z)); + } + + + /** + * Computes the interpolated quaternion along the curve at + * a given point between key frames. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newQuat returns the value of the interpolated quaternion + */ + + public void getInterpolatedQuaternion (float u, Quat4f newQuat) { + + // if linear interpolation + if (this.linear == 1) { + double quatDot; + + quatDot = keyFrame[1].quat.x * keyFrame[2].quat.x + + keyFrame[1].quat.y * keyFrame[2].quat.y + + keyFrame[1].quat.z * keyFrame[2].quat.z + + keyFrame[1].quat.w * keyFrame[2].quat.w; + + if (quatDot < 0) { + newQuat.x = keyFrame[1].quat.x + + (-keyFrame[2].quat.x - keyFrame[1].quat.x) * u; + newQuat.y = keyFrame[1].quat.y + + (-keyFrame[2].quat.y - keyFrame[1].quat.y) * u; + newQuat.z = keyFrame[1].quat.z + + (-keyFrame[2].quat.z - keyFrame[1].quat.z) * u; + newQuat.w = keyFrame[1].quat.w + + (-keyFrame[2].quat.w - keyFrame[1].quat.w) * u; + } else { + newQuat.x = keyFrame[1].quat.x + + (keyFrame[2].quat.x - keyFrame[1].quat.x) * u; + newQuat.y = keyFrame[1].quat.y + + (keyFrame[2].quat.y - keyFrame[1].quat.y) * u; + newQuat.z = keyFrame[1].quat.z + + (keyFrame[2].quat.z - keyFrame[1].quat.z) * u; + newQuat.w = keyFrame[1].quat.w + + (keyFrame[2].quat.w - keyFrame[1].quat.w) * u; + } + + } else { + + // TODO: + // Currently we just use the great circle spherical interpolation + // for quaternions irrespective of the linear flag. Eventually + // we might want to do cubic interpolation of quaternions + newQuat.interpolate (keyFrame[1].quat, keyFrame[2].quat, u); + } + + } + + + + /** + * Computes the interpolated scale along the curve at a given point + * between key frames and returns a Point3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newScale returns the interpolated x,y,z scale value in a Point3f + */ + + public void getInterpolatedScale (float u, Point3f newScale) { + + // if linear interpolation + if (this.linear == 1) { + + newScale.x = keyFrame[1].scale.x + + ((keyFrame[2].scale.x - keyFrame[1].scale.x) * u); + newScale.y = keyFrame[1].scale.y + + ((keyFrame[2].scale.y - keyFrame[1].scale.y) * u); + newScale.z = keyFrame[1].scale.z + + ((keyFrame[2].scale.z - keyFrame[1].scale.z) * u); + + } else { + + newScale.x = e0.x + u * (e1.x + u * (e2.x + u * e3.x)); + newScale.y = e0.y + u * (e1.y + u * (e2.y + u * e3.y)); + newScale.z = e0.z + u * (e1.z + u * (e2.z + u * e3.z)); + + } + } + + + /** + * Computes the interpolated position along the curve at a given point + * between key frames and returns a Point3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newPos returns the interpolated x,y,z position in a Point3f + */ + + public void getInterpolatedPosition (float u, Point3f newPos) { + + // if linear interpolation + if (this.linear == 1) { + newPos.x = keyFrame[1].position.x + + ((keyFrame[2].position.x - keyFrame[1].position.x) * u); + newPos.y = keyFrame[1].position.y + + ((keyFrame[2].position.y - keyFrame[1].position.y) * u); + newPos.z = keyFrame[1].position.z + + ((keyFrame[2].position.z - keyFrame[1].position.z) * u); + } else { + + newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); + newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); + newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); + + } + } + + + /** + * Computes the interpolated position along the curve at a given point + * between key frames and returns a Vector3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newPos returns the interpolated x,y,z position in a Vector3f. + */ + + public void getInterpolatedPositionVector (float u, Vector3f newPos) { + // if linear interpolation + if (this.linear == 1) { + newPos.x = keyFrame[1].position.x + + ((keyFrame[2].position.x - keyFrame[1].position.x) * u); + newPos.y = keyFrame[1].position.y + + ((keyFrame[2].position.y - keyFrame[1].position.y) * u); + newPos.z = keyFrame[1].position.z + + ((keyFrame[2].position.z - keyFrame[1].position.z) * u); + } else { + + newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); + newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); + newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); + + } + } + + /** + * Computes the ratio of the length of the spline from the ith + * key frame to the position specified by u to the length of the entire + * spline segment from the ith key frame to the (i+1) + * th key frame. When the (i+1)th key frame's linear + * value is equal to 1, this is meaninful otherwise it should return u. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @return the interpolated ratio + */ + + public float getInterpolatedValue (float u) { + return (computeLength(u)/this.length); + } +} diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBCubicSplineCurve.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBCubicSplineCurve.java new file mode 100644 index 0000000..b76c20e --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBCubicSplineCurve.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.interpolators; + +import org.jogamp.java3d.internal.J3dUtilsI18N; + +/** + * KBCubicSplineCurve is a container class that holds a number of + * KBCubicSplineSegments + * + * @since Java3D 1.2 + */ + +public class KBCubicSplineCurve { + + private float totalCurveLength; + private KBCubicSplineSegment[] cubicSplineSegment; + public int numSegments; + + + // default constructor + KBCubicSplineCurve () { + numSegments = 0; + totalCurveLength = 0f; + } + + /** + * This method takes a list of key frames and creates spline segments + * from it. It requires at least four key frames to be passed to it. + * Given n key frames, it creates n-3 KBCubicSplineSegments. + * @param the list of key frames that specify the motion path + */ + + KBCubicSplineCurve (KBKeyFrame keys[]) { + + int keyLength = keys.length; + // Require at least 4 key frames for cubic spline curve + if (keyLength < 4) + throw new + IllegalArgumentException(J3dUtilsI18N.getString("KBCubicSplineCurve0")); + + numSegments = keyLength - 3; + this.cubicSplineSegment = new KBCubicSplineSegment[numSegments]; + + // intialize and calculate coefficients for each segment + int k0 = 0; int k1 = 1; int k2 = 2; int k3 = 3; + for (; k0 < numSegments; k0++, k1++, k2++, k3++) { + this.cubicSplineSegment[k0] = new KBCubicSplineSegment + (keys[k0], keys[k1], keys[k2], keys[k3]); + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method takes a list of spline segments creates the + * KBCubicSplineCurve. + * @param the list of segments that comprise the complete motion path + */ + + KBCubicSplineCurve (KBCubicSplineSegment s[]) { + + cubicSplineSegment = new KBCubicSplineSegment[s.length]; + numSegments = cubicSplineSegment.length; + for (int i = 0; i < numSegments; i++) { + this.cubicSplineSegment[i] = s[i]; + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method takes a list of spline segments to replace the existing + * set of KBCubicSplineSegments that comprise the current + * KBCubicSplineCurve motion path. + * @param s the list of segments that comprise the complete motion path + */ + + public void setSegments (KBCubicSplineSegment s[]) { + + cubicSplineSegment = new KBCubicSplineSegment[s.length]; + numSegments = cubicSplineSegment.length; + for (int i = 0; i < numSegments; i++) { + this.cubicSplineSegment[i] = s[i]; + } + + // compute total curve length + computeTotalCurveLength (); + } + + /** + * This method returns the KBCubicSplineSegments pointed to by index + * @param index the index of the KBCubicSplineSegment required + * @return the KBCubicSplineSegment pointed to by index + */ + public KBCubicSplineSegment getSegment (int index) { + + return this.cubicSplineSegment[index]; + + } + + + // computes the total length of the curve + private void computeTotalCurveLength () { + + totalCurveLength = 0f; + for (int i = 0; i < numSegments; i++) { + totalCurveLength += cubicSplineSegment[i].length; + } + + } + + /** + * This method returns the total length of the entire KBCubicSplineCurve + * motion path. + * + * @return the length of the KBCubicSplineCurve motion path + */ + + public float getTotalCurveLength () { + + return this.totalCurveLength; + + } + +} + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBCubicSplineSegment.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBCubicSplineSegment.java new file mode 100644 index 0000000..158c6cd --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBCubicSplineSegment.java @@ -0,0 +1,624 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.interpolators; + +import org.jogamp.vecmath.Point3f; +import org.jogamp.vecmath.Vector3f; + + +/** + * The KBCubicSplineSegment class creates the representation of a + * Kochanek-Bartel's (also known as the TCB or Tension-Continuity-Bias + * Spline. This class takes 4 key frames as its input (using KBKeyFrame). + * If interpolating between the ith and (i+1)th key + * frame then the four key frames that need to be specified are the + * (i-1)th, ith, (i+1)th + * and (i+2)th keyframes in order. The KBCubicSegmentClass + * then pre-computes the hermite interpolation basis coefficients if the + * (i+1)th frame has the linear flag set to zero. These are used to + * calculate the interpolated position, scale and quaternions when they + * requested by the user using the getInterpolated* methods. If the the + * (i+1)th frame's linear flag is set to 1 then the class uses + * linear interpolation to calculate the interpolated position, scale, heading + * pitch and bank it returns through the getInterpolated* methods. + * + * @since Java3D 1.2 + */ +public class KBCubicSplineSegment { + + // Legendre polynomial information for Gaussian quadrature of speed + // for the domain [0,u], 0 <= u <= 1. + + // Legendre roots mapped to (root+1)/2 + static final double modRoot[] = + { + 0.046910077, + 0.230765345, + 0.5, + 0.769234655, + 0.953089922 + }; + + // original coefficients divided by 2 + static final double modCoeff[] = + { + 0.118463442, + 0.239314335, + 0.284444444, + 0.239314335, + 0.118463442 + }; + + // Key Frames + KBKeyFrame[] keyFrame = new KBKeyFrame[4]; + + // H.C + Point3f c0, c1, c2, c3; // coefficients for position + Point3f e0, e1, e2, e3; // coefficients for scale + float h0, h1, h2, h3; // coefficients for heading + float p0, p1, p2, p3; // coefficients for pitch + float b0, b1, b2, b3; // coefficients for bank + + // variables for destination derivative + float one_minus_t_in; + float one_minus_c_in; + float one_minus_b_in; + float one_plus_c_in; + float one_plus_b_in; + float ddb; + float dda; + + // variables for source derivative + float one_minus_t_out; + float one_minus_c_out; + float one_minus_b_out; + float one_plus_c_out; + float one_plus_b_out; + float dsb; + float dsa; + + // Length of the spline segment + float length; + + // interpolation type + int linear; + + // Default constructor + KBCubicSplineSegment () { + + length = 0; + + } + + /** + * Creates a cubic spline segment between two key frames using the + * key frames provided. If creating a spline between the ith frame and + * the (i+1)th frame then send down the (i - 1)th, + * ith , (i+1)th and the (i+2)th key + * frames. + * + * @param kf0 (i - 1)th Key Frame + * @param kf1 ith Key Frame + * @param kf2 (i + 1)th Key Frame + * @param kf3 (i + 2)th Key Frame + */ + + KBCubicSplineSegment (KBKeyFrame kf0, KBKeyFrame kf1, KBKeyFrame kf2, + KBKeyFrame kf3) { + + // Copy KeyFrame information + keyFrame[0] = new KBKeyFrame(kf0); + keyFrame[1] = new KBKeyFrame(kf1); + keyFrame[2] = new KBKeyFrame(kf2); + keyFrame[3] = new KBKeyFrame(kf3); + + // if linear interpolation is requested then just set linear flag + // if spline interpolation is needed then compute spline coefficients + if (kf2.linear == 1) { + this.linear = 1; + } else { + this.linear = 0; + computeCommonCoefficients (kf0, kf1, kf2, kf3); + computeHermiteCoefficients (kf0, kf1, kf2, kf3); + } + + length = computeLength (1.0f); + // System.out.println ("Segment length = " + length); + + } + + // compute the common coefficients + private void computeCommonCoefficients (KBKeyFrame kf0, + KBKeyFrame kf1, + KBKeyFrame kf2, + KBKeyFrame kf3) { + + // variables for destination derivative + float one_minus_t_in = 1.0f - kf1.tension; + float one_minus_c_in = 1.0f - kf1.continuity; + float one_minus_b_in = 1.0f - kf1.bias; + float one_plus_c_in = 1.0f + kf1.continuity; + float one_plus_b_in = 1.0f + kf1.bias; + + // coefficients for the incoming Tangent + ddb = one_minus_t_in * one_minus_c_in * one_minus_b_in; + dda = one_minus_t_in * one_plus_c_in * one_plus_b_in; + + // variables for source derivative + float one_minus_t_out = 1.0f - kf2.tension; + float one_minus_c_out = 1.0f - kf2.continuity; + float one_minus_b_out = 1.0f - kf2.bias; + float one_plus_c_out = 1.0f + kf2.continuity; + float one_plus_b_out = 1.0f + kf2.bias; + + // coefficients for the outgoing Tangent + dsb = one_minus_t_in * one_plus_c_in * one_minus_b_in; + dsa = one_minus_t_in * one_minus_c_in * one_plus_b_in; + } + + + // compute the hermite interpolation basis coefficients + private void computeHermiteCoefficients (KBKeyFrame kf0, + KBKeyFrame kf1, + KBKeyFrame kf2, + KBKeyFrame kf3) { + + + Point3f deltaP = new Point3f(); + Point3f deltaS = new Point3f(); + float deltaH; + float deltaT; + float deltaB; + + // Find the difference in position and scale + deltaP.x = kf2.position.x - kf1.position.x; + deltaP.y = kf2.position.y - kf1.position.y; + deltaP.z = kf2.position.z - kf1.position.z; + + deltaS.x = kf2.scale.x - kf1.scale.x; + deltaS.y = kf2.scale.y - kf1.scale.y; + deltaS.z = kf2.scale.z - kf1.scale.z; + + // Find the difference in heading, pitch, and bank + deltaH = kf2.heading - kf1.heading; + deltaT = kf2.pitch - kf1.pitch; + deltaB = kf2.bank - kf1.bank; + + // Incoming Tangent + Point3f dd_pos = new Point3f(); + Point3f dd_scale = new Point3f(); + float dd_heading, dd_pitch, dd_bank; + + // If this is the first keyframe of the animation + if (kf0.knot == kf1.knot) { + + float ddab = 0.5f * (dda + ddb); + + // Position + dd_pos.x = ddab * deltaP.x; + dd_pos.y = ddab * deltaP.y; + dd_pos.z = ddab * deltaP.z; + + // Scale + dd_scale.x = ddab * deltaS.x; + dd_scale.y = ddab * deltaS.y; + dd_scale.z = ddab * deltaS.z; + + // Heading, Pitch and Bank + dd_heading = ddab * deltaH; + dd_pitch = ddab * deltaT; + dd_bank = ddab * deltaB; + + } else { + + float adj0 = (kf1.knot - kf0.knot)/(kf2.knot - kf0.knot); + + // Position + dd_pos.x = adj0 * + ((ddb * deltaP.x) + (dda * (kf1.position.x - kf0.position.x))); + dd_pos.y = adj0 * + ((ddb * deltaP.y) + (dda * (kf1.position.y - kf0.position.y))); + dd_pos.z = adj0 * + ((ddb * deltaP.z) + (dda * (kf1.position.z - kf0.position.z))); + + // Scale + dd_scale.x = adj0 * + ((ddb * deltaS.x) + (dda * (kf1.scale.x - kf0.scale.x))); + dd_scale.y = adj0 * + ((ddb * deltaS.y) + (dda * (kf1.scale.y - kf0.scale.y))); + dd_scale.z = adj0 * + ((ddb * deltaS.z) + (dda * (kf1.scale.z - kf0.scale.z))); + + // Heading, Pitch and Bank + dd_heading = adj0 * + ((ddb * deltaH) + (dda * (kf1.heading - kf0.heading))); + dd_pitch = adj0 * + ((ddb * deltaT) + (dda * (kf1.pitch - kf0.pitch))); + dd_bank = adj0 * + ((ddb * deltaB) + (dda * (kf1.bank - kf0.bank))); + } + + // Outgoing Tangent + Point3f ds_pos = new Point3f(); + Point3f ds_scale = new Point3f(); + float ds_heading, ds_pitch, ds_bank; + + // If this is the last keyframe of the animation + if (kf2.knot == kf3.knot) { + + float dsab = 0.5f * (dsa + dsb); + + // Position + ds_pos.x = dsab * deltaP.x; + ds_pos.y = dsab * deltaP.y; + ds_pos.z = dsab * deltaP.z; + + // Scale + ds_scale.x = dsab * deltaS.x; + ds_scale.y = dsab * deltaS.y; + ds_scale.z = dsab * deltaS.z; + + // Heading, Pitch and Bank + ds_heading = dsab * deltaH; + ds_pitch = dsab * deltaT; + ds_bank = dsab * deltaB; + + } else { + + float adj1 = (kf2.knot - kf1.knot)/(kf3.knot - kf1.knot); + + // Position + ds_pos.x = adj1 * + ((dsb * (kf3.position.x - kf2.position.x)) + (dsa * deltaP.x)); + ds_pos.y = adj1 * + ((dsb * (kf3.position.y - kf2.position.y)) + (dsa * deltaP.y)); + ds_pos.z = adj1 * + ((dsb * (kf3.position.z - kf2.position.z)) + (dsa * deltaP.z)); + + // Scale + ds_scale.x = adj1 * + ((dsb * (kf3.scale.x - kf2.scale.x)) + (dsa * deltaS.x)); + ds_scale.y = adj1 * + ((dsb * (kf3.scale.y - kf2.scale.y)) + (dsa * deltaS.y)); + ds_scale.z = adj1 * + ((dsb * (kf3.scale.z - kf2.scale.z)) + (dsa * deltaS.z)); + + // Heading, Pitch and Bank + ds_heading = adj1 * + ((dsb * (kf3.heading - kf2.heading)) + (dsa * deltaH)); + ds_pitch = adj1 * + ((dsb * (kf3.pitch - kf2.pitch)) + (dsa * deltaT)); + ds_bank = adj1 * + ((dsb * (kf3.bank - kf2.bank)) + (dsa * deltaB)); + } + + // Calculate the coefficients of the polynomial for position + c0 = new Point3f(); + c0.x = kf1.position.x; + c0.y = kf1.position.y; + c0.z = kf1.position.z; + + c1 = new Point3f(); + c1.x = dd_pos.x; + c1.y = dd_pos.y; + c1.z = dd_pos.z; + + c2 = new Point3f(); + c2.x = 3*deltaP.x - 2*dd_pos.x - ds_pos.x; + c2.y = 3*deltaP.y - 2*dd_pos.y - ds_pos.y; + c2.z = 3*deltaP.z - 2*dd_pos.z - ds_pos.z; + + c3 = new Point3f(); + c3.x = -2*deltaP.x + dd_pos.x + ds_pos.x; + c3.y = -2*deltaP.y + dd_pos.y + ds_pos.y; + c3.z = -2*deltaP.z + dd_pos.z + ds_pos.z; + + // Calculate the coefficients of the polynomial for scale + e0 = new Point3f(); + e0.x = kf1.scale.x; + e0.y = kf1.scale.y; + e0.z = kf1.scale.z; + + e1 = new Point3f(); + e1.x = dd_scale.x; + e1.y = dd_scale.y; + e1.z = dd_scale.z; + + e2 = new Point3f(); + e2.x = 3*deltaS.x - 2*dd_scale.x - ds_scale.x; + e2.y = 3*deltaS.y - 2*dd_scale.y - ds_scale.y; + e2.z = 3*deltaS.z - 2*dd_scale.z - ds_scale.z; + + e3 = new Point3f(); + e3.x = -2*deltaS.x + dd_scale.x + ds_scale.x; + e3.y = -2*deltaS.y + dd_scale.y + ds_scale.y; + e3.z = -2*deltaS.z + dd_scale.z + ds_scale.z; + + // Calculate the coefficients of the polynomial for heading, pitch + // and bank + h0 = kf1.heading; + p0 = kf1.pitch; + b0 = kf1.bank; + + h1 = dd_heading; + p1 = dd_pitch; + b1 = dd_bank; + + h2 = 3*deltaH - 2*dd_heading - ds_heading; + p2 = 3*deltaT - 2*dd_pitch - ds_pitch; + b2 = 3*deltaB - 2*dd_bank - ds_bank; + + h3 = -2*deltaH + dd_heading + ds_heading; + p3 = -2*deltaT + dd_pitch + ds_pitch; + b3 = -2*deltaB + dd_bank + ds_bank; + } + + + /** + * Computes the length of the curve at a given point between + * key frames. + * @param u specifies the point between keyframes where 0 <= u <= 1. + */ + + public float computeLength (float u) { + + float result = 0f; + + // if linear interpolation + if (linear == 1) { + result = u*keyFrame[2].position.distance(keyFrame[1].position); + } else { + // Need to transform domain [0,u] to [-1,1]. If 0 <= x <= u + // and -1 <= t <= 1, then x = u*(t+1)/2. + int degree = 5; + for (int i = 0; i < degree; i++) + result += (float)modCoeff[i]*computeSpeed(u*(float)modRoot[i]); + result *= u; + } + + return result; + } + + // Velocity along curve + private float computeSpeed (float u) { + Point3f v = new Point3f(); + + v.x = c1.x + u * (2 * c2.x + 3 * u * c3.x); + v.y = c1.y + u * (2 * c2.y + 3 * u * c3.y); + v.z = c1.z + u * (2 * c2.z + 3 * u * c3.z); + + return (float)(Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z)); + } + + + /** + * Computes the interpolated scale along the curve at a given point + * between key frames and returns a Point3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newScale returns the interpolated x,y,z scale value in a Point3f + */ + + public void getInterpolatedScale (float u, Point3f newScale) { + + // if linear interpolation + if (this.linear == 1) { + + newScale.x = keyFrame[1].scale.x + + ((keyFrame[2].scale.x - keyFrame[1].scale.x) * u); + newScale.y = keyFrame[1].scale.y + + ((keyFrame[2].scale.y - keyFrame[1].scale.y) * u); + newScale.z = keyFrame[1].scale.z + + ((keyFrame[2].scale.z - keyFrame[1].scale.z) * u); + + } else { + + newScale.x = e0.x + u * (e1.x + u * (e2.x + u * e3.x)); + newScale.y = e0.y + u * (e1.y + u * (e2.y + u * e3.y)); + newScale.z = e0.z + u * (e1.z + u * (e2.z + u * e3.z)); + + } + } + + + /** + * Computes the interpolated position along the curve at a given point + * between key frames and returns a Point3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newPos returns the interpolated x,y,z position in a Point3f + */ + + public void getInterpolatedPosition (float u, Point3f newPos) { + + // if linear interpolation + if (this.linear == 1) { + newPos.x = keyFrame[1].position.x + + ((keyFrame[2].position.x - keyFrame[1].position.x) * u); + newPos.y = keyFrame[1].position.y + + ((keyFrame[2].position.y - keyFrame[1].position.y) * u); + newPos.z = keyFrame[1].position.z + + ((keyFrame[2].position.z - keyFrame[1].position.z) * u); + } else { + + newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); + newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); + newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); + + } + } + + + /** + * Computes the interpolated position along the curve at a given point + * between key frames and returns a Vector3f with the interpolated + * x, y, and z scale components. This routine uses linear + * interpolation if the (i+1)th key frame's linear + * value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @param newPos returns the interpolated x,y,z position in a Vector3f. + */ + + public void getInterpolatedPositionVector (float u, Vector3f newPos) { + // if linear interpolation + if (this.linear == 1) { + newPos.x = keyFrame[1].position.x + + ((keyFrame[2].position.x - keyFrame[1].position.x) * u); + newPos.y = keyFrame[1].position.y + + ((keyFrame[2].position.y - keyFrame[1].position.y) * u); + newPos.z = keyFrame[1].position.z + + ((keyFrame[2].position.z - keyFrame[1].position.z) * u); + } else { + + newPos.x = c0.x + u * (c1.x + u * (c2.x + u * c3.x)); + newPos.y = c0.y + u * (c1.y + u * (c2.y + u * c3.y)); + newPos.z = c0.z + u * (c1.z + u * (c2.z + u * c3.z)); + + } + } + + /** + * Computes the interpolated heading along the curve at a given point + * between key frames and returns the interpolated value as a float + * This routine uses linear interpolation if the (i+1)th + * key frame's linear value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @return returns the interpolated heading value + */ + + public float getInterpolatedHeading (float u) { + + float newHeading; + + // if linear interpolation + if (this.linear == 1) { + + newHeading = keyFrame[1].heading + + ((keyFrame[2].heading - keyFrame[1].heading) * u); + } else { + + newHeading = h0 + u * (h1 + u * (h2 + u * h3)); + + } + + return newHeading; + } + + + /** + * Computes the interpolated pitch along the curve at a given point + * between key frames and returns the interpolated value as a float + * This routine uses linear interpolation if the (i+1)th + * key frame's linear value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @return returns the interpolated pitch value + */ + + public float getInterpolatedPitch (float u) { + + float newPitch; + + // if linear interpolation + if (this.linear == 1) { + + newPitch = keyFrame[1].pitch + + ((keyFrame[2].pitch - keyFrame[1].pitch) * u); + } else { + + newPitch = p0 + u * (p1 + u * (p2 + u * p3)); + + } + + return newPitch; + } + + /** + * Computes the interpolated bank along the curve at a given point + * between key frames and returns the interpolated value as a float + * This routine uses linear interpolation if the (i+1)th + * key frame's linear value is equal to 1. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @return returns the interpolated bank value + */ + + public float getInterpolatedBank (float u) { + + float newBank; + + // if linear interpolation + if (this.linear == 1) { + + newBank = keyFrame[1].bank + + ((keyFrame[2].bank - keyFrame[1].bank) * u); + } else { + + newBank = b0 + u * (b1 + u * (b2 + u * b3)); + + } + + return newBank; + } + + + /** + * Computes the ratio of the length of the spline from the ith + * key frame to the position specified by u to the length of the entire + * spline segment from the ith key frame to the (i+1) + * th key frame. When the (i+1)th key frame's linear + * value is equal to 1, this is meaninful otherwise it should return u. + * + * @param u specifies the point between keyframes where 0 <= u <= 1. + * @return the interpolated ratio + */ + + public float getInterpolatedValue (float u) { + return (computeLength(u)/this.length); + } +} diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBKeyFrame.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBKeyFrame.java new file mode 100644 index 0000000..7fc665d --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBKeyFrame.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.interpolators; + +import org.jogamp.vecmath.Point3f; + +import org.jogamp.java3d.internal.J3dUtilsI18N; + +/** + * This class represents a Key Frame that can be used for Kochanek-Bartels + * (also called TCB or Tension-Continuity-Bias Splines) spline interpolation. + * + * @since Java3D 1.2 + */ +public class KBKeyFrame { + + // Position, Rotation and Scale + public Point3f position; + public float heading; + public float pitch; + public float bank; + public Point3f scale; + + // Tension, Continuity & Bias + public float tension; + public float continuity; + public float bias; + + // Sample Time + public float knot; + + // Interpolation type (linear = 0 -> spline interpolation) + public int linear; + + // default constructor + KBKeyFrame () { + tension = continuity = bias = 0.0f; + } + + public KBKeyFrame (KBKeyFrame kf) { + this(kf.knot, kf.linear, kf.position, kf.heading, kf.pitch, kf.bank, + kf.scale, kf.tension, kf.continuity, kf.bias); + + } + + + /** + * Creates a key frame using the given inputs. + * + * @param k knot value for this key frame + * @param l the linear flag (0 - Spline Interp, 1, Linear Interp + * @param pos the position at the key frame + * @param hd the heading value at the key frame + * @param pi the pitch value at the key frame + * @param bk the bank value at the key frame + * @param s the scales at the key frame + * @param t tension (-1.0 < t < 1.0) + * @param c continuity (-1.0 < c < 1.0) + * @param b bias (-1.0 < b < 1.0) + */ + public KBKeyFrame (float k, int l, Point3f pos, float hd, float pi, + float bk, Point3f s, float t, float c, float b) { + + knot = k; + linear = l; + position = new Point3f(pos); + heading = hd; + pitch = pi; + bank = bk; + scale = new Point3f(s); + + // Check for valid tension continuity and bias values + if (t < -1.0f || t > 1.0f) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("KBKeyFrame0")); + } + + if (b < -1.0f || b > 1.0f) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("KBKeyFrame1")); + } + + if (c < -1.0f || c > 1.0f) { + throw new IllegalArgumentException(J3dUtilsI18N.getString("KBKeyFrame2")); + } + + // copy valid tension, continuity and bias values + tension = t; + continuity = c; + bias = b; + } + + /** + * Prints information comtained in this key frame + * @param tag string tag for identifying debug message + */ + public void debugPrint (String tag) { + System.out.println ("\n" + tag); + System.out.println (" knot = " + knot); + System.out.println (" linear = " + linear); + System.out.println (" position(x,y,z) = " + position.x + " " + + position.y + " " + position.z); + + System.out.println (" tension = " + tension); + System.out.println (" continuity = " + continuity); + System.out.println (" bias = " + bias); + } +} + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBRotPosScaleSplinePathInterpolator.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBRotPosScaleSplinePathInterpolator.java new file mode 100644 index 0000000..be52f5e --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBRotPosScaleSplinePathInterpolator.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.interpolators; + +import org.jogamp.java3d.Alpha; +import org.jogamp.java3d.Node; +import org.jogamp.java3d.NodeComponent; +import org.jogamp.java3d.RestrictedAccessException; +import org.jogamp.java3d.Transform3D; +import org.jogamp.java3d.TransformGroup; +import org.jogamp.vecmath.Matrix4d; +import org.jogamp.vecmath.Point3f; +import org.jogamp.vecmath.Vector3f; + + +/** + * KBRotPosScaleSplinePathInterpolator; A rotation and position path + * interpolation behavior node using Kochanek-Bartels cubic splines + * (also known as TCB or Tension-Continuity-Bias Splines). + * + * @since Java3D 1.2 + */ + +/** + * KBRotPosScaleSplinePathInterpolator behavior. This class defines a + * behavior that varies the rotational, translational, and scale components + * of its target TransformGroup by using the Kochanek-Bartels cubic spline + * interpolation to interpolate among a series of key frames + * (using the value generated by the specified Alpha object). The + * interpolated position, orientation, and scale are used to generate + * a transform in the local coordinate system of this interpolator. + */ + +public class KBRotPosScaleSplinePathInterpolator + extends KBSplinePathInterpolator { + + private Transform3D rotation = new Transform3D(); + + private Matrix4d pitchMat = new Matrix4d(); // pitch matrix + private Matrix4d bankMat = new Matrix4d(); // bank matrix + private Matrix4d tMat = new Matrix4d(); // transformation matrix + private Matrix4d sMat = new Matrix4d(); // scale matrix + //Quat4f iQuat = new Quat4f(); // interpolated quaternion + private Vector3f iPos = new Vector3f(); // interpolated position + private Point3f iScale = new Point3f(); // interpolated scale + float iHeading, iPitch, iBank; // interpolated heading, + // pitch and bank + + KBCubicSplineCurve cubicSplineCurve = new KBCubicSplineCurve(); + KBCubicSplineSegment cubicSplineSegments[]; + int numSegments; + int currentSegmentIndex; + KBCubicSplineSegment currentSegment; + + // non-public, default constructor used by cloneNode + KBRotPosScaleSplinePathInterpolator() { + } + + /** + * Constructs a new KBRotPosScaleSplinePathInterpolator object that + * varies the rotation, translation, and scale of the target + * TransformGroup's transform. At least 2 key frames are required for + * this interpolator. The first key + * frame's knot must have a value of 0.0 and the last knot must have a + * value of 1.0. An intermediate key frame with index k must have a + * knot value strictly greater than the knot value of a key frame with + * index less than k. + * @param alpha the alpha object for this interpolator + * @param target the TransformGroup node affected by this interpolator + * @param axisOfTransform the transform that specifies the local + * coordinate system in which this interpolator operates. + * @param keys an array of key frames that defien the motion path + */ + public KBRotPosScaleSplinePathInterpolator(Alpha alpha, + TransformGroup target, + Transform3D axisOfTransform, + KBKeyFrame keys[]) { + super(alpha,target, axisOfTransform, keys); + + // Create a spline curve using the derived key frames + cubicSplineCurve = new KBCubicSplineCurve(this.keyFrames); + numSegments = cubicSplineCurve.numSegments; + + } + + /** + * @deprecated As of Java 3D version 1.3, replaced by + *TransformInterpolator.setTransformAxis(Transform3D)
+ */
+ public void setAxisOfRotPosScale(Transform3D axisOfRotPosScale) {
+ setTransformAxis(axisOfRotPosScale);
+ }
+
+ /**
+ * @deprecated As of Java 3D version 1.3, replaced by
+ * TransformInterpolator.getTransformAxis()
+ */
+ public Transform3D getAxisOfRotPosScale() {
+ return getTransformAxis();
+ }
+
+ /**
+ * Set the key frame at the specified index to keyFrame
+ * @param index Index of the key frame to change
+ * @param keyFrame The new key frame
+ */
+ @Override
+ public void setKeyFrame( int index, KBKeyFrame keyFrame ) {
+ super.setKeyFrame( index, keyFrame );
+
+ // TODO Optimize this
+ // Create a spline curve using the derived key frames
+ cubicSplineCurve = new KBCubicSplineCurve(this.keyFrames);
+ numSegments = cubicSplineCurve.numSegments;
+ }
+
+ /**
+ * Set all the key frames
+ * @param keyFrame The new key frames
+ */
+ @Override
+ public void setKeyFrames( KBKeyFrame[] keyFrame ) {
+ super.setKeyFrames( keyFrame );
+
+ // Create a spline curve using the derived key frames
+ cubicSplineCurve = new KBCubicSplineCurve(this.keyFrames);
+ numSegments = cubicSplineCurve.numSegments;
+ }
+
+ /**
+ * Computes the new transform for this interpolator for a given
+ * alpha value.
+ *
+ * @param alphaValue alpha value between 0.0 and 1.0
+ * @param transform object that receives the computed transform for
+ * the specified alpha value
+ *
+ * @since Java 3D 1.3
+ */
+ @Override
+ public void computeTransform(float alphaValue, Transform3D transform) {
+ // compute the current value of u from alpha and the
+ // determine lower and upper knot points
+ computePathInterpolation( alphaValue );
+
+ // Determine the segment within which we will be interpolating
+ currentSegmentIndex = this.lowerKnot - 1;
+
+ // if we are at the start of the curve
+ if (currentSegmentIndex == 0 && currentU == 0f) {
+
+ iHeading = keyFrames[1].heading;
+ iPitch = keyFrames[1].pitch;
+ iBank = keyFrames[1].bank;
+ iPos.set(keyFrames[1].position);
+ iScale.set(keyFrames[1].scale);
+
+ // if we are at the end of the curve
+ } else if (currentSegmentIndex == (numSegments-1) &&
+ currentU == 1.0) {
+
+ iHeading = keyFrames[upperKnot].heading;
+ iPitch = keyFrames[upperKnot].pitch;
+ iBank = keyFrames[upperKnot].bank;
+ iPos.set(keyFrames[upperKnot].position);
+ iScale.set(keyFrames[upperKnot].scale);
+
+ // if we are somewhere in between the curve
+ } else {
+
+ // Get a reference to the current spline segment i.e. the
+ // one bounded by lowerKnot and upperKnot
+ currentSegment
+ = cubicSplineCurve.getSegment(currentSegmentIndex);
+
+ // interpolate quaternions
+ iHeading = currentSegment.getInterpolatedHeading (currentU);
+ iPitch = currentSegment.getInterpolatedPitch (currentU);
+ iBank = currentSegment.getInterpolatedBank (currentU);
+
+ // interpolate position
+ currentSegment.getInterpolatedPositionVector(currentU,iPos);
+
+ // interpolate position
+ currentSegment.getInterpolatedScale(currentU,iScale);
+
+ }
+
+ // Generate a transformation matrix in tMat using interpolated
+ // heading, pitch and bank
+ pitchMat.setIdentity();
+ pitchMat.rotX(-iPitch);
+ bankMat.setIdentity();
+ bankMat.rotZ(iBank);
+ tMat.setIdentity();
+ tMat.rotY(-iHeading);
+ tMat.mul(pitchMat);
+ tMat.mul(bankMat);
+
+ // TODO: Handle Non-Uniform scale
+ // Currently this interpolator does not handle non uniform scale
+ // We cheat by just taking the x scale component
+
+ // Scale the transformation matrix
+ sMat.set((double)iScale.x);
+ tMat.mul(sMat);
+
+ // Set the translation components.
+ tMat.m03 = iPos.x;
+ tMat.m13 = iPos.y;
+ tMat.m23 = iPos.z;
+ rotation.set(tMat);
+
+ // construct a Transform3D from: axis * rotation * axisInverse
+ transform.mul(axis, rotation);
+ transform.mul(transform, axisInverse);
+ }
+
+ /**
+ * Copies KBRotPosScaleSplinePathInterpolator 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 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
+ public Node cloneNode(boolean forceDuplicate) {
+ KBRotPosScaleSplinePathInterpolator spline =
+ new KBRotPosScaleSplinePathInterpolator();
+
+ spline.duplicateNode(this, forceDuplicate);
+ return spline;
+ }
+
+ /**
+ * Copies KBRotPosScaleSplinePathInterpolator 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
+ public void duplicateNode(Node originalNode, boolean forceDuplicate) {
+ super.duplicateNode(originalNode, forceDuplicate);
+
+ KBRotPosScaleSplinePathInterpolator interpolator =
+ (KBRotPosScaleSplinePathInterpolator)originalNode;
+ setAxisOfRotPosScale(interpolator.axis);
+ target = interpolator.target;
+ cubicSplineCurve = new KBCubicSplineCurve(interpolator.keyFrames);
+ numSegments = cubicSplineCurve.numSegments;
+ }
+}
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBSplinePathInterpolator.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBSplinePathInterpolator.java
new file mode 100644
index 0000000..a3fe2cb
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/KBSplinePathInterpolator.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.interpolators;
+
+import org.jogamp.java3d.Alpha;
+import org.jogamp.java3d.Node;
+import org.jogamp.java3d.NodeComponent;
+import org.jogamp.java3d.RestrictedAccessException;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.java3d.TransformInterpolator;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+/**
+ * KBSplinePathInterpolator behavior. This class defines the base class for
+ * all Kochanek-Bartels (also known as TCB or Tension-Continuity-Bias)
+ * Spline Path Interpolators.
+ *
+ * @since Java3D 1.2
+ */
+
+public abstract class KBSplinePathInterpolator extends TransformInterpolator {
+
+ private int keysLength;
+ /**
+ * An array of KBKeyFrame for interpolator
+ */
+ protected KBKeyFrame[] keyFrames;
+
+ /**
+ * This value is the distance between knots
+ * value which can be used in further calculations by the subclass.
+ */
+ protected float currentU;
+
+ /**
+ * The lower knot
+ */
+ protected int lowerKnot;
+ /**
+ * The upper knot
+ */
+ protected int upperKnot;
+
+ /**
+ * Constructs a KBSplinePathInterpolator node with a null alpha value and
+ * a null target of TransformGroup
+ *
+ * @since Java 3D 1.3
+ */
+ KBSplinePathInterpolator() {
+ }
+
+
+ /**
+ * @deprecated As of Java 3D version 1.3, replaced by
+ * KBSplinePathInterpolator(Alpha, TransformGroup, TCBKeyFrame[])
+ */
+ public KBSplinePathInterpolator(Alpha alpha, KBKeyFrame keys[]) {
+ this(alpha, null, keys);
+ }
+
+ /**
+ * Constructs a new KBSplinePathInterpolator object that interpolates
+ * between keyframes with specified alpha, target and an default
+ * axisOfTranform set to identity.
+ * It takes at least two key frames. The first key
+ * frame's knot must have a value of 0.0 and the last knot must have a
+ * value of 1.0. An intermediate key frame with index k must have a
+ * knot value strictly greater than the knot value of a key frame with
+ * index less than k. Once this constructor has all the valid key frames
+ * it creates its own list of key fames that duplicates the first key frame
+ * at the beginning of the list and the last key frame at the end of the
+ * list.
+ * @param alpha the alpha object for this interpolator
+ * @param target the TransformGroup node affected by this interpolator
+ * @param keys an array of KBKeyFrame. Requires at least two key frames.
+ *
+ * @since Java 3D 1.3
+ */
+ public KBSplinePathInterpolator(Alpha alpha, TransformGroup target, KBKeyFrame keys[]) {
+ super(alpha, target);
+ processKeyFrames( keys );
+ }
+
+ /**
+ * Constructs a new KBSplinePathInterpolator object that interpolates
+ * between keyframes with specified alpha, target and axisOfTransform.
+ * It takes at least two key frames. The first key
+ * frame's knot must have a value of 0.0 and the last knot must have a
+ * value of 1.0. An intermediate key frame with index k must have a
+ * knot value strictly greater than the knot value of a key frame with
+ * index less than k. Once this constructor has all the valid key frames
+ * it creates its own list of key fames that duplicates the first key frame
+ * at the beginning of the list and the last key frame at the end of the
+ * list.
+ * @param alpha the alpha object for this interpolator
+ * @param target the TransformGroup node affected by this interpolator
+ * @param axisOfTransform the transform that defines the local coordinate
+ * @param keys an array of KBKeyFrame. Requires at least two key frames
+ *
+ * @since Java 3D 1.3
+ */
+ public KBSplinePathInterpolator(Alpha alpha,
+ TransformGroup target,
+ Transform3D axisOfTransform,
+ KBKeyFrame keys[]) {
+ super(alpha, target, axisOfTransform);
+ processKeyFrames( keys );
+ }
+
+ /**
+ * Process the new array of key frames
+ */
+ private void processKeyFrames( KBKeyFrame[] keys ) {
+
+ // Make sure that we have at least two key frames
+ keysLength = keys.length;
+ if (keysLength < 2) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator0"));
+
+ }
+
+ // Make sure that the first key frame's knot is equal to 0.0
+ if (keys[0].knot < -0.0001 || keys[0].knot > 0.0001) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator1"));
+ }
+
+ // Make sure that the last key frames knot is equal to 1.0
+ if (keys[keysLength-1].knot -1.0 < -0.0001 || keys[keysLength-1].knot -1.0 > 0.0001) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator2"));
+ }
+
+ // Make sure that all the knots are in sequence
+ for (int i = 0; i < keysLength; i++) {
+ if (i>0 && keys[i].knot < keys[i-1].knot) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("KBSplinePathInterpolator3"));
+ }
+ }
+
+ // Make space for a leading and trailing key frame in addition to
+ // the keys passed in
+ keyFrames = new KBKeyFrame[keysLength+2];
+ keyFrames[0] = new KBKeyFrame();
+ keyFrames[0] = keys[0];
+ for (int i = 1; i < keysLength+1; i++) {
+ keyFrames[i] = keys[i-1];
+ }
+ keyFrames[keysLength+1] = new KBKeyFrame();
+ keyFrames[keysLength+1] = keys[keysLength-1];
+
+ // Make key frame length reflect the 2 added key frames
+ keysLength += 2;
+ }
+
+ /**
+ * This method retrieves the length of the key frame array.
+ * @return the number of key frames
+ */
+ public int getArrayLength(){
+ return keysLength-2;
+ }
+
+ /**
+ * This method retrieves the key frame at the specified index.
+ * @param index the index of the key frame requested
+ * @return the key frame at the associated index
+ */
+ public KBKeyFrame getKeyFrame (int index) {
+
+ // We add 1 to index because we have added a leading keyFrame
+ return this.keyFrames[index+1];
+ }
+
+ /**
+ * Set the key frame at the specified index to keyFrame
+ * @param index Index of the key frame to change
+ * @param keyFrame The new key frame
+ * @since Java 3D 1.3
+ */
+ public void setKeyFrame( int index, KBKeyFrame keyFrame ) {
+ this.keyFrames[index+1] = keyFrame;
+ }
+
+ /**
+ * Set allthe key frames
+ * @param keyFrames The new key frame
+ * @since Java 3D 1.3
+ */
+ public void setKeyFrames( KBKeyFrame[] keyFrames ) {
+ processKeyFrames( keyFrames );
+ }
+
+ /**
+ * @deprecated As of Java 3D version 1.3, replaced by
+ * computePathInterpolation(float)
+ */
+ protected void computePathInterpolation() {
+ computePathInterpolation(this.getAlpha().value());
+ }
+
+ /**
+ * This method computes the bounding knot indices and interpolation value
+ * "CurrentU" given the current value of the knots[] array and the
+ * specified alpha value
+ * @param alphaValue alpha value between 0.0 and 1.0
+ *
+ * @since Java 3D 1.3
+ */
+ protected void computePathInterpolation( float alphaValue ) {
+
+ // skip knots till we find the two we fall between
+ int i = 1;
+ int len = keysLength - 2;
+ while ((alphaValue > keyFrames[i].knot) && (i < len)) {
+ i++;
+ }
+
+ if (i == 1) {
+ currentU = 0f;
+ lowerKnot = 1;
+ upperKnot = 2;
+ } else {
+ currentU = (alphaValue - keyFrames[i-1].knot)/
+ (keyFrames[i].knot - keyFrames[i-1].knot);
+ lowerKnot = i-1;
+ upperKnot = i;
+ }
+ }
+
+ /**
+ * Copies all KBSplinePathInterpolator 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
+ public void duplicateNode(Node originalNode, boolean forceDuplicate) {
+ super.duplicateNode(originalNode, forceDuplicate);
+ KBSplinePathInterpolator originalSpline =
+ (KBSplinePathInterpolator) originalNode;
+ setAlpha(originalSpline.getAlpha());
+ keysLength = originalSpline.keysLength;
+ keyFrames = new KBKeyFrame[keysLength];
+ System.arraycopy(originalSpline.keyFrames, 0,
+ keyFrames, 0, keysLength);
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/RotPosScaleTCBSplinePathInterpolator.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/RotPosScaleTCBSplinePathInterpolator.java
new file mode 100644
index 0000000..a286608
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/RotPosScaleTCBSplinePathInterpolator.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.interpolators;
+
+import org.jogamp.java3d.Alpha;
+import org.jogamp.java3d.Node;
+import org.jogamp.java3d.NodeComponent;
+import org.jogamp.java3d.RestrictedAccessException;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.vecmath.Matrix4d;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Quat4f;
+import org.jogamp.vecmath.Vector3d;
+import org.jogamp.vecmath.Vector3f;
+
+
+/**
+ * RotPosScaleTCBSplinePathInterpolator behavior. This class defines a
+ * behavior that varies the rotational, translational, and scale components
+ * of its target TransformGroup by using the Kochanek-Bartels cubic spline
+ * interpolation to interpolate among a series of key frames
+ * (using the value generated by the specified Alpha object). The
+ * interpolated position, orientation, and scale are used to generate
+ * a transform in the local coordinate system of this interpolator.
+ *
+ * @since Java3D 1.1
+ */
+
+public class RotPosScaleTCBSplinePathInterpolator
+extends TCBSplinePathInterpolator {
+
+ private Transform3D rotation = new Transform3D();
+ private Matrix4d tMat = new Matrix4d();
+ private Matrix4d sMat = new Matrix4d();
+ private Quat4f iQuat = new Quat4f(); // interpolated quaternion
+ private Vector3f iPos = new Vector3f(); // interpolated position
+ private Point3f iScale = new Point3f(); // interpolated scale
+
+ CubicSplineCurve cubicSplineCurve = new CubicSplineCurve();
+ CubicSplineSegment cubicSplineSegments[];
+ int numSegments;
+ int currentSegmentIndex;
+ CubicSplineSegment currentSegment;
+
+ // non-public, default constructor used by cloneNode
+ RotPosScaleTCBSplinePathInterpolator() {
+ }
+
+ /**
+ * Constructs a new RotPosScaleTCBSplinePathInterpolator object that
+ * varies the rotation, translation, and scale of the target
+ * TransformGroup's transform. At least 2 key frames are required for
+ * this interpolator. The first key
+ * frame's knot must have a value of 0.0 and the last knot must have a
+ * value of 1.0. An intermediate key frame with index k must have a
+ * knot value strictly greater than the knot value of a key frame with
+ * index less than k.
+ * @param alpha the alpha object for this interpolator
+ * @param target the TransformGroup node affected by this interpolator
+ * @param axisOfTransform the transform that specifies the local
+ * coordinate system in which this interpolator operates.
+ * @param keys an array of key frames that defien the motion path
+ */
+ public RotPosScaleTCBSplinePathInterpolator(Alpha alpha,
+ TransformGroup target,
+ Transform3D axisOfTransform,
+ TCBKeyFrame keys[]) {
+ super(alpha, target, axisOfTransform, keys);
+ // Create a spline curve using the derived key frames
+ cubicSplineCurve = new CubicSplineCurve(this.keyFrames);
+ numSegments = cubicSplineCurve.numSegments;
+
+ }
+
+
+ /**
+ * @deprecated As of Java 3D version 1.3, replaced by
+ * TransformInterpolator.setTransformAxis(Transform3D)
+ */
+ public void setAxisOfRotPosScale(Transform3D axisOfRotPosScale) {
+ setTransformAxis(axisOfRotPosScale);
+ }
+
+ /**
+ * @deprecated As of Java 3D version 1.3, replaced by
+ * TransformInterpolator.getTransformAxis()
+ */
+ public Transform3D getAxisOfRotPosScale() {
+ return getTransformAxis();
+ }
+
+ /**
+ * Computes the new transform for this interpolator for a given
+ * alpha value.
+ *
+ * @param alphaValue alpha value between 0.0 and 1.0
+ * @param transform object that receives the computed transform for
+ * the specified alpha value
+ *
+ * @since Java 3D 1.3
+ */
+ @Override
+ public void computeTransform(float alphaValue, Transform3D transform) {
+
+ // compute the current value of u from alpha and the
+ // determine lower and upper knot points
+ computePathInterpolation(alphaValue);
+
+ // Determine the segment within which we will be interpolating
+ currentSegmentIndex = this.lowerKnot - 1;
+
+ // if we are at the start of the curve
+ if (currentSegmentIndex == 0 && currentU == 0f) {
+
+ iQuat.set(keyFrames[1].quat);
+ iPos.set(keyFrames[1].position);
+ iScale.set(keyFrames[1].scale);
+
+ // if we are at the end of the curve
+ } else if (currentSegmentIndex == (numSegments-1) &&
+ currentU == 1.0) {
+
+ iQuat.set(keyFrames[upperKnot].quat);
+ iPos.set(keyFrames[upperKnot].position);
+ iScale.set(keyFrames[upperKnot].scale);
+
+ // if we are somewhere in between the curve
+ } else {
+
+ // Get a reference to the current spline segment i.e. the
+ // one bounded by lowerKnot and upperKnot
+ currentSegment
+ = cubicSplineCurve.getSegment(currentSegmentIndex);
+
+ // interpolate quaternions
+ currentSegment.getInterpolatedQuaternion(currentU,iQuat);
+
+ // interpolate position
+ currentSegment.getInterpolatedPositionVector(currentU,iPos);
+
+ // interpolate position
+ currentSegment.getInterpolatedScale(currentU,iScale);
+
+ }
+
+ // Alway normalize the quaternion
+ iQuat.normalize();
+ tMat.set(iQuat);
+
+ // Set the translation components.
+ tMat.m03 = iPos.x;
+ tMat.m13 = iPos.y;
+ tMat.m23 = iPos.z;
+ rotation.set(tMat);
+
+ // construct a Transform3D from: axis * rotation * axisInverse
+ transform.mul(axis, rotation);
+ transform.setScale(new Vector3d(iScale));
+ transform.mul(transform, axisInverse);
+
+ }
+
+ /**
+ * Used to create 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.
+ *
+ * @see Node#cloneTree
+ * @see Node#cloneNode
+ * @see Node#duplicateNode
+ * @see NodeComponent#setDuplicateOnCloneTree
+ */
+ @Override
+ public Node cloneNode(boolean forceDuplicate) {
+ RotPosScaleTCBSplinePathInterpolator spline =
+ new RotPosScaleTCBSplinePathInterpolator();
+ spline.duplicateNode(this, forceDuplicate);
+ return spline;
+ }
+
+ /**
+ * Copies RotPosScaleTCBSplinePathInterpolator 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
+ public void duplicateNode(Node originalNode, boolean forceDuplicate) {
+ super.duplicateNode(originalNode, forceDuplicate);
+ RotPosScaleTCBSplinePathInterpolator interpolator =
+ (RotPosScaleTCBSplinePathInterpolator)originalNode;
+
+ cubicSplineCurve = new CubicSplineCurve(interpolator.keyFrames);
+ numSegments = cubicSplineCurve.numSegments;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/TCBKeyFrame.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/TCBKeyFrame.java
new file mode 100644
index 0000000..262574a
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/TCBKeyFrame.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.interpolators;
+
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Quat4f;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+/**
+ * This class represents a Key Frame that can be used for Kochanek-Bartels
+ * (TCB) spline interpolation.
+ *
+ * @since Java3D 1.1
+ */
+
+public class TCBKeyFrame {
+
+ // Position, Rotation and Scale
+ public Point3f position;
+ public Quat4f quat;
+ public Point3f scale;
+
+ // Tension, Continuity & Bias
+ public float tension;
+ public float continuity;
+ public float bias;
+
+ // Sample Time
+ public float knot;
+
+ // Interpolation type (linear = 0 -> spline interpolation)
+ public int linear;
+
+ // default constructor
+ TCBKeyFrame () {
+ tension = continuity = bias = 0.0f;
+ }
+
+ public TCBKeyFrame (TCBKeyFrame kf) {
+ this(kf.knot, kf.linear, kf.position, kf.quat, kf.scale,
+ kf.tension, kf.continuity, kf.bias);
+
+ }
+
+ /**
+ * Creates a key frame using the given inputs.
+ *
+ * @param k knot value for this key frame
+ * @param l the linear flag (0 - Spline Interp, 1, Linear Interp
+ * @param pos the position at the key frame
+ * @param q the rotations at the key frame
+ * @param s the scales at the key frame
+ * @param t tension (-1.0 < t < 1.0)
+ * @param c continuity (-1.0 < c < 1.0)
+ * @param b bias (-1.0 < b < 1.0)
+ */
+ public TCBKeyFrame (float k, int l, Point3f pos, Quat4f q, Point3f s,
+ float t, float c, float b) {
+
+ knot = k;
+ linear = l;
+ position = new Point3f(pos);
+ quat = new Quat4f(q);
+ scale = new Point3f(s);
+
+ // Check for valid tension continuity and bias values
+ if (t < -1.0f || t > 1.0f) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBKeyFrame0"));
+ }
+
+ if (b < -1.0f || b > 1.0f) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBKeyFrame1"));
+ }
+
+ if (c < -1.0f || c > 1.0f) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBKeyFrame2"));
+ }
+
+ // copy valid tension, continuity and bias values
+ tension = t;
+ continuity = c;
+ bias = b;
+ }
+
+ /**
+ * Prints information comtained in this key frame
+ * @param tag string tag for identifying debug message
+ */
+ public void debugPrint (String tag) {
+ System.out.println ("\n" + tag);
+ System.out.println (" knot = " + knot);
+ System.out.println (" linear = " + linear);
+ System.out.println (" position(x,y,z) = " + position.x + " "
+ + position.y + " " + position.z);
+
+ System.out.println (" tension = " + tension);
+ System.out.println (" continuity = " + continuity);
+ System.out.println (" bias = " + bias);
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/TCBSplinePathInterpolator.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/TCBSplinePathInterpolator.java
new file mode 100644
index 0000000..fb6d0e0
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/TCBSplinePathInterpolator.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.interpolators;
+
+import org.jogamp.java3d.Alpha;
+import org.jogamp.java3d.Node;
+import org.jogamp.java3d.NodeComponent;
+import org.jogamp.java3d.RestrictedAccessException;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.java3d.TransformInterpolator;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+/**
+ * TCBSplinePathInterpolator behavior. This class defines the base class for
+ * all TCB (Kochanek-Bartels) Spline Path Interpolators.
+ *
+ * @since Java3D 1.1
+ */
+
+public abstract class TCBSplinePathInterpolator extends TransformInterpolator {
+
+ private int keysLength;
+
+ /**
+ * An array of KBKeyFrame for interpolator
+ */
+ protected TCBKeyFrame[] keyFrames;
+
+ /**
+ * This value is the distance between knots
+ * value which can be used in further calculations by the subclass.
+ */
+ protected float currentU;
+
+ /**
+ * The lower knot
+ */
+ protected int lowerKnot;
+
+ /**
+ * The upper knot
+ */
+ protected int upperKnot;
+
+ /**
+ * Constructs a TCBSplinePathInterpolator node with a null alpha value and
+ * a null target of TransformGroup
+ *
+ * @since Java 3D 1.3
+ */
+
+ TCBSplinePathInterpolator() {
+ }
+
+ /**
+ * @deprecated As of Java 3D version 1.3, replaced by
+ * TCBSplinePathInterpolator(Alpha, TransformGroup, TCBKeyFrame[])
+ */
+ public TCBSplinePathInterpolator(Alpha alpha, TCBKeyFrame keys[]) {
+ this(alpha, null, keys);
+ }
+
+ /**
+ * Constructs a new TCBSplinePathInterpolator object that interpolates
+ * between keyframes with specified alpha, target and default axisOfTransform
+ * set to identity. It takes at least two key frames. The first key
+ * frame's knot must have a value of 0.0 and the last knot must have a
+ * value of 1.0. An intermediate key frame with index k must have a
+ * knot value strictly greater than the knot value of a key frame with
+ * index less than k. Once this constructor has all the valid key frames
+ * it creates its own list of key fames that duplicates the first key frame
+ * at the beginning of the list and the last key frame at the end of the
+ * list.
+ * @param alpha the alpha object for this interpolator
+ * @param target the TransformGroup node effected by this TCBSplinePathInterpolator
+ * @param keys an array of TCBKeyFrame. Requires at least two key frames.
+ *
+ * @since Java 3D 1.3
+ */
+ public TCBSplinePathInterpolator(Alpha alpha, TransformGroup target, TCBKeyFrame keys[]) {
+ super(alpha, target);
+ processKeyFrames(keys);
+ }
+
+ /**
+ * Constructs a new TCBSplinePathInterpolator object that interpolates
+ * between keyframes with specified alpha, target and axisOfTransform.
+ * It takes at least two key frames. The first key
+ * frame's knot must have a value of 0.0 and the last knot must have a
+ * value of 1.0. An intermediate key frame with index k must have a
+ * knot value strictly greater than the knot value of a key frame with
+ * index less than k. Once this constructor has all the valid key frames
+ * it creates its own list of key fames that duplicates the first key frame
+ * at the beginning of the list and the last key frame at the end of the
+ * list.
+ * @param alpha the alpha object for this interpolator
+ * @param target the TransformGroup node effected by this TCBSplinePathInterpolator
+ * @param axisOfTransform the transform that defines the local coordinate
+ * @param keys an array of TCBKeyFrame. Requires at least two key frames.
+ *
+ * @since Java 3D 1.3
+ */
+ public TCBSplinePathInterpolator(Alpha alpha, TransformGroup target, Transform3D axisOfTransform,
+ TCBKeyFrame keys[]) {
+ super(alpha, target, axisOfTransform);
+ processKeyFrames(keys);
+ }
+
+ /**
+ * Process the new array of key frames
+ */
+ private void processKeyFrames( TCBKeyFrame keys[] ){
+
+ // Make sure that we have at least two key frames
+ keysLength = keys.length;
+ if (keysLength < 2) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator0"));
+
+ }
+
+ // Make sure that the first key frame's knot is equal to 0.0
+ if (keys[0].knot < -0.0001 || keys[0].knot > 0.0001) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator1"));
+ }
+
+ // Make sure that the last key frames knot is equal to 1.0
+ if (keys[keysLength-1].knot -1.0 < -0.0001 || keys[keysLength-1].knot -1.0 > 0.0001) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator2"));
+ }
+
+ // Make sure that all the knots are in sequence
+ for (int i = 0; i < keysLength; i++) {
+ if (i>0 && keys[i].knot < keys[i-1].knot) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("TCBSplinePathInterpolator3"));
+ }
+ }
+
+ // Make space for a leading and trailing key frame in addition to
+ // the keys passed in
+ keyFrames = new TCBKeyFrame[keysLength+2];
+ keyFrames[0] = new TCBKeyFrame();
+ keyFrames[0] = keys[0];
+ for (int i = 1; i < keysLength+1; i++) {
+ keyFrames[i] = keys[i-1];
+ }
+ keyFrames[keysLength+1] = new TCBKeyFrame();
+ keyFrames[keysLength+1] = keys[keysLength-1];
+
+ // Make key frame length reflect the 2 added key frames
+ keysLength += 2;
+ }
+
+ /**
+ * This method retrieves the length of the key frame array.
+ * @return the number of key frames
+ */
+ public int getArrayLength(){
+ return keysLength-2;
+ }
+
+ /**
+ * This method retrieves the key frame at the specified index.
+ * @param index the index of the key frame requested
+ * @return the key frame at the associated index
+ */
+ public TCBKeyFrame getKeyFrame (int index) {
+
+ // We add 1 to index because we have added a leading keyFrame
+ return this.keyFrames[index+1];
+ }
+
+ /**
+ * This method computes the bounding knot indices and interpolation value
+ * "CurrentU" given the specified value of alpha and the knots[] array.
+ * @param alphaValue alpha value between 0.0 and 1.0
+ *
+ * @since Java 3D 1.3
+ */
+ protected void computePathInterpolation(float alphaValue) {
+
+ // skip knots till we find the two we fall between
+ int i = 1;
+ int len = keysLength - 2;
+ while ((alphaValue > keyFrames[i].knot) && (i < len)) {
+ i++;
+ }
+
+ if (i == 1) {
+ currentU = 0f;
+ lowerKnot = 1;
+ upperKnot = 2;
+ } else {
+ currentU = (alphaValue - keyFrames[i-1].knot)/
+ (keyFrames[i].knot - keyFrames[i-1].knot);
+ lowerKnot = i-1;
+ upperKnot = i;
+ }
+ }
+
+ /**
+ * @deprecated As of Java 3D version 1.3, replaced by
+ * computePathInterpolation(float)
+ */
+ protected void computePathInterpolation() {
+ float value = (this.getAlpha()).value();
+ computePathInterpolation(value);
+ }
+
+ /**
+ * Copies all TCBSplinePathInterpolator 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
+ public void duplicateNode(Node originalNode, boolean forceDuplicate) {
+ super.duplicateNode(originalNode, forceDuplicate);
+ TCBSplinePathInterpolator originalSpline = (TCBSplinePathInterpolator) originalNode;
+ setAlpha(originalSpline.getAlpha());
+ keysLength = originalSpline.keysLength;
+ keyFrames = new TCBKeyFrame[keysLength];
+ System.arraycopy(originalSpline.keyFrames, 0,
+ keyFrames, 0, keysLength);
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/package.html b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/package.html
new file mode 100644
index 0000000..19ef214
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/interpolators/package.html
@@ -0,0 +1,11 @@
+
+
+
Provides spline-based interpolation behaviors.
+ + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/keyboard/KeyNavigator.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/keyboard/KeyNavigator.java new file mode 100644 index 0000000..6b44a61 --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/keyboard/KeyNavigator.java @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.keyboard; + +import java.awt.event.KeyEvent; + +import org.jogamp.java3d.Transform3D; +import org.jogamp.java3d.TransformGroup; +import org.jogamp.vecmath.Matrix4d; +import org.jogamp.vecmath.Point3d; +import org.jogamp.vecmath.Quat4d; +import org.jogamp.vecmath.Vector3d; + +/** + * This is the KeyNavigator class. It accumulates AWT key events (key + * press and key release) and computes a new transform based on the + * accumulated events and elapsed time. + */ +public class KeyNavigator { + + private Vector3d navVec; + private long time; + + private Vector3d fwdAcc; + private Vector3d bwdAcc; + private Vector3d leftAcc; + private Vector3d rightAcc; + private Vector3d upAcc; + private Vector3d downAcc; + + private Vector3d fwdDrag; + private Vector3d bwdDrag; + private Vector3d leftDrag; + private Vector3d rightDrag; + private Vector3d upDrag; + private Vector3d downDrag; + + private double fwdVMax; + private double bwdVMax; + private double leftVMax; + private double rightVMax; + private double upVMax; + private double downVMax; + + private float leftRotAngle; + private float rightRotAngle; + private float upRotAngle; + private float downRotAngle; + + private double mmx; + + private Vector3d a = new Vector3d(); + private Vector3d dv = new Vector3d(); + private Point3d dp = new Point3d(); + private Quat4d udQuat = new Quat4d(); + private Quat4d lrQuat = new Quat4d(); + private Vector3d vpPos = new Vector3d(); + private double vpScale; + private Quat4d vpQuat = new Quat4d(); + private Matrix4d vpMatrix = new Matrix4d(); + private Transform3D vpTrans = new Transform3D(); + private Matrix4d mat = new Matrix4d(); + private Vector3d nda = new Vector3d(); + private Vector3d temp = new Vector3d(); + private Transform3D nominal = new Transform3D(); + private TransformGroup targetTG; + + private static final int UP_ARROW = (1<<0); + private static final int DOWN_ARROW = (1<<1); + private static final int LEFT_ARROW = (1<<2); + private static final int RIGHT_ARROW = (1<<3); + private static final int PLUS_SIGN = (1<<4); + private static final int MINUS_SIGN = (1<<5); + private static final int PAGE_UP = (1<<6); + private static final int PAGE_DOWN = (1<<7); + private static final int HOME_DIR = (1<<8); + private static final int HOME_NOMINAL = (1<<9); + + private static final int SHIFT = (1<<10); + private static final int ALT = (1<<11); + private static final int META = (1<<12); + + private static final int KEY_UP = (1<<13); + private static final int KEY_DOWN = (1<<14); + + private int key_state = 0; + private int modifier_key_state = 0; + + + /** + * Constructs a new key navigator object that operates on the specified + * transform group. All parameters are set to their default, idle state. + * @param targetTG the target transform group + */ + public KeyNavigator(TransformGroup targetTG) { + this.targetTG = targetTG; + targetTG.getTransform(nominal); + + mmx = 128.0; + navVec = new Vector3d(0.0,0.0,0.0); + + fwdAcc = new Vector3d( 0.0, 0.0,-mmx); + bwdAcc = new Vector3d( 0.0, 0.0, mmx); + leftAcc = new Vector3d(-mmx, 0.0, 0.0); + rightAcc = new Vector3d( mmx, 0.0, 0.0); + upAcc = new Vector3d( 0.0, mmx, 0.0); + downAcc = new Vector3d( 0.0,-mmx, 0.0); + + fwdDrag = new Vector3d( 0.0, 0.0, mmx); + bwdDrag = new Vector3d( 0.0, 0.0,-mmx); + leftDrag = new Vector3d( mmx, 0.0, 0.0); + rightDrag = new Vector3d(-mmx, 0.0, 0.0); + upDrag = new Vector3d( 0.0,-mmx, 0.0); + downDrag = new Vector3d( 0.0, mmx, 0.0); + + fwdVMax = -mmx; + bwdVMax = mmx; + leftVMax = -mmx; + rightVMax = mmx; + upVMax = mmx; + downVMax = -mmx; + + leftRotAngle = (float) (-Math.PI*2.0/3.0); + rightRotAngle = (float) (Math.PI*2.0/3.0); + upRotAngle = (float) (Math.PI*2.0/3.0); + downRotAngle = (float) (-Math.PI*2.0/3.0); + + // Create Timer here. + time = System.currentTimeMillis(); + + } + + + private long getDeltaTime() { + long newTime = System.currentTimeMillis(); + long deltaTime = newTime - time; + time = newTime; + if (deltaTime > 2000) return 0; + else return deltaTime; + } + + /* Generate a quaterion as a rotation of radians av about 0/x 1/y 2/z axis */ + private void genRotQuat(double av, int axis, Quat4d q) { + double b; + + q.x = q.y = q.z = 0.0; + q.w = Math.cos(av/2.0); + + b = 1.0 - q.w*q.w; + + if (b > 0.0) + b = Math.sqrt(b); + else + return; + + if (av < 0.0) + b = -b; + if (axis == 0) + q.x = b; + else if (axis == 1) + q.y = b; + else + q.z = b; + + } + + private void accKeyAdd(Vector3d a, Vector3d da, Vector3d drag, double scaleVel) { + + /* Scaling of acceleration due to modification keys */ + nda.scale(scaleVel, da); + /* Addition of sufficent acceleration to counteract drag */ + nda.sub(drag); + + /* Summing into overall acceleration */ + a.add(nda); + + } + + + /** + * Computes a new transform for the next frame based on + * the current transform, accumulated keyboard inputs, and + * elapsed time. This new transform is written into the target + * transform group. + * This method should be called once per frame. + */ + public void integrateTransformChanges() { + double scaleVel, scaleRot, scaleScale, pre; + double udAng, lrAng, r; + + // Get the current View Platform transform into a transform3D object. + targetTG.getTransform(vpTrans); + // Extract the position, quaterion, and scale from the transform3D. + vpScale = vpTrans.get(vpQuat, vpPos); + + + double deltaTime = (double) getDeltaTime(); + deltaTime *= 0.001; + + /* Calculate scale due to modification keys */ + if ((modifier_key_state & SHIFT) != 0 && + (modifier_key_state & META) == 0) { + scaleVel = 3.0; scaleRot = 2.0; scaleScale = 4.0; + } + else if ((modifier_key_state & SHIFT) == 0 && + (modifier_key_state & META) != 0) { + scaleVel = 0.1; scaleRot = 0.1; scaleScale = 0.1; + } + else if ((modifier_key_state & SHIFT) != 0 && + (modifier_key_state & META) != 0) { + scaleVel = 0.3; scaleRot = 0.5; scaleScale = 0.1; + } + else { + scaleRot = scaleVel = 1.0; scaleScale = 4.0; + } + + /* + * Processing of rectiliear motion keys. + */ + + a.x = a.y = a.z = 0.0; /* acceleration initially 0 */ + + /* Acceleration due to keys being down */ + if ((key_state & UP_ARROW) != 0 && (key_state & DOWN_ARROW) == 0) + accKeyAdd(a, fwdAcc, fwdDrag, scaleVel); + else + if ((key_state & UP_ARROW) == 0 && (key_state & DOWN_ARROW) != 0) + accKeyAdd(a, bwdAcc, bwdDrag, scaleVel); + + if (((modifier_key_state & ALT) != 0) && + (key_state & LEFT_ARROW) != 0 && (key_state & RIGHT_ARROW) == 0) { + accKeyAdd(a, leftAcc, leftDrag, scaleVel); + } else + if (((modifier_key_state & ALT) != 0) && + (key_state & LEFT_ARROW) == 0 && (key_state & RIGHT_ARROW) != 0) + accKeyAdd(a, rightAcc, rightDrag, scaleVel); + + if (((modifier_key_state & ALT) != 0) && + (key_state & PAGE_UP) != 0 && (key_state & PAGE_DOWN) == 0) + accKeyAdd(a, upAcc, upDrag, scaleVel); + else + if (((modifier_key_state & ALT) != 0) && + (key_state & PAGE_UP) == 0 && (key_state & PAGE_DOWN) != 0) + accKeyAdd(a, downAcc, downDrag, scaleVel); + + + /* + * Drag due to new or existing motion + */ + pre = navVec.z + a.z * deltaTime; + if (pre < 0.0) { + if (pre + fwdDrag.z * deltaTime < 0.0) + a.add(fwdDrag); + else + a.z -= pre/deltaTime; + } else if (pre > 0.0) { + if (pre + bwdDrag.z * deltaTime > 0.0) + a.add(bwdDrag); + else + a.z -= pre/deltaTime; + } + + pre = navVec.x + a.x * deltaTime; + if (pre < 0.0) { + if (pre + leftDrag.x * deltaTime < 0.0) + a.add(leftDrag); + else + a.x -= pre/deltaTime; + } else if (pre > 0.0) { + if (pre + rightDrag.x * deltaTime > 0.0) + a.add(rightDrag); + else + a.x -= pre/deltaTime; + } + + pre = navVec.y + a.y * deltaTime; + if (pre < 0.0) { + if (pre + downDrag.y * deltaTime < 0.0) + a.add(downDrag); + else + a.y -= pre/deltaTime; + } else if (pre > 0.0) { + if (pre + upDrag.y * deltaTime > 0.0) + a.add(upDrag); + else + a.y -= pre/deltaTime; + } + + /* Integration of acceleration to velocity */ + dv.scale(deltaTime, a); + navVec.add(dv); + + /* Speed limits */ + if (navVec.z < scaleVel * fwdVMax) navVec.z = scaleVel * fwdVMax; + if (navVec.z > scaleVel * bwdVMax) navVec.z = scaleVel * bwdVMax; + if (navVec.x < scaleVel * leftVMax) navVec.x = scaleVel * leftVMax; + if (navVec.x > scaleVel * rightVMax) navVec.x = scaleVel* rightVMax; + if (navVec.y > scaleVel * upVMax) navVec.y = scaleVel * upVMax; + if (navVec.y < scaleVel * downVMax) navVec.y = scaleVel * downVMax; + + /* Integration of velocity to distance */ + dp.scale(deltaTime, navVec); + + /* Scale our motion to the current avatar scale */ + // 1.0 eventually needs to be a more complex value (see hs). + // r = workplace_coexistence_to_vworld_ori.scale/ + // one_to_one_coexistence_to_vworld_ori.scale; + r = vpScale/1.0; + dp.scale(r, dp); + + /* + * Processing of rotation motion keys. + */ + udAng = lrAng = 0.0; + + /* Rotation due to keys being down */ + if (((modifier_key_state & ALT) == 0) && + (key_state & LEFT_ARROW) != 0 && (key_state & RIGHT_ARROW) == 0) + lrAng = (double) leftRotAngle; + else if (((modifier_key_state & ALT) == 0) && + (key_state & LEFT_ARROW) == 0 && (key_state & RIGHT_ARROW) != 0) + lrAng = (double) rightRotAngle; + + if (((modifier_key_state & ALT) == 0) && + (key_state & PAGE_UP) != 0 && (key_state & PAGE_DOWN) == 0) + udAng = (double) upRotAngle; + else if (((modifier_key_state & ALT) == 0) && + (key_state & PAGE_UP) == 0 && (key_state & PAGE_DOWN) != 0) + udAng = (double) downRotAngle; + + lrAng *= scaleRot; + udAng *= scaleRot; + + /* Scaling of angle change to delta time */ + lrAng *= deltaTime; + udAng *= deltaTime; + + + /* Addition to existing orientation */ + // vr_quat_inverse(&workplace_coexistence_to_vworld_ori.quat, &vpQuat); + // vpQuat gotten at top of method. + vpQuat.inverse(); + + if(lrAng != 0.0) { + genRotQuat(lrAng, 1, lrQuat); + vpQuat.mul(lrQuat, vpQuat); + } + + if(udAng != 0.0) { + genRotQuat(udAng, 0, udQuat); + vpQuat.mul(udQuat, vpQuat); + } + + /* Rotation of distance vector */ + vpQuat.inverse(); + vpQuat.normalize(); /* Improvment over HoloSketch */ + mat.set(vpQuat); + mat.transform(dp); + + /* Processing of scale */ + if ((key_state & PLUS_SIGN) != 0) { + vpScale *= (1.0 + (scaleScale*deltaTime)); + if (vpScale > 10e+14) vpScale = 1.0; + } else if ((key_state & MINUS_SIGN) != 0) { + vpScale /= (1.0 + (scaleScale*deltaTime)); + if (vpScale < 10e-14) vpScale = 1.0; + } + + // add dp into current vp position. + vpPos.add(dp); + + if ((key_state & HOME_NOMINAL) != 0) { + resetVelocity(); + // Extract the position, quaterion, and scale from the nominal + // transform + vpScale = nominal.get(vpQuat, vpPos); + } + + + /* Final update of view platform */ + // Put the transform back into the transform group. + vpTrans.set(vpQuat, vpPos, vpScale); + targetTG.setTransform(vpTrans); + } + + + /** + * Resets the keyboard navigation velocity to 0. + */ + private void resetVelocity() { + navVec.x = navVec.y = navVec.z = 0.0; + } + + + /** + * Processed a keyboard event. This routine should be called + * every time a KEY_PRESSED or KEY_RELEASED event is received. + * @param keyEvent the AWT key event + */ + public void processKeyEvent(KeyEvent keyEvent) { + int keyCode = keyEvent.getKeyCode(); + int keyChar = keyEvent.getKeyChar(); + +//System.err.println("keyCode " + keyCode + " keyChar " + keyChar); + + if (keyEvent.getID() == KeyEvent.KEY_RELEASED) { + if (keyChar == '+') key_state &= ~PLUS_SIGN; + else + switch (keyCode) { + case KeyEvent.VK_UP: key_state &= ~UP_ARROW; break; + case KeyEvent.VK_DOWN: key_state &= ~DOWN_ARROW; break; + case KeyEvent.VK_LEFT: key_state &= ~LEFT_ARROW; break; + case KeyEvent.VK_RIGHT: key_state &= ~RIGHT_ARROW; break; + case KeyEvent.VK_PAGE_UP: key_state &= ~PAGE_UP; break; + case KeyEvent.VK_PAGE_DOWN: key_state &= ~PAGE_DOWN; break; + case KeyEvent.VK_EQUALS: key_state &= ~HOME_NOMINAL;break; + default: switch(keyChar) { + case '-': key_state &= ~MINUS_SIGN; break; + } + } + } else if (keyEvent.getID() == KeyEvent.KEY_PRESSED) { + if (keyChar == '+') key_state |= PLUS_SIGN; + switch (keyCode) { + case KeyEvent.VK_UP: key_state |= UP_ARROW; break; + case KeyEvent.VK_DOWN: key_state |= DOWN_ARROW; break; + case KeyEvent.VK_LEFT: key_state |= LEFT_ARROW; break; + case KeyEvent.VK_RIGHT: key_state |= RIGHT_ARROW; break; + case KeyEvent.VK_PAGE_UP: key_state |= PAGE_UP; break; + case KeyEvent.VK_PAGE_DOWN: key_state |= PAGE_DOWN; break; + case KeyEvent.VK_EQUALS: key_state |= HOME_NOMINAL;break; + default: switch(keyChar) { + case '-': key_state |= MINUS_SIGN; break; + } + } + } + + /* Check modifier keys */ + if (keyEvent.isShiftDown()) + modifier_key_state |= SHIFT; + else + modifier_key_state &= ~SHIFT; + + if (keyEvent.isMetaDown()) + modifier_key_state |= META; + else + modifier_key_state &= ~META; + + if (keyEvent.isAltDown()) + modifier_key_state |= ALT; + else + modifier_key_state &= ~ALT; + +//System.err.println("keyCode " + keyEvent.getKeyCode() + " modifiers " + keyEvent.getModifiers()); +//System.err.println("SHIFT_MASK " + keyEvent.SHIFT_MASK); +//System.err.println("CTRL_MASK " + keyEvent.CTRL_MASK); +//System.err.println("META_MASK " + keyEvent.META_MASK); +//System.err.println("ALT_MASK " + keyEvent.ALT_MASK); + + } +} diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/keyboard/KeyNavigatorBehavior.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/keyboard/KeyNavigatorBehavior.java new file mode 100644 index 0000000..78ecb41 --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/keyboard/KeyNavigatorBehavior.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.keyboard; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.util.Enumeration; +import java.util.LinkedList; + +import org.jogamp.java3d.Behavior; +import org.jogamp.java3d.TransformGroup; +import org.jogamp.java3d.WakeupCondition; +import org.jogamp.java3d.WakeupCriterion; +import org.jogamp.java3d.WakeupOnAWTEvent; +import org.jogamp.java3d.WakeupOnBehaviorPost; +import org.jogamp.java3d.WakeupOnElapsedFrames; +import org.jogamp.java3d.WakeupOr; + +import org.jogamp.java3d.internal.J3dUtilsI18N; + +/** + * This class is a simple behavior that invokes the KeyNavigator + * to modify the view platform transform. + */ +public class KeyNavigatorBehavior extends Behavior implements KeyListener { + private WakeupCriterion w1 = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED); + private WakeupCriterion w2 = new WakeupOnAWTEvent(KeyEvent.KEY_RELEASED); + private WakeupOnElapsedFrames w3 = new WakeupOnElapsedFrames(0); + private WakeupCriterion[] warray = { w1, w2, w3 }; + private WakeupCondition w = new WakeupOr(warray); + private KeyEvent eventKey; + private KeyNavigator keyNavigator; + private boolean listener = false; + + private LinkedList eventq; + + + /** + * Override Behavior's initialize method to setup wakeup criteria. + */ + @Override + public void initialize() { + // Establish initial wakeup criteria + if (listener) { + w1 = new WakeupOnBehaviorPost(this, KeyEvent.KEY_PRESSED); + w2 = new WakeupOnBehaviorPost(this, KeyEvent.KEY_RELEASED); + warray[0] = w1; + warray[1] = w2; + w = new WakeupOr(warray); + eventq = new LinkedList(); + } + wakeupOn(w); + } + + /** + * Override Behavior's stimulus method to handle the event. + */ + @Override + public void processStimulus(Enumeration criteria) { + WakeupOnAWTEvent ev; + WakeupCriterion genericEvt; + AWTEvent[] events; + boolean sawFrame = false; + + while (criteria.hasMoreElements()) { + genericEvt = (WakeupCriterion) criteria.nextElement(); + if (genericEvt instanceof WakeupOnAWTEvent) { + ev = (WakeupOnAWTEvent) genericEvt; + events = ev.getAWTEvent(); + processAWTEvent(events); + } else if (genericEvt instanceof WakeupOnElapsedFrames && + eventKey != null) { + sawFrame = true; + } else if ((genericEvt instanceof WakeupOnBehaviorPost)) { + while(true) { + // access to the queue must be synchronized + synchronized (eventq) { + if (eventq.isEmpty()) break; + eventKey = (KeyEvent)eventq.remove(0); + if (eventKey.getID() == KeyEvent.KEY_PRESSED || + eventKey.getID() == KeyEvent.KEY_RELEASED) { + keyNavigator.processKeyEvent(eventKey); + } + } + } + } + } + if (sawFrame) + keyNavigator.integrateTransformChanges(); + + // Set wakeup criteria for next time + wakeupOn(w); + } + + /** + * Process a keyboard event + */ + private void processAWTEvent(AWTEvent[] events) { + for (int loop = 0; loop < events.length; loop++) { + if (events[loop] instanceof KeyEvent) { + eventKey = (KeyEvent) events[loop]; + // change the transformation; for example to zoom + if (eventKey.getID() == KeyEvent.KEY_PRESSED || + eventKey.getID() == KeyEvent.KEY_RELEASED) { + //System.out.println("Keyboard is hit! " + eventKey); + keyNavigator.processKeyEvent(eventKey); + } + } + } + } + + /** + * Adds this behavior as a KeyListener to the specified component. + * This method can only be called if + * the behavior was created with one of the constructors that takes + * a Component as a parameter. + * @param c The component to add the KeyListener to. + * @exception IllegalStateException if the behavior was not created + * as a listener + * @since Java 3D 1.2.1 + */ + public void addListener(Component c) { + if (!listener) { + throw new IllegalStateException(J3dUtilsI18N.getString("Behavior0")); + } + c.addKeyListener(this); + } + + /** + * Constructs a new key navigator behavior node that operates + * on the specified transform group. + * @param targetTG the target transform group + */ + public KeyNavigatorBehavior(TransformGroup targetTG) { + keyNavigator = new KeyNavigator(targetTG); + } + + /** + * Constructs a key navigator behavior that uses AWT listeners + * and behavior posts rather than WakeupOnAWTEvent. The behavior + * is added to the specified Component and works on the given + * TransformGroup. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param c The component to add the KeyListener to. + * @param targetTG The target transform group. + * @since Java 3D 1.2.1 + */ + public KeyNavigatorBehavior(Component c, TransformGroup targetTG) { + this(targetTG); + if (c != null) { + c.addKeyListener(this); + } + listener = true; + } + + @Override + public void keyPressed(KeyEvent evt) { +// System.out.println("keyPressed"); + + // add new event to the queue + // must be MT safe + synchronized (eventq) { + eventq.add(evt); + // only need to post if this is the only event in the queue + if (eventq.size() == 1) postId(KeyEvent.KEY_PRESSED); + } + } + + @Override + public void keyReleased(KeyEvent evt) { +// System.out.println("keyReleased"); + + // add new event to the queue + // must be MT safe + synchronized (eventq) { + eventq.add(evt); + // only need to post if this is the only event in the queue + if (eventq.size() == 1) postId(KeyEvent.KEY_RELEASED); + } + } + + @Override + public void keyTyped(KeyEvent evt) {} + +} diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/keyboard/package.html b/src/classes/share/org/jogamp/java3d/utils/behaviors/keyboard/package.html new file mode 100644 index 0000000..efe76d5 --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/keyboard/package.html @@ -0,0 +1,11 @@ + + + + +Provides keyboard navigation utility classes.
+ + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseBehavior.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseBehavior.java new file mode 100644 index 0000000..cfc0c2c --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseBehavior.java @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.mouse; + +import java.awt.Component; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.util.Enumeration; +import java.util.LinkedList; + +import org.jogamp.java3d.Behavior; +import org.jogamp.java3d.Transform3D; +import org.jogamp.java3d.TransformGroup; +import org.jogamp.java3d.WakeupCriterion; +import org.jogamp.java3d.WakeupOnAWTEvent; +import org.jogamp.java3d.WakeupOnBehaviorPost; +import org.jogamp.java3d.WakeupOr; + +import org.jogamp.java3d.internal.J3dUtilsI18N; + + +/** + * Base class for all mouse manipulators (see MouseRotate, MouseZoom + * and MouseTranslate for + * examples of how to extend this base class). + */ + +public abstract class MouseBehavior extends Behavior + implements MouseListener, MouseMotionListener, MouseWheelListener { + + private boolean listener = false; + + protected WakeupCriterion[] mouseEvents; + protected WakeupOr mouseCriterion; + protected int x, y; + protected int x_last, y_last; + protected TransformGroup transformGroup; + protected Transform3D transformX; + protected Transform3D transformY; + protected Transform3D currXform; + protected boolean buttonPress = false; + protected boolean reset = false; + protected boolean invert = false; + protected boolean wakeUp = false; + protected int flags = 0; + + // to queue the mouse events + protected LinkedList mouseq; + + // true if this behavior is enable + protected boolean enable = true; + + /** + * Set this flag if you want to manually wakeup the behavior. + */ + public static final int MANUAL_WAKEUP = 0x1; + + /** + * Set this flag if you want to invert the inputs. This is useful when + * the transform for the view platform is being changed instead of the + * transform for the object. + */ + public static final int INVERT_INPUT = 0x2; + + /** + * Creates a mouse behavior object with a given transform group. + * @param transformGroup The transform group to be manipulated. + */ + public MouseBehavior(TransformGroup transformGroup) { + super(); + // need to remove old behavior from group + this.transformGroup = transformGroup; + currXform = new Transform3D(); + transformX = new Transform3D(); + transformY = new Transform3D(); + reset = true; + } + + /** + * Initializes standard fields. Note that this behavior still + * needs a transform group to work on (use setTransformGroup(tg)) and + * the transform group must add this behavior. + * @param format flags + */ + public MouseBehavior(int format) { + super(); + flags = format; + currXform = new Transform3D(); + transformX = new Transform3D(); + transformY = new Transform3D(); + reset = true; + } + + /** + * Creates a mouse behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behaviors is added to + * the specified Component and works on the given TransformGroup. + * A null component can be passed to specify the behaviors should use + * listeners. Components can then be added to the behavior with the + * addListener(Component c) method. + * @param c The Component to add the MouseListener and + * MouseMotionListener to. + * @param transformGroup The TransformGroup to operate on. + * @since Java 3D 1.2.1 + */ + public MouseBehavior(Component c, TransformGroup transformGroup) { + this(transformGroup); + if (c != null) { + c.addMouseListener(this); + c.addMouseMotionListener(this); + c.addMouseWheelListener(this); + } + listener = true; + } + + /** + * Creates a mouse behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and the transform + * group must add this behavior. + * @param format interesting flags (wakeup conditions). + * @since Java 3D 1.2.1 + */ + public MouseBehavior(Component c, int format) { + this(format); + if (c != null) { + c.addMouseListener(this); + c.addMouseMotionListener(this); + c.addMouseWheelListener(this); + } + listener = true; + } + + /** + * Swap a new transformGroup replacing the old one. This allows + * manipulators to operate on different nodes. + * + * @param transformGroup The *new* transform group to be manipulated. + */ + public void setTransformGroup(TransformGroup transformGroup){ + // need to remove old behavior from group + this.transformGroup = transformGroup; + currXform = new Transform3D(); + transformX = new Transform3D(); + transformY = new Transform3D(); + reset = true; + } + + /** + * Return the transformGroup on which this node is operating + */ + public TransformGroup getTransformGroup() { + return this.transformGroup; + } + + /** Initializes the behavior. + */ + + @Override + public void initialize() { + mouseEvents = new WakeupCriterion[4]; + + if (!listener) { + mouseEvents[0] = new WakeupOnAWTEvent(MouseEvent.MOUSE_DRAGGED); + mouseEvents[1] = new WakeupOnAWTEvent(MouseEvent.MOUSE_PRESSED); + mouseEvents[2] = new WakeupOnAWTEvent(MouseEvent.MOUSE_RELEASED); + mouseEvents[3] = new WakeupOnAWTEvent(MouseEvent.MOUSE_WHEEL); + } + else { + mouseEvents[0] = new WakeupOnBehaviorPost(this, + MouseEvent.MOUSE_DRAGGED); + mouseEvents[1] = new WakeupOnBehaviorPost(this, + MouseEvent.MOUSE_PRESSED); + mouseEvents[2] = new WakeupOnBehaviorPost(this, + MouseEvent.MOUSE_RELEASED); + mouseEvents[3] = new WakeupOnBehaviorPost(this, + MouseEvent.MOUSE_WHEEL); + mouseq = new LinkedList(); + } + mouseCriterion = new WakeupOr(mouseEvents); + wakeupOn (mouseCriterion); + x = 0; + y = 0; + x_last = 0; + y_last = 0; + } + + /** + * Manually wake up the behavior. If MANUAL_WAKEUP flag was set upon + * creation, you must wake up this behavior each time it is handled. + */ + + public void wakeup() + { + wakeUp = true; + } + + /** + * Handles mouse events + */ + public void processMouseEvent(MouseEvent evt) { + if (evt.getID()==MouseEvent.MOUSE_PRESSED) { + buttonPress = true; + return; + } + else if (evt.getID()==MouseEvent.MOUSE_RELEASED){ + buttonPress = false; + wakeUp = false; + } + /* + else if (evt.getID() == MouseEvent.MOUSE_MOVED) { + // Process mouse move event + } + else if (evt.getID() == MouseEvent.MOUSE_WHEEL) { + // Process mouse wheel event + } + */ + } + + /** + * All mouse manipulators must implement this. + */ + @Override + public abstract void processStimulus (Enumeration criteria); + + /** + * Adds this behavior as a MouseListener, mouseWheelListener and MouseMotionListener to + * the specified component. This method can only be called if + * the behavior was created with one of the constructors that takes + * a Component as a parameter. + * @param c The component to add the MouseListener, MouseWheelListener and + * MouseMotionListener to. + * @exception IllegalStateException if the behavior was not created + * as a listener + * @since Java 3D 1.2.1 + */ + public void addListener(Component c) { + if (!listener) { + throw new IllegalStateException(J3dUtilsI18N.getString("Behavior0")); + } + c.addMouseListener(this); + c.addMouseMotionListener(this); + c.addMouseWheelListener(this); + } + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mouseEntered(MouseEvent e) {} + @Override + public void mouseExited(MouseEvent e) {} + + @Override + public void mousePressed(MouseEvent e) { +// System.out.println("mousePressed"); + + // add new event to the queue + // must be MT safe + if (enable) { + synchronized (mouseq) { + mouseq.add(e); + // only need to post if this is the only event in the queue + if (mouseq.size() == 1) + postId(MouseEvent.MOUSE_PRESSED); + } + } + } + + @Override + public void mouseReleased(MouseEvent e) { +// System.out.println("mouseReleased"); + + // add new event to the queue + // must be MT safe + if (enable) { + synchronized (mouseq) { + mouseq.add(e); + // only need to post if this is the only event in the queue + if (mouseq.size() == 1) + postId(MouseEvent.MOUSE_RELEASED); + } + } + } + + @Override + public void mouseDragged(MouseEvent e) { +// System.out.println("mouseDragged"); + + // add new event to the to the queue + // must be MT safe. + if (enable) { + synchronized (mouseq) { + mouseq.add(e); + // only need to post if this is the only event in the queue + if (mouseq.size() == 1) + postId(MouseEvent.MOUSE_DRAGGED); + } + } + } + + @Override + public void mouseMoved(MouseEvent e) {} + + @Override + public void setEnable(boolean state) { + super.setEnable(state); + this.enable = state; + if (!enable && (mouseq != null)) { + mouseq.clear(); + } + } + + @Override + public void mouseWheelMoved(MouseWheelEvent e){ +// System.out.println("MouseBehavior : mouseWheel enable = " + enable ); + + // add new event to the to the queue + // must be MT safe. + if (enable) { + synchronized (mouseq) { + mouseq.add(e); + // only need to post if this is the only event in the queue + if (mouseq.size() == 1) + postId(MouseEvent.MOUSE_WHEEL); + } + } + } +} + + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseBehaviorCallback.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseBehaviorCallback.java new file mode 100644 index 0000000..4965ccf --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseBehaviorCallback.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.mouse; + +import org.jogamp.java3d.Transform3D; + +/** + * The MouseBehaviorCallback interface allows a class to be notified + * when the transform is changed by one of the MouseBehaviors. The + * class that is interested in transform changes implements this + * interface, and the object created with that class is registered + * with the desired subclass of MouseBehavior using the + *setupCallback
method. When the transform changes, the
+ * registered object's transformChanged
method is
+ * invoked.
+ */
+
+public interface MouseBehaviorCallback {
+
+ public final static int ROTATE=0;
+ public final static int TRANSLATE=1;
+ public final static int ZOOM=2;
+
+ /**
+ * Classes implementing this interface that are registered with
+ * one of the MouseBehaviors will be called every time the
+ * behavior updates the Transform
+ * @param type will be one of ROTATE, TRANSLATE or ZOOM
+ */
+ public void transformChanged( int type, Transform3D transform );
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseRotate.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseRotate.java
new file mode 100644
index 0000000..65f0c09
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseRotate.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.mouse;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+import java.awt.event.MouseEvent;
+import java.util.Enumeration;
+
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.java3d.WakeupCriterion;
+import org.jogamp.java3d.WakeupOnAWTEvent;
+import org.jogamp.java3d.WakeupOnBehaviorPost;
+import org.jogamp.vecmath.Matrix4d;
+import org.jogamp.vecmath.Vector3d;
+
+/**
+ * MouseRotate is a Java3D behavior object that lets users control the
+ * rotation of an object via a mouse.
+ * + * To use this utility, first create a transform group that this + * rotate behavior will operate on. Then, + *
+ * The above code will add the rotate behavior to the transform + * group. The user can rotate any object attached to the objTrans. + */ + +public class MouseRotate extends MouseBehavior { + double x_angle, y_angle; + double x_factor = .03; + double y_factor = .03; + + private MouseBehaviorCallback callback = null; + + /** + * Creates a rotate behavior given the transform group. + * @param transformGroup The transformGroup to operate on. + */ + public MouseRotate(TransformGroup transformGroup) { + super(transformGroup); + } + + /** + * Creates a default mouse rotate behavior. + **/ + public MouseRotate() { + super(0); + } + + /** + * Creates a rotate behavior. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and + * the transform group must add this behavior. + * @param flags interesting flags (wakeup conditions). + */ + public MouseRotate(int flags) { + super(flags); + } + + /** + * Creates a rotate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param c The Component to add the MouseListener + * and MouseMotionListener to. + * @since Java 3D 1.2.1 + */ + public MouseRotate(Component c) { + super(c, 0); + } + + /** + * Creates a rotate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behaviors is added to + * the specified Component and works on the given TransformGroup. + * A null component can be passed to specify the behavior should use + * listeners. Components can then be added to the behavior with the + * addListener(Component c) method. + * @param c The Component to add the MouseListener and + * MouseMotionListener to. + * @param transformGroup The TransformGroup to operate on. + * @since Java 3D 1.2.1 + */ + public MouseRotate(Component c, TransformGroup transformGroup) { + super(c, transformGroup); + } + + /** + * Creates a rotate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added to + * the behavior with the addListener(Component c) method. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and the transform + * group must add this behavior. + * @param flags interesting flags (wakeup conditions). + * @since Java 3D 1.2.1 + */ + public MouseRotate(Component c, int flags) { + super(c, flags); + } + + @Override + public void initialize() { + super.initialize(); + x_angle = 0; + y_angle = 0; + if ((flags & INVERT_INPUT) == INVERT_INPUT) { + invert = true; + x_factor *= -1; + y_factor *= -1; + } + } + + /** + * Return the x-axis movement multipler. + **/ + public double getXFactor() { + return x_factor; + } + + /** + * Return the y-axis movement multipler. + **/ + public double getYFactor() { + return y_factor; + } + + + /** + * Set the x-axis amd y-axis movement multipler with factor. + **/ + public void setFactor( double factor) { + x_factor = y_factor = factor; + } + + /** + * Set the x-axis amd y-axis movement multipler with xFactor and yFactor + * respectively. + **/ + public void setFactor( double xFactor, double yFactor) { + x_factor = xFactor; + y_factor = yFactor; + } + + @Override + public void processStimulus (Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] events; + MouseEvent evt; +// int id; +// int dx, dy; + + while (criteria.hasMoreElements()) { + wakeup = (WakeupCriterion) criteria.nextElement(); + if (wakeup instanceof WakeupOnAWTEvent) { + events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); + if (events.length > 0) { + evt = (MouseEvent) events[events.length-1]; + doProcess(evt); + } + } + + else if (wakeup instanceof WakeupOnBehaviorPost) { + while (true) { + // access to the queue must be synchronized + synchronized (mouseq) { + if (mouseq.isEmpty()) break; + evt = (MouseEvent)mouseq.remove(0); + // consolidate MOUSE_DRAG events + while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) && + !mouseq.isEmpty() && + (((MouseEvent)mouseq.get(0)).getID() == + MouseEvent.MOUSE_DRAGGED)) { + evt = (MouseEvent)mouseq.remove(0); + } + } + doProcess(evt); + } + } + + } + wakeupOn (mouseCriterion); + } + + void doProcess(MouseEvent evt) { + int id; + int dx, dy; + + processMouseEvent(evt); + if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || + ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))) { + id = evt.getID(); + if ((id == MouseEvent.MOUSE_DRAGGED) && + !evt.isMetaDown() && ! evt.isAltDown()){ + x = evt.getX(); + y = evt.getY(); + + dx = x - x_last; + dy = y - y_last; + + if (!reset){ + x_angle = dy * y_factor; + y_angle = dx * x_factor; + + transformX.rotX(x_angle); + transformY.rotY(y_angle); + + transformGroup.getTransform(currXform); + + Matrix4d mat = new Matrix4d(); + // Remember old matrix + currXform.get(mat); + + // Translate to origin + currXform.setTranslation(new Vector3d(0.0,0.0,0.0)); + if (invert) { + currXform.mul(currXform, transformX); + currXform.mul(currXform, transformY); + } else { + currXform.mul(transformX, currXform); + currXform.mul(transformY, currXform); + } + + // Set old translation back + Vector3d translation = new + Vector3d(mat.m03, mat.m13, mat.m23); + currXform.setTranslation(translation); + + // Update xform + transformGroup.setTransform(currXform); + + transformChanged( currXform ); + + if (callback!=null) + callback.transformChanged( MouseBehaviorCallback.ROTATE, + currXform ); + } + else { + reset = false; + } + + x_last = x; + y_last = y; + } + else if (id == MouseEvent.MOUSE_PRESSED) { + x_last = evt.getX(); + y_last = evt.getY(); + } + } + } + + /** + * Users can overload this method which is called every time + * the Behavior updates the transform + * + * Default implementation does nothing + */ + public void transformChanged( Transform3D transform ) { + } + + + /** + * The transformChanged method in the callback class will + * be called every time the transform is updated + */ + public void setupCallback( MouseBehaviorCallback callback ) { + this.callback = callback; + } +} diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseTranslate.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseTranslate.java new file mode 100644 index 0000000..44bd43b --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseTranslate.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.mouse; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.event.MouseEvent; +import java.util.Enumeration; + +import org.jogamp.java3d.Transform3D; +import org.jogamp.java3d.TransformGroup; +import org.jogamp.java3d.WakeupCriterion; +import org.jogamp.java3d.WakeupOnAWTEvent; +import org.jogamp.java3d.WakeupOnBehaviorPost; +import org.jogamp.vecmath.Vector3d; + +/** + * MouseTranslate is a Java3D behavior object that lets users control the + * translation (X, Y) of an object via a mouse drag motion with the third + * mouse button (alt-click on PC). See MouseRotate for similar usage info. + */ + +public class MouseTranslate extends MouseBehavior { + + double x_factor = .02; + double y_factor = .02; + Vector3d translation = new Vector3d(); + + private MouseBehaviorCallback callback = null; + + /** + * Creates a mouse translate behavior given the transform group. + * @param transformGroup The transformGroup to operate on. + */ + public MouseTranslate(TransformGroup transformGroup) { + super(transformGroup); + } + + /** + * Creates a default translate behavior. + */ + public MouseTranslate(){ + super(0); + } + + /** + * Creates a translate behavior. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and + * the transform group must add this behavior. + * @param flags + */ + public MouseTranslate(int flags) { + super(flags); + } + + /** + * Creates a translate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param c The Component to add the MouseListener + * and MouseMotionListener to. + * @since Java 3D 1.2.1 + */ + public MouseTranslate(Component c) { + super(c, 0); + } + + /** + * Creates a translate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behaviors is added to + * the specified Component and works on the given TransformGroup. + * A null component can be passed to specify the behavior should use + * listeners. Components can then be added to the behavior with the + * addListener(Component c) method. + * @param c The Component to add the MouseListener and + * MouseMotionListener to. + * @param transformGroup The TransformGroup to operate on. + * @since Java 3D 1.2.1 + */ + public MouseTranslate(Component c, TransformGroup transformGroup) { + super(c, transformGroup); + } + + /** + * Creates a translate behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added to + * the behavior with the addListener(Component c) method. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and the transform + * group must add this behavior. + * @param flags interesting flags (wakeup conditions). + * @since Java 3D 1.2.1 + */ + public MouseTranslate(Component c, int flags) { + super(c, flags); + } + + @Override + public void initialize() { + super.initialize(); + if ((flags & INVERT_INPUT) == INVERT_INPUT) { + invert = true; + x_factor *= -1; + y_factor *= -1; + } + } + + /** + * Return the x-axis movement multipler. + **/ + public double getXFactor() { + return x_factor; + } + + /** + * Return the y-axis movement multipler. + **/ + public double getYFactor() { + return y_factor; + } + + /** + * Set the x-axis amd y-axis movement multipler with factor. + **/ + public void setFactor( double factor) { + x_factor = y_factor = factor; + } + + /** + * Set the x-axis amd y-axis movement multipler with xFactor and yFactor + * respectively. + **/ + public void setFactor( double xFactor, double yFactor) { + x_factor = xFactor; + y_factor = yFactor; + } + + @Override + public void processStimulus (Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] events; + MouseEvent evt; +// int id; +// int dx, dy; + + while (criteria.hasMoreElements()) { + wakeup = (WakeupCriterion) criteria.nextElement(); + + if (wakeup instanceof WakeupOnAWTEvent) { + events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); + if (events.length > 0) { + evt = (MouseEvent) events[events.length-1]; + doProcess(evt); + } + } + + else if (wakeup instanceof WakeupOnBehaviorPost) { + while (true) { + // access to the queue must be synchronized + synchronized (mouseq) { + if (mouseq.isEmpty()) break; + evt = (MouseEvent)mouseq.remove(0); + // consolodate MOUSE_DRAG events + while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) && + !mouseq.isEmpty() && + (((MouseEvent)mouseq.get(0)).getID() == + MouseEvent.MOUSE_DRAGGED)) { + evt = (MouseEvent)mouseq.remove(0); + } + } + doProcess(evt); + } + } + + } + wakeupOn(mouseCriterion); + } + + void doProcess(MouseEvent evt) { + int id; + int dx, dy; + + processMouseEvent(evt); + + if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || + ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))){ + id = evt.getID(); + if ((id == MouseEvent.MOUSE_DRAGGED) && + !evt.isAltDown() && evt.isMetaDown()) { + + x = evt.getX(); + y = evt.getY(); + + dx = x - x_last; + dy = y - y_last; + + if ((!reset) && ((Math.abs(dy) < 50) && (Math.abs(dx) < 50))) { + //System.out.println("dx " + dx + " dy " + dy); + transformGroup.getTransform(currXform); + + translation.x = dx*x_factor; + translation.y = -dy*y_factor; + + transformX.set(translation); + + if (invert) { + currXform.mul(currXform, transformX); + } else { + currXform.mul(transformX, currXform); + } + + transformGroup.setTransform(currXform); + + transformChanged( currXform ); + + if (callback!=null) + callback.transformChanged( MouseBehaviorCallback.TRANSLATE, + currXform ); + + } + else { + reset = false; + } + x_last = x; + y_last = y; + } + else if (id == MouseEvent.MOUSE_PRESSED) { + x_last = evt.getX(); + y_last = evt.getY(); + } + } + } + + /** + * Users can overload this method which is called every time + * the Behavior updates the transform + * + * Default implementation does nothing + */ + public void transformChanged( Transform3D transform ) { + } + + /** + * The transformChanged method in the callback class will + * be called every time the transform is updated + */ + public void setupCallback( MouseBehaviorCallback callback ) { + this.callback = callback; + } +} + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseWheelZoom.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseWheelZoom.java new file mode 100644 index 0000000..3e18bec --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseWheelZoom.java @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.mouse; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.util.Enumeration; + +import org.jogamp.java3d.Transform3D; +import org.jogamp.java3d.TransformGroup; +import org.jogamp.java3d.WakeupCriterion; +import org.jogamp.java3d.WakeupOnAWTEvent; +import org.jogamp.java3d.WakeupOnBehaviorPost; +import org.jogamp.vecmath.Vector3d; + + +/** + * MouseWheelZoom is a Java3D behavior object that lets users control the + * Z axis translation of an object via mouse wheel. + * @since Java 3D 1.3.2 + */ + +public class MouseWheelZoom extends MouseBehavior { + + double z_factor = .1; + Vector3d translation = new Vector3d(); + + private MouseBehaviorCallback callback = null; + + /** + * Creates a zoom behavior given the transform group. + * @param transformGroup The transformGroup to operate on. + */ + public MouseWheelZoom(TransformGroup transformGroup) { + super(transformGroup); + } + + /** + * Creates a default mouse zoom behavior. + **/ + public MouseWheelZoom() { + super(0); + } + + /** + * Creates a zoom behavior. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and + * the transform group must add this behavior. + * @param flags + */ + public MouseWheelZoom(int flags) { + super(flags); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param c The Component to add the MouseListener + * and MouseMotionListener to. + * @since Java 3D 1.3.2 + */ + public MouseWheelZoom(Component c) { + super(c, 0); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behaviors is added to + * the specified Component and works on the given TransformGroup. + * @param c The Component to add the MouseListener and + * MouseMotionListener to. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param transformGroup The TransformGroup to operate on. + * @since Java 3D 1.3.2 + */ + public MouseWheelZoom(Component c, TransformGroup transformGroup) { + super(c, transformGroup); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and the transform + * group must add this behavior. + * @param flags interesting flags (wakeup conditions). + * @since Java 3D 1.3.2 + */ + public MouseWheelZoom(Component c, int flags) { + super(c, flags); + } + + @Override + public void initialize() { + super.initialize(); + if ((flags & INVERT_INPUT) == INVERT_INPUT) { + z_factor *= -1; + invert = true; + } + } + + /** + * Return the y-axis movement multipler. + **/ + public double getFactor() { + return z_factor; + } + + /** + * Set the wheel units movement multipler with factor. + **/ + public void setFactor( double factor) { + z_factor = factor; + } + + + @Override + public void processStimulus(Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] events; + MouseEvent evt; + + while (criteria.hasMoreElements()) { + wakeup = (WakeupCriterion) criteria.nextElement(); + if (wakeup instanceof WakeupOnAWTEvent) { + events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); + if (events.length > 0) { + evt = (MouseEvent) events[events.length-1]; + doProcess(evt); + } + } + + else if (wakeup instanceof WakeupOnBehaviorPost) { + while (true) { + synchronized (mouseq) { + if (mouseq.isEmpty()) break; + evt = (MouseEvent)mouseq.remove(0); + // consolidate MOUSE_WHEEL events + while((evt.getID() == MouseEvent.MOUSE_WHEEL) && + !mouseq.isEmpty() && + (((MouseEvent)mouseq.get(0)).getID() == + MouseEvent.MOUSE_WHEEL)) { + evt = (MouseEvent)mouseq.remove(0); + } + } + doProcess(evt); + } + } + + } + wakeupOn(mouseCriterion); + } + + void doProcess(MouseEvent evt) { + int units = 0; + + processMouseEvent(evt); + + if ((evt.getID() == MouseEvent.MOUSE_WHEEL)) { + MouseWheelEvent wheelEvent = (MouseWheelEvent)evt; + if (wheelEvent.getScrollType() == wheelEvent.WHEEL_UNIT_SCROLL ) { + units = wheelEvent.getUnitsToScroll(); + } + + if (!reset) { + transformGroup.getTransform(currXform); + + translation.z = units*z_factor; + + transformX.set(translation); + + if (invert) { + currXform.mul(currXform, transformX); + } else { + currXform.mul(transformX, currXform); + } + + transformGroup.setTransform(currXform); + + transformChanged( currXform ); + + if (callback!=null) + callback.transformChanged( MouseBehaviorCallback.ZOOM, + currXform ); + + } + else { + reset = false; + } + } + } + + + /** + * Users can overload this method which is called every time + * the Behavior updates the transform + * + * Default implementation does nothing + */ + public void transformChanged( Transform3D transform ) { + } + + /** + * The transformChanged method in the callback class will + * be called every time the transform is updated + */ + public void setupCallback( MouseBehaviorCallback callback ){ + this.callback = callback; + } +} + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseZoom.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseZoom.java new file mode 100644 index 0000000..0e724e3 --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/MouseZoom.java @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.mouse; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.event.MouseEvent; +import java.util.Enumeration; + +import org.jogamp.java3d.Transform3D; +import org.jogamp.java3d.TransformGroup; +import org.jogamp.java3d.WakeupCriterion; +import org.jogamp.java3d.WakeupOnAWTEvent; +import org.jogamp.java3d.WakeupOnBehaviorPost; +import org.jogamp.vecmath.Vector3d; + + +/** + * MouseZoom is a Java3D behavior object that lets users control the + * Z axis translation of an object via a mouse drag motion with the second + * mouse button. See MouseRotate for similar usage info. + */ + +public class MouseZoom extends MouseBehavior { + + double z_factor = .04; + Vector3d translation = new Vector3d(); + + private MouseBehaviorCallback callback = null; + + /** + * Creates a zoom behavior given the transform group. + * @param transformGroup The transformGroup to operate on. + */ + public MouseZoom(TransformGroup transformGroup) { + super(transformGroup); + } + + /** + * Creates a default mouse zoom behavior. + **/ + public MouseZoom(){ + super(0); + } + + /** + * Creates a zoom behavior. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and + * the transform group must add this behavior. + * @param flags + */ + public MouseZoom(int flags) { + super(flags); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param c The Component to add the MouseListener + * and MouseMotionListener to. + * @since Java 3D 1.2.1 + */ + public MouseZoom(Component c) { + super(c, 0); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behaviors is added to + * the specified Component and works on the given TransformGroup. + * @param c The Component to add the MouseListener and + * MouseMotionListener to. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * @param transformGroup The TransformGroup to operate on. + * @since Java 3D 1.2.1 + */ + public MouseZoom(Component c, TransformGroup transformGroup) { + super(c, transformGroup); + } + + /** + * Creates a zoom behavior that uses AWT listeners and behavior + * posts rather than WakeupOnAWTEvent. The behavior is added to the + * specified Component. A null component can be passed to specify + * the behavior should use listeners. Components can then be added + * to the behavior with the addListener(Component c) method. + * Note that this behavior still needs a transform + * group to work on (use setTransformGroup(tg)) and the transform + * group must add this behavior. + * @param flags interesting flags (wakeup conditions). + * @since Java 3D 1.2.1 + */ + public MouseZoom(Component c, int flags) { + super(c, flags); + } + + @Override + public void initialize() { + super.initialize(); + if ((flags & INVERT_INPUT) == INVERT_INPUT) { + z_factor *= -1; + invert = true; + } + } + + /** + * Return the y-axis movement multipler. + **/ + public double getFactor() { + return z_factor; + } + + /** + * Set the y-axis movement multipler with factor. + **/ + public void setFactor( double factor) { + z_factor = factor; + } + + + @Override + public void processStimulus (Enumeration criteria) { + WakeupCriterion wakeup; + AWTEvent[] events; + MouseEvent evt; +// int id; +// int dx, dy; + + while (criteria.hasMoreElements()) { + wakeup = (WakeupCriterion) criteria.nextElement(); + if (wakeup instanceof WakeupOnAWTEvent) { + events = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); + if (events.length > 0) { + evt = (MouseEvent) events[events.length-1]; + doProcess(evt); + } + } + + else if (wakeup instanceof WakeupOnBehaviorPost) { + while (true) { + synchronized (mouseq) { + if (mouseq.isEmpty()) break; + evt = (MouseEvent)mouseq.remove(0); + // consolodate MOUSE_DRAG events + while((evt.getID() == MouseEvent.MOUSE_DRAGGED) && + !mouseq.isEmpty() && + (((MouseEvent)mouseq.get(0)).getID() == + MouseEvent.MOUSE_DRAGGED)) { + evt = (MouseEvent)mouseq.remove(0); + } + } + doProcess(evt); + } + } + + } + wakeupOn (mouseCriterion); + } + + void doProcess(MouseEvent evt) { + int id; + int dx, dy; + + processMouseEvent(evt); + + if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || + ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))){ + id = evt.getID(); + if ((id == MouseEvent.MOUSE_DRAGGED) && + evt.isAltDown() && !evt.isMetaDown()){ + + x = evt.getX(); + y = evt.getY(); + + dx = x - x_last; + dy = y - y_last; + + if (!reset){ + transformGroup.getTransform(currXform); + + translation.z = dy*z_factor; + + transformX.set(translation); + + if (invert) { + currXform.mul(currXform, transformX); + } else { + currXform.mul(transformX, currXform); + } + + transformGroup.setTransform(currXform); + + transformChanged( currXform ); + + if (callback!=null) + callback.transformChanged( MouseBehaviorCallback.ZOOM, + currXform ); + + } + else { + reset = false; + } + + x_last = x; + y_last = y; + } + else if (id == MouseEvent.MOUSE_PRESSED) { + x_last = evt.getX(); + y_last = evt.getY(); + } + } + } + + + /** + * Users can overload this method which is called every time + * the Behavior updates the transform + * + * Default implementation does nothing + */ + public void transformChanged( Transform3D transform ) { + } + + /** + * The transformChanged method in the callback class will + * be called every time the transform is updated + */ + public void setupCallback( MouseBehaviorCallback callback ) { + this.callback = callback; + } +} + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/package.html b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/package.html new file mode 100644 index 0000000..6eb2142 --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/mouse/package.html @@ -0,0 +1,11 @@ + + + + ++ * + * MouseRotate behavior = new MouseRotate(); + * behavior.setTransformGroup(objTrans); + * objTrans.addChild(behavior); + * behavior.setSchedulingBounds(bounds); + * + *
Provides mouse navigation utility classes.
+ + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/Intersect.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/Intersect.java new file mode 100644 index 0000000..45002ab --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/Intersect.java @@ -0,0 +1,1297 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.picking; + +import org.jogamp.java3d.PickPoint; +import org.jogamp.java3d.PickRay; +import org.jogamp.java3d.PickSegment; +import org.jogamp.vecmath.Point3d; +import org.jogamp.vecmath.Point3f; +import org.jogamp.vecmath.Tuple3d; +import org.jogamp.vecmath.Vector3d; + +import org.jogamp.java3d.internal.J3dUtilsI18N; + +/* + * Contains static methods to aid in the intersection test between + * various PickShape classes and geometry primitives (such as quad, + * triangle, line and point). + */ + + +/** + * @deprecated As of Java 3D version 1.2, this class is no + * longer needed + */ + +public class Intersect +{ + + /** + * Determines if thePickRay
and quadrilateral
+ * objects intersect.
+ * The quadrilateral is defined as coordinates[index]
to
+ * coordinates[index+3]
.
+ *
+ * @param ray The ray to use in the intersection test.
+ * @param coordinates An array holding the quadrilateral data.
+ * @param index An array index that designates the starting position
+ * in the array of the quadrilateral to test.
+ * @param dist On return dist[0] will be set to the distance between ray's
+ * origin and the point of intersection, if it exists.
+ * The dist array should be allocated by the user.
+ * @return true
if the ray intersects the quad,
+ * false
if the ray does not intersect the object.
+ */
+ public static boolean rayAndQuad( PickRay ray, Point3d coordinates[],
+ int index, double dist[] ) {
+
+ if((coordinates.length - index) < 4)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect0"));
+
+ Point3d pnts[] = new Point3d[4];
+
+ for(int i=0; i<4; i++)
+ pnts[i] = coordinates[index+i];
+
+ return rayAndPoly(pnts, ray, dist);
+
+ }
+
+ /**
+ * Return true if triangle intersects with ray and the distance, from
+ * the origin of ray to the intersection point, is stored in dist[0].
+ * The triangle is defined by coordinates[index] to coordinates[index+2]
+ * coordinates[index+2]
.
+ *
+ * @param ray The ray to use in the intersection test.
+ * @param coordinates An array holding the triangle data.
+ * @param index An array index that designates the starting position
+ * in the array of the triangle to test.
+ * @param dist On return dist[0] will be set to the distance between ray's origin and the
+ * point of intersection, if it exists. The dist array should be
+ * allocated by the user.
+ * @return true
if the ray intersects the triangle,
+ * false
if the ray does not intersect the object.
+ */
+ public static boolean rayAndTriangle( PickRay ray, Point3d coordinates[],
+ int index, double dist[] ) {
+
+ if((coordinates.length - index) < 3)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect1"));
+
+ Point3d pnts[] = new Point3d[3];
+
+ for(int i=0; i<3; i++)
+ pnts[i] = coordinates[index+i];
+
+ return rayAndPoly(pnts, ray, dist);
+
+ }
+
+ /**
+ * Return true if triangle intersects with ray and the distance, from
+ * the origin of ray to the intersection point, is stored in dist[0].
+ * The triangle is defined by coordinates[index] to coordinates[index+2]
+ *
+ * @param ray The ray that is used in intersection test.
+ * @param coordinates an array of vertices.
+ * @param index the vertex index
+ * @param dist On return dist[0] will be set to the distance between ray's origin and the point intersection, if
+ * exist.
+ * @return true if ray intersects triangle, else return false.
+ */
+
+ public static boolean rayAndTriangle( PickRay ray, Point3f coordinates[],
+ int index, double dist[] ) {
+
+ if((coordinates.length - index) < 3)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect1"));
+
+ Point3d pnts[] = new Point3d[3];
+
+ for(int i=0; i<3; i++)
+ pnts[i] = new Point3d(coordinates[index+i]);
+
+ return rayAndPoly(pnts, ray, dist);
+
+ }
+
+
+ /**
+ * Caluates the intersection between a PickSegment
+ * object and a quadrilateral.
+ * The quad is defined as coordinates[index] to coordinates[index+3]
+ *
+ * @param segment The segment to use in the intersection test.
+ * @param coordinates An array holding the quadrilateral data.
+ * @param index An array index that designates the starting position
+ * in the array of the quadrilateral to test.
+ * @param dist On return dist[0] will be set to the distance between the start of the segment
+ * and the point of intersection, if it exists. The dist array
+ * should be allocated by the user.
+ * @return true
if the segment intersects the quad,
+ * false
if the segment does not intersect the object.
+ */
+ public static boolean segmentAndQuad( PickSegment segment,
+ Point3d coordinates[],
+ int index, double dist[] ) {
+ if((coordinates.length - index) < 4)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect3"));
+
+ Point3d pnts[] = new Point3d[4];
+
+ for(int i=0; i<4; i++)
+ pnts[i] = coordinates[index+i];
+
+ return segmentAndPoly(pnts, segment, dist);
+
+ }
+
+ /**
+ * Return true if quad intersects with segment and the distance, from
+ * the start of segment to the intersection point, is stored in dist[0].
+ * The quad is defined by coordinates[index] to coordinates[index+3]
+ *
+ * @param segment The segment that is used in intersection test.
+ * @param coordinates an array of vertices.
+ * @param index the vertex index
+ * @param dist On return dist[0] will be set to the distance between segment's start and the point
+ * intersection, if exist.
+ * @return true if segment intersects quad, else return false.
+ */
+
+ public static boolean segmentAndQuad( PickSegment segment, Point3f coordinates[],
+ int index, double dist[] ) {
+ if((coordinates.length - index) < 4)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect3"));
+
+ Point3d pnts[] = new Point3d[4];
+
+ for(int i=0; i<4; i++)
+ pnts[i] = new Point3d(coordinates[index+i]);
+
+ return segmentAndPoly(pnts, segment, dist);
+
+ }
+
+ /**
+ * Caluates the intersection between a PickSegment
+ * object and a triangle.
+ * The triangle is defined as coordinates[index] to coordinates[index+2]
+ *
+ * @param segment The segment to use in the intersection test.
+ * @param coordinates An array holding the triangle data.
+ * @param index An array index that designates the starting position
+ * in the array of the triangle to test.
+ * @param dist On return dist[0] contains the distance between the start of the segment
+ * and the point of intersection, if it exists. The dist array
+ * should be allocated by the user.
+ * @return true
if the segment intersects the triangle,
+ * false
if the segment does not intersect the object.
+ */
+ public static boolean segmentAndTriangle( PickSegment segment,
+ Point3d coordinates[],
+ int index,
+ double dist[] ) {
+ if((coordinates.length - index) < 3)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect5"));
+
+ Point3d pnts[] = new Point3d[3];
+
+ for(int i=0; i<3; i++)
+ pnts[i] = coordinates[index+i];
+
+ return segmentAndPoly(pnts, segment, dist);
+
+ }
+
+ /**
+ * Return true if triangle intersects with segment and the distance, from
+ * the start of segment to the intersection point, is stored in dist[0].
+ * The triangle is defined by coordinates[index] to coordinates[index+2]
+ *
+ * @param segment The segment that is used in intersection test.
+ * @param coordinates an array of vertices.
+ * @param index the vertex index
+ * @param dist On return dist[0] will be set to the distance between segment's start and the point
+ * intersection, if exist.
+ * @return true if segment intersects triangle, else return false.
+ */
+
+ public static boolean segmentAndTriangle( PickSegment segment,
+ Point3f coordinates[], int index,
+ double dist[] ) {
+ if((coordinates.length - index) < 3)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect6"));
+
+ Point3d pnts[] = new Point3d[3];
+
+ for(int i=0; i<3; i++)
+ pnts[i] = new Point3d(coordinates[index+i]);
+
+ return segmentAndPoly(pnts, segment, dist);
+
+ }
+
+ /**
+ * Caluates the intersection between a PickPoint
+ * object and a quadrilateral.
+ * The quad is defined as coordinates[index]
to
+ * coordinates[index+3]
.
+ *
+ * @param point The point to use in the intersection test.
+ * @param coordinates An array holding the quadrilateral data.
+ * @param index An array index that designates the starting position
+ * in the array of the quadrilateral to test.
+ * @return true
if the point intersects the quad,
+ * false
if the point does not intersect the object.
+ */
+ private static boolean pointAndQuad( PickPoint point,
+ Point3d coordinates[],
+ int index) {
+
+ if((coordinates.length - index) < 4)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect7"));
+
+ Point3d pnts[] = new Point3d[4];
+
+ for(int i=0; i<4; i++)
+ pnts[i] = coordinates[index+i];
+
+ return pointAndPoly( pnts, point);
+
+ }
+
+ /**
+ * Return true if quad intersects with point.
+ * The triangle is defined by coordinates[index] to coordinates[index+3]
+ *
+ * @param point The point that is used in intersection test.
+ * @param coordinates an array of vertices.
+ * @param index the vertex index
+ * @return true if point intersects quad, else return false.
+ */
+
+ private static boolean pointAndQuad( PickPoint point, Point3f coordinates[],
+ int index) {
+
+ if((coordinates.length - index) < 4)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect7"));
+
+ Point3d pnts[] = new Point3d[4];
+
+ for(int i=0; i<4; i++)
+ pnts[i] = new Point3d(coordinates[index+i]);
+
+ return pointAndPoly( pnts, point);
+
+ }
+
+ /**
+ * Caluates the intersection between a PickPoint
+ * object and a triangle.
+ * The triangle is defined by coordinates[index]
to
+ * coordinates[index+2]
.
+ *
+ * @param point The point to use in the intersection test.
+ * @param coordinates An array holding the triangle data.
+ * @param index An array index that designates the starting position
+ * in the array of the triangle to test.
+ * @return true
if the point intersects the triangle,
+ * false
if the point does not intersect the object.
+ */
+ private static boolean pointAndTriangle( PickPoint point,
+ Point3d coordinates[],
+ int index) {
+
+ if((coordinates.length - index) < 3)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect9"));
+
+ Point3d pnts[] = new Point3d[3];
+
+ for(int i=0; i<3; i++)
+ pnts[i] = coordinates[index+i];
+
+ return pointAndPoly( pnts, point);
+
+ }
+
+ /**
+ * Return true if triangle intersects with point.
+ * The triangle is defined by coordinates[index] to coordinates[index+2]
+ *
+ * @param point The point that is used in intersection test.
+ * @param coordinates an array of vertices.
+ * @param index the vertex index
+ * @return true if point intersects triangle, else return false.
+ */
+
+ private static boolean pointAndTriangle( PickPoint point, Point3f coordinates[],
+ int index) {
+
+ if((coordinates.length - index) < 3)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect10"));
+
+ Point3d pnts[] = new Point3d[3];
+
+ for(int i=0; i<3; i++)
+ pnts[i] = new Point3d(coordinates[index+i]);
+
+ return pointAndPoly( pnts, point);
+
+ }
+
+ /**
+ * Determines if the PickRay
and Point3d
+ * objects intersect.
+ *
+ * @param ray The ray that is used in the intersection test.
+ * @param pnt The point that is used in intersection test.
+ * @param dist On return dist[0] will be set to the distance between ray's origin and the point
+ * of intersection, if it exists. The dist array
+ * should be allocated by the user.
+ * @return true
if the ray intersects the point,
+ * false
if the ray does not intersect the object.
+ */
+ public static boolean rayAndPoint( PickRay ray, Point3d pnt,
+ double dist[] ) {
+
+ Point3d origin = new Point3d();
+ Vector3d direction = new Vector3d();
+
+ ray.get(origin, direction);
+
+ return rayAndPoint(pnt, origin, direction, dist);
+ }
+
+ /**
+ * Return true if point intersects with ray and the distance, from
+ * the origin of ray to the intersection point, is stored in dist[0].
+ *
+ * @param ray The ray that is used in intersection test.
+ * @param pnt The point that is used in intersection test.
+ * @param dist On return dist[0] contains the distance between ray's origin and the point
+ * intersection, if exist.
+ * @return true if ray intersects point, else return false.
+ */
+
+ public static boolean rayAndPoint( PickRay ray, Point3f pnt, double dist[] ) {
+
+ Point3d origin = new Point3d();
+ Vector3d direction = new Vector3d();
+
+ ray.get(origin, direction);
+
+ return rayAndPoint(new Point3d(pnt), origin, direction, dist);
+ }
+
+ /**
+ * Determines if the PickSegment
and Point3d
+ * objects intersect.
+ *
+ * @param segment The segment that is used in the intersection test.
+ * @param pnt The point that is used in intersection test.
+ * @param dist On return dist[0] contains the distance between segment's origin and the point
+ * of intersection, if it exists. The dist array
+ * should be allocated by the user.
+ * @return true
if the segment intersects the point,
+ * false
if the segment does not intersect the object.
+ */
+ public static boolean segmentAndPoint( PickSegment segment, Point3d pnt,
+ double dist[] ) {
+
+ Point3d start = new Point3d();
+ Point3d end = new Point3d();
+ Vector3d direction = new Vector3d();
+
+ segment.get(start, end);
+ direction.x = end.x - start.x;
+ direction.y = end.y - start.y;
+ direction.z = end.z - start.z;
+
+ if((rayAndPoint(pnt, start, direction, dist)==true) && (dist[0] <= 1.0))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Return true if point intersects with segment and the distance, from
+ * the start of segment to the intersection point, is stored in dist[0].
+ *
+ * @param segment The segment that is used in intersection test.
+ * @param pnt The point that is used in intersection test.
+ * @param dist On return dist[0] contains the distance between segment's start and the point
+ * intersection, if exist.
+ * @return true if segment intersects point, else return false.
+ */
+
+ public static boolean segmentAndPoint( PickSegment segment, Point3f pnt,
+ double dist[] ) {
+
+ Point3d start = new Point3d();
+ Point3d end = new Point3d();
+ Vector3d direction = new Vector3d();
+
+ segment.get(start, end);
+ direction.x = end.x - start.x;
+ direction.y = end.y - start.y;
+ direction.z = end.z - start.z;
+
+ if((rayAndPoint(new Point3d(pnt), start, direction, dist)==true)
+ && (dist[0] <= 1.0))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Determines if the PickPoint
and Point3d
+ * objects intersect.
+ *
+ * @param point The PickPoint that is used in the intersection test.
+ * @param pnt The Point3d that is used in intersection test.
+ * @return true
if the PickPoint and Point3d objects
+ * intersect, false
if the do not intersect.
+ */
+ public static boolean pointAndPoint( PickPoint point, Point3d pnt) {
+
+ Point3d location = new Point3d();
+
+ point.get(location);
+
+ if ((location.x == pnt.x) && (location.y == pnt.y) &&
+ (location.z == pnt.z))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Return true if pnt intersects with point.
+ *
+ * @param point The point that is used in intersection test.
+ * @param pnt The point that is used in intersection test.
+ * @return true if point intersects pnt, else return false.
+ */
+
+ public static boolean pointAndPoint( PickPoint point, Point3f pnt) {
+
+ Point3d location = new Point3d();
+
+ point.get(location);
+
+ if(((float) location.x == pnt.x) && ((float) location.y == pnt.y)
+ && ((float) location.z == pnt.z))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Determines if the PickRay
and Line
+ * objects intersect.
+ * The line is defined as coordinates[index]
to
+ * coordinates[index+1]
.
+ *
+ * @param ray The ray that is used in the intersection test.
+ * @param coordinates An array holding the line data.
+ * @param dist On return dist[0] contains the distance between ray's origin and the point of
+ * intersection, if it exists. The dist array
+ * should be allocated by the user.
+ * @return true
if the ray intersects the line,
+ * false
if the ray does not intersect the object.
+ */
+ public static boolean rayAndLine(PickRay ray, Point3d coordinates[],
+ int index,
+ double dist[] ) {
+ Point3d origin = new Point3d();
+ Vector3d direction = new Vector3d();
+
+ if((coordinates.length - index) < 2)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect11"));
+
+ ray.get(origin, direction);
+ Point3d start = coordinates[index++];
+ Point3d end = coordinates[index];
+
+ return lineAndRay( start, end, origin, direction, dist );
+
+ }
+
+ /**
+ * Return true if line intersects with ray and the distance, from
+ * the origin of ray to the intersection point, is stored in dist[0].
+ * The line is defined by coordinates[index] to coordinates[index+1]
+ *
+ * @param ray The ray that is used in intersection test.
+ * @param coordinates an array of vertices.
+ * @param index the vertex index
+ * @param dist On return dist[0] contains the distance between ray's origin and the point intersection, if
+ * exist.
+ * @return true if ray intersects line, else return false.
+ */
+
+ public static boolean rayAndLine(PickRay ray, Point3f coordinates[], int index,
+ double dist[] ) {
+ Point3d origin = new Point3d();
+ Vector3d direction = new Vector3d();
+
+ if((coordinates.length - index) < 2)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect11"));
+
+ ray.get(origin, direction);
+ Point3d start = new Point3d(coordinates[index++]);
+ Point3d end = new Point3d(coordinates[index]);
+
+ return lineAndRay( start, end, origin, direction, dist );
+
+ }
+
+ /**
+ * Determines if the PickSegment
and Line
+ * objects intersect.
+ * The line is defined as coordinates[index]
to
+ * coordinates[index+1]
.
+ *
+ * @param segment The segment that is used in the intersection test.
+ * @param coordinates An array holding the line data.
+ * @param dist On return dist[0] contains the distance between segment's origin and the point of
+ * intersection, if it exists. The dist array
+ * should be allocated by the user.
+ * @return true
if the segment intersects the line,
+ * false
if the segment does not intersect the object.
+ */
+ public static boolean segmentAndLine(PickSegment segment,
+ Point3d coordinates[],
+ int index, double dist[] ) {
+
+ Point3d start = new Point3d();
+ Point3d end = new Point3d();
+ Vector3d direction = new Vector3d();
+
+ if((coordinates.length - index) < 2)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect13"));
+
+ segment.get(start, end);
+ direction.x = end.x - start.x;
+ direction.y = end.y - start.y;
+ direction.z = end.z - start.z;
+
+ Point3d startpnt = coordinates[index++];
+ Point3d endpnt = coordinates[index];
+
+ if(lineAndRay(startpnt, endpnt, start, direction, dist)==true)
+ if(dist[0] <= 1.0)
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Return true if line intersects with segment and the distance, from
+ * the start of segment to the intersection point, is stored in dist[0].
+ * The line is defined by coordinates[index] to coordinates[index+1]
+ *
+ * @param segment The segment that is used in intersection test.
+ * @param coordinates an array of vertices.
+ * @param index the vertex index
+ * @param dist On return dist[0] contains the distance between segment's start and the point
+ * intersection, if exist.
+ * @return true if segment intersects line, else return false.
+ */
+
+ public static boolean segmentAndLine(PickSegment segment, Point3f coordinates[],
+ int index, double dist[] ) {
+
+ Point3d start = new Point3d();
+ Point3d end = new Point3d();
+ Vector3d direction = new Vector3d();
+
+ if((coordinates.length - index) < 2)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect13"));
+
+ segment.get(start, end);
+ direction.x = end.x - start.x;
+ direction.y = end.y - start.y;
+ direction.z = end.z - start.z;
+
+ Point3d startpnt = new Point3d(coordinates[index++]);
+ Point3d endpnt = new Point3d(coordinates[index]);
+
+ if(lineAndRay(startpnt, endpnt, start, direction, dist)==true)
+ if(dist[0] <= 1.0)
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Determines if the PickPoint
and Line
+ * objects intersect.
+ * The line is defined as coordinates[index]
to
+ * coordinates[index+1]
.
+ *
+ * @param point The point that is used in the intersection test.
+ * @param coordinates An array holding the line data.
+ * @return true
if the the point intersects the line,
+ * false
if the the point does not intersect the object.
+ */
+ public static boolean pointAndLine(PickPoint point, Point3d coordinates[],
+ int index ) {
+
+ if((coordinates.length - index) < 2)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect13"));
+
+ double dist[] = new double[1];
+ Point3d start = coordinates[index++];
+ Point3d end = coordinates[index];
+ Point3d location = new Point3d();
+ Vector3d direction = new Vector3d();
+
+ point.get(location);
+ direction.x = end.x - start.x;
+ direction.y = end.y - start.y;
+ direction.z = end.z - start.z;
+
+ if ((rayAndPoint(location, start, direction, dist)==true) &&
+ (dist[0] <= 1.0))
+ return true;
+
+ return false;
+
+ }
+
+ /**
+ * Return true if line intersects with point.
+ * The line is defined by coordinates[index] to coordinates[index+1]
+ *
+ * @param point The point that is used in intersection test.
+ * @param coordinates an array of vertices.
+ * @param index the vertex index
+ * @return true if point intersects line, else return false.
+ */
+
+ public static boolean pointAndLine(PickPoint point, Point3f coordinates[],
+ int index ) {
+
+ if((coordinates.length - index) < 2)
+ throw new RuntimeException(J3dUtilsI18N.getString("Intersect13"));
+
+ double dist[] = new double[1];
+ Point3d start = new Point3d(coordinates[index++]);
+ Point3d end = new Point3d(coordinates[index]);
+ Point3d location = new Point3d();
+ Vector3d direction = new Vector3d();
+
+ point.get(location);
+ direction.x = end.x - start.x;
+ direction.y = end.y - start.y;
+ direction.z = end.z - start.z;
+
+ if((rayAndPoint(location, start, direction, dist)==true) && (dist[0] <= 1.0))
+ return true;
+
+ return false;
+
+ }
+
+ /**
+ * Return true if point is on the inside of halfspace test. The
+ * halfspace is
+ * partition by the plane of triangle or quad.
+ * */
+
+ private static boolean pointAndPoly( Point3d coordinates[], PickPoint point) {
+
+ Vector3d vec0 = new Vector3d(); // Edge vector from point 0 to point 1;
+ Vector3d vec1 = new Vector3d(); // Edge vector from point 0 to point 2 or 3;
+ Vector3d pNrm = new Vector3d();
+ double absNrmX, absNrmY, absNrmZ, pD = 0.0;
+ Vector3d tempV3d = new Vector3d();
+ double pNrmDotrDir = 0.0;
+
+ double tempD;
+
+ int i, j;
+
+ // Compute plane normal.
+ for(i=0; iorg.jogamp.java3d.utils.picking.PickCanvas
+ *
+ * @see org.jogamp.java3d.utils.picking.PickCanvas
+ */
+
+public class PickObject extends Object {
+
+ // Have to rethink what to support. Is this complete.
+
+ /**
+ * A flag to indicate to the pickNode method to return a
+ * Shape3D
node from
+ * a given SceneGraphPath
.
+ *
+ * @see PickObject#pickNode
+ */
+ public static final int SHAPE3D = 0x1;
+
+ /**
+ * A flag to indicate to the pickNode method to return a
+ * Morph
node from
+ * a given SceneGraphPath
.
+ *
+ * @see PickObject#pickNode
+ */
+ public static final int MORPH = 0x2;
+
+ /**
+ * A flag to indicate to the pickNode method to return a
+ * Primitive
node
+ * from a given SceneGraphPath
.
+ *
+ * @see PickObject#pickNode
+ */
+ public static final int PRIMITIVE = 0x4;
+
+ /**
+ * A flag to indicate to the pickNode method to return a
+ * Link
node from
+ * a given SceneGraphPath
.
+ *
+ * @see PickObject#pickNode
+ */
+ public static final int LINK = 0x8;
+
+ /**
+ * A flag to indicate to the pickNode method to return a
+ * Group
node from
+ * a given SceneGraphPath
.
+ *
+ * @see PickObject#pickNode
+ */
+ public static final int GROUP = 0x10;
+
+ /**
+ * A flag to indicate to the pickNode method to return a
+ * TransformGroup
+ * node from a given SceneGraphPath
.
+ *
+ * @see PickObject#pickNode
+ */
+ public static final int TRANSFORM_GROUP = 0x20;
+
+ /**
+ * A flag to indicate to the pickNode method to return a
+ * BranchGroup
+ * node from a given SceneGraphPath
.
+ *
+ * @see PickObject#pickNode
+ */
+ public static final int BRANCH_GROUP = 0x40;
+
+ /**
+ * A flag to indicate to the pickNode method to return a
+ * Switch
node from
+ * a given SceneGraphPath
.
+ *
+ * @see PickObject#pickNode
+ */
+ public static final int SWITCH = 0x80;
+
+
+ /**
+ * Set this flag if you want to pick by geometry.
+ */
+ public static final int USE_GEOMETRY = 0x100;
+
+
+ /**
+ * Set this flag if you want to pick by bounds.
+ */
+ public static final int USE_BOUNDS = 0x200;
+
+ BranchGroup pickRoot;
+ Canvas3D canvas;
+ Point3d origin = new Point3d();
+ Vector3d direction = new Vector3d();
+ PickRay pickRay = new PickRay();
+ SceneGraphPath sceneGraphPath = null;
+ SceneGraphPath sceneGraphPathArr[] = null;
+ int pickBy; // To pick by Bounds or Geometry.
+
+ static final boolean debug = false;
+
+ /**
+ * Creates a PickObject.
+ * @param c Current J3D canvas.
+ * @param root The portion of the scenegraph for which picking is to occur
+ * on. It has to be a BranchGroup
.
+ *
+ * @see BranchGroup
+ * @see Canvas3D
+ */
+ public PickObject(Canvas3D c, BranchGroup root)
+ {
+ pickRoot = root;
+ canvas = c;
+ }
+
+ /**
+ * Creates a PickRay that starts at the viewer position and points into
+ * the scene in the direction of (xpos, ypos) specified in window space.
+ *
+ * @param xpos The value along the x-axis.
+ * @param ypos The value along the y-axis.
+ * @return A PickShape object that is the constructed PickRay.
+ */
+ public PickShape generatePickRay(int xpos, int ypos)
+ {
+
+ Transform3D motion=new Transform3D();
+ Point3d eyePosn = new Point3d();
+ Point3d mousePosn = new Point3d();
+ Vector3d mouseVec=new Vector3d();
+
+ canvas.getCenterEyeInImagePlate(eyePosn);
+ canvas.getPixelLocationInImagePlate(xpos,ypos,mousePosn);
+ if (canvas.getView().getProjectionPolicy() ==
+ View.PARALLEL_PROJECTION) {
+ // Correct for the parallel projection: keep the eye's z
+ // coordinate, but make x,y be the same as the mouse, this
+ // simulates the eye being at "infinity"
+ eyePosn.x = mousePosn.x;
+ eyePosn.y = mousePosn.y;
+ }
+
+ canvas.getImagePlateToVworld(motion);
+
+ if (debug) {
+ System.out.println("mouse position " + xpos + " " + ypos);
+ System.out.println("before, mouse " + mousePosn + " eye " + eyePosn);
+ }
+
+ motion.transform(eyePosn);
+ motion.transform(mousePosn);
+ mouseVec.sub(mousePosn, eyePosn);
+ mouseVec.normalize();
+
+ if (debug) {
+ System.out.println(motion + "\n");
+ System.out.println("after, mouse " + mousePosn + " eye " + eyePosn +
+ " mouseVec " + mouseVec);
+ }
+
+ pickRay.set(eyePosn, mouseVec);
+
+ return (PickShape) pickRay;
+
+ }
+
+ /**
+ * Returns an array referencing all the items that are pickable below the
+ * BranchGroup
(specified in the PickObject constructor) that
+ * intersect with a ray that starts at the
+ * viewer position and points into the scene in the direction of (xpos, ypos)
+ * specified in window space. The resultant array is unordered.
+ *
+ * @param xpos The value along the x-axis.
+ * @param ypos The value along the y-axis.
+ * @return The array of SceneGraphPath objects that contain Objects that
+ * were picked
+ * If no pickable object is found null
is returned..
+ *
+ * @see SceneGraphPath
+ */
+ public SceneGraphPath[] pickAll(int xpos, int ypos)
+ {
+ pickRay = (PickRay) generatePickRay(xpos, ypos);
+ sceneGraphPathArr = pickRoot.pickAll(pickRay);
+ return sceneGraphPathArr;
+ }
+
+ /**
+ * Returns a sorted array of references to all the Pickable items below the
+ * BranchGroup
(specified in the PickObject constructor) that
+ * intersect with the ray that starts at the viewer
+ * position and points into the scene in the direction of (xpos, ypos)
+ * in the window space.
+ * Element [0] references the item closest to viewer.
+ *
+ * @param xpos The value along the x-axis.
+ * @param ypos The value along the y-axis.
+ * @return A sorted arrayof SceneGraphPath objects that contain Objects that
+ * were picked. The array is sorted from closest to farthest from the
+ * viewer
+ * If no pickable object is found null
is returned..
+ *
+ * @see SceneGraphPath
+ */
+ public SceneGraphPath[] pickAllSorted(int xpos, int ypos)
+ {
+ pickRay = (PickRay) generatePickRay(xpos, ypos);
+ sceneGraphPathArr = pickRoot.pickAllSorted(pickRay);
+ return sceneGraphPathArr;
+ }
+
+ /**
+ * Returns a reference to any item that is Pickable below the specified
+ * BranchGroup
(specified in the PickObject constructor) which
+ * intersects with the ray that starts at the viewer
+ * position and points into the scene in the direction of (xpos, ypos) in
+ * window space.
+ *
+ * @param xpos The value along the x-axis.
+ * @param ypos The value along the y-axis.
+ * @return A SceneGraphPath of an object that was picked. This is not
+ * guarenteed to return the same result for multiple picks
+ * If no pickable object is found null
is returned..
+ *
+ * @see SceneGraphPath
+ */
+ public SceneGraphPath pickAny(int xpos, int ypos)
+ {
+ pickRay = (PickRay) generatePickRay(xpos, ypos);
+ sceneGraphPath = pickRoot.pickAny(pickRay);
+ return sceneGraphPath;
+ }
+
+ /**
+ * Returns a reference to the item that is closest to the viewer and is
+ * Pickable below the BranchGroup
(specified in the PickObject
+ * constructor) which intersects with the ray that starts at
+ * the viewer position and points into the scene in the direction of
+ * (xpos, ypos) in the window space.
+ *
+ * @param xpos The value along the x-axis.
+ * @param ypos The value along the y-axis.
+ * @return A SceneGraphPath which contains the closest pickable object.
+ * If no pickable object is found, null
is returned.
+ *
+ * @see SceneGraphPath
+ */
+ public SceneGraphPath pickClosest(int xpos, int ypos)
+ {
+ pickRay = (PickRay) generatePickRay(xpos, ypos);
+ sceneGraphPath = pickRoot.pickClosest(pickRay);
+ return sceneGraphPath;
+ }
+
+
+ /**
+ * Returns an array referencing all the items that are pickable below the
+ * BranchGroup
(specified in the PickObject constructor) that
+ * intersect with a ray that starts at the
+ * viewer position and points into the scene in the direction of (xpos, ypos)
+ * specified in window space. The resultant array is unordered.
+ *
+ * @param xpos The value along the x-axis.
+ * @param ypos The value along the y-axis.
+ * @param flag Specifys picking by Geometry or Bounds.
+ * @return The array of SceneGraphPath objects that contain Objects that
+ * were picked
+ * If no pickable object is found null
is returned..
+ *
+ * @see SceneGraphPath
+ */
+ public SceneGraphPath[] pickAll(int xpos, int ypos, int flag)
+ {
+
+ if(flag == USE_BOUNDS) {
+ return pickAll(xpos, ypos);
+ }
+ else if(flag == USE_GEOMETRY) {
+ return pickGeomAll(xpos, ypos);
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Returns a sorted array of references to all the Pickable items below the
+ * BranchGroup
(specified in the PickObject constructor) that
+ * intersect with the ray that starts at the viewer
+ * position and points into the scene in the direction of (xpos, ypos)
+ * in the window space.
+ * Element [0] references the item closest to viewer.
+ *
+ * @param xpos The value along the x-axis.
+ * @param ypos The value along the y-axis.
+ * @param flag Specifys picking by Geometry or Bounds.
+ * @return A sorted arrayof SceneGraphPath objects that contain Objects that
+ * were picked. The array is sorted from closest to farthest from the
+ * viewer
+ * If no pickable object is found null
is returned..
+ *
+ * @see SceneGraphPath
+ */
+ public SceneGraphPath[] pickAllSorted(int xpos, int ypos, int flag)
+ {
+
+ if(flag == USE_BOUNDS) {
+ return pickAllSorted(xpos, ypos);
+ }
+ else if(flag == USE_GEOMETRY) {
+ return pickGeomAllSorted(xpos, ypos);
+ }
+ else
+ return null;
+
+ }
+
+ /**
+ * Returns a reference to any item that is Pickable below the specified
+ * BranchGroup
(specified in the PickObject constructor) which
+ * intersects with the ray that starts at the viewer
+ * position and points into the scene in the direction of (xpos, ypos) in
+ * window space.
+ *
+ * @param xpos The value along the x-axis.
+ * @param ypos The value along the y-axis.
+ * @param flag Specifys picking by Geometry or Bounds.
+ * @return A SceneGraphPath of an object that was picked. This is not
+ * guarenteed to return the same result for multiple picks
+ * If no pickable object is found null
is returned..
+ *
+ * @see SceneGraphPath
+ */
+ public SceneGraphPath pickAny(int xpos, int ypos, int flag)
+ {
+
+ if(flag == USE_BOUNDS) {
+ return pickAny(xpos, ypos);
+ }
+ else if(flag == USE_GEOMETRY) {
+ return pickGeomAny(xpos, ypos);
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Returns a reference to the item that is closest to the viewer and is
+ * Pickable below the BranchGroup
(specified in the PickObject
+ * constructor) which intersects with the ray that starts at
+ * the viewer position and points into the scene in the direction of
+ * (xpos, ypos) in the window space.
+ *
+ * @param xpos The value along the x-axis.
+ * @param ypos The value along the y-axis.
+ * @param flag Specifys picking by Geometry or Bounds.
+ * @return A SceneGraphPath which contains the closest pickable object.
+ * If no pickable object is found, null
is returned.
+ *
+ * @see SceneGraphPath
+ */
+ public SceneGraphPath pickClosest(int xpos, int ypos, int flag)
+ {
+
+ if(flag == USE_BOUNDS) {
+ return pickClosest(xpos, ypos);
+ }
+ else if(flag == USE_GEOMETRY) {
+ return pickGeomClosest(xpos, ypos);
+ }
+ else
+ return null;
+ }
+
+ private SceneGraphPath[] pickGeomAll(int xpos, int ypos)
+ {
+ Node obj;
+ int i, cnt=0;
+
+ pickRay = (PickRay) generatePickRay(xpos, ypos);
+ sceneGraphPathArr = pickRoot.pickAll(pickRay);
+
+ if(sceneGraphPathArr == null)
+ return null;
+
+ boolean found[] = new boolean[sceneGraphPathArr.length];
+
+ for(i=0; ioccurrence
+ * of a Node that is of the specified type.
+ *
+ * @param sgPath the SceneGraphPath to be traversed.
+ * @param flags the Node types interested.
+ * @param occurrence the occurrence of a Node that
+ * matches the specified type to return. An occurrence
of
+ * 1 means to return the first occurrence of that object type (the object
+ * closest to the Locale).
+ * @return the nth occurrence
of a Node
+ * of type flags
, starting from the Locale. If no pickable object is
+ * found, null
is returned.
+ */
+ public Node pickNode(SceneGraphPath sgPath, int flags, int occurrence)
+ {
+ int curCnt=0;
+
+ if (sgPath != null) {
+ Node pickedNode = sgPath.getObject();
+
+ // Shape3D and Morph are leaf nodes and have no children. It doesn't
+ // make sense to do occurrence check here. We'll just return it for now.
+ if ((pickedNode instanceof Shape3D) && ((flags & SHAPE3D) != 0)){
+ if (debug) System.out.println("Shape3D found");
+ return pickedNode;
+ } else if ((pickedNode instanceof Morph) && ((flags & MORPH) != 0)){
+ if (debug) System.out.println("Morph found");
+ return pickedNode;
+ }
+ else {
+ for (int j = 0; j < sgPath.nodeCount(); j++){
+ pickedNode = sgPath.getNode(j);
+ if (debug) System.out.println("looking at node " + pickedNode);
+
+ if ((pickedNode instanceof Group) && ((flags & GROUP) != 0)){
+ if (debug) System.out.println("Group found");
+ curCnt++;
+ if(curCnt == occurrence)
+ return pickedNode;
+ }
+ else if ((pickedNode instanceof BranchGroup) &&
+ ((flags & BRANCH_GROUP) != 0)){
+ if (debug) System.out.println("Branch group found");
+ curCnt++;
+ if(curCnt == occurrence)
+ return pickedNode;
+ }
+ else if ((pickedNode instanceof TransformGroup) &&
+ ((flags & TRANSFORM_GROUP) != 0)){
+ if (debug) System.out.println("xform group found");
+ curCnt++;
+ if(curCnt == occurrence)
+ return pickedNode;
+ }
+ else if ((pickedNode instanceof Primitive) &&
+ ((flags & PRIMITIVE) != 0)){
+ if (debug) System.out.println("Primitive found");
+ curCnt++;
+ if(curCnt == occurrence)
+ return pickedNode;
+ }
+ else if ((pickedNode instanceof Link) && ((flags & LINK) != 0)){
+ if (debug) System.out.println("Link found");
+ curCnt++;
+ if(curCnt == occurrence)
+ return pickedNode;
+ }
+ }
+
+ if (pickedNode == null)
+ if (debug) System.out.println("ERROR: null SceneGraphPath");
+ }
+
+ }
+
+ return null;
+
+ }
+
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickRotateBehavior.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickRotateBehavior.java
new file mode 100644
index 0000000..d962658
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickRotateBehavior.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.picking;
+
+import org.jogamp.java3d.Bounds;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehaviorCallback;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseRotate;
+
+/*
+ * A mouse behavior that allows user to pick and drag scene graph objects.
+ * Common usage:
+ * + * 1. Create your scene graph. + *
+ * 2. Create this behavior with root and canvas. + *
+ *
+ *+ * PickRotateBehavior behavior = new PickRotateBehavior(canvas, root, bounds); + * root.addChild(behavior); + *
+ * The above behavior will monitor for any picking events on
+ * the scene graph (below root node) and handle mouse drags on pick hits.
+ * Note the root node can also be a subgraph node of the scene graph (rather
+ * than the topmost).
+ */
+
+/**
+ * @deprecated As of Java 3D version 1.2, replaced by
+ * org.jogamp.java3d.utils.picking.behaviors.PickRotateBehavior
+ *
+ * @see org.jogamp.java3d.utils.picking.behaviors.PickRotateBehavior
+ */
+
+public class PickRotateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
+ MouseRotate drag;
+ int pickMode = PickObject.USE_BOUNDS;
+ private PickingCallback callback=null;
+ private TransformGroup currentTG;
+
+ /**
+ * Creates a pick/rotate behavior that waits for user mouse events for
+ * the scene graph. This method has its pickMode set to BOUNDS picking.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ **/
+
+ public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
+ super(canvas, root, bounds);
+ drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
+ drag.setTransformGroup(currGrp);
+ currGrp.addChild(drag);
+ drag.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ }
+
+ /**
+ * Creates a pick/rotate behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ * @param pickMode specifys PickObject.USE_BOUNDS or PickObject.USE_GEOMETRY.
+ * Note: If pickMode is set to PickObject.USE_GEOMETRY, all geometry object in
+ * the scene graph that allows pickable must have its ALLOW_INTERSECT bit set.
+ **/
+
+ public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
+ int pickMode){
+ super(canvas, root, bounds);
+ drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
+ drag.setTransformGroup(currGrp);
+ currGrp.addChild(drag);
+ drag.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ this.pickMode = pickMode;
+ }
+
+ /**
+ * Sets the pickMode component of this PickRotateBehavior to the value of
+ * the passed pickMode.
+ * @param pickMode the pickMode to be copied.
+ **/
+
+
+ public void setPickMode(int pickMode) {
+ this.pickMode = pickMode;
+ }
+
+ /**
+ * Return the pickMode component of this PickRotateBehavior.
+ **/
+
+ public int getPickMode() {
+ return pickMode;
+ }
+
+ /**
+ * Update the scene to manipulate any nodes. This is not meant to be
+ * called by users. Behavior automatically calls this. You can call
+ * this only if you know what you are doing.
+ *
+ * @param xpos Current mouse X pos.
+ * @param ypos Current mouse Y pos.
+ **/
+ @Override
+ public void updateScene(int xpos, int ypos){
+ TransformGroup tg = null;
+
+ if (!mevent.isMetaDown() && !mevent.isAltDown()){
+
+ // tg = (TransformGroup) pickScene.pickNode(pickScene.pickClosest(xpos, ypos),
+ // PickObject.TRANSFORM_GROUP);
+
+ tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos, ypos,pickMode),
+ PickObject.TRANSFORM_GROUP);
+ // Make sure the selection exists and is movable.
+ if ((tg != null) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
+ drag.setTransformGroup(tg);
+ drag.wakeup();
+ currentTG = tg;
+ } else if (callback!=null)
+ callback.transformChanged( PickingCallback.NO_PICK, null );
+ }
+ }
+
+ /**
+ * Callback method from MouseRotate
+ * This is used when the Picking callback is enabled
+ */
+ @Override
+ public void transformChanged( int type, Transform3D transform ) {
+ callback.transformChanged( PickingCallback.ROTATE, currentTG );
+ }
+
+ /**
+ * Register the class @param callback to be called each
+ * time the picked object moves
+ */
+ public void setupCallback( PickingCallback callback ) {
+ this.callback = callback;
+ if (callback==null)
+ drag.setupCallback( null );
+ else
+ drag.setupCallback( this );
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickTranslateBehavior.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickTranslateBehavior.java
new file mode 100644
index 0000000..0dac749
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickTranslateBehavior.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.picking;
+
+import org.jogamp.java3d.Bounds;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehavior;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehaviorCallback;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseTranslate;
+
+// A mouse behavior that allows user to pick and translate scene graph objects.
+// Common usage: 1. Create your scene graph. 2. Create this behavior with
+// the root and canvas. See PickRotateBehavior for more details.
+
+/**
+ * @deprecated As of Java 3D version 1.2, replaced by
+ * org.jogamp.java3d.utils.picking.behaviors.PickTranslateBehavior
+ *
+ * @see org.jogamp.java3d.utils.picking.behaviors.PickTranslateBehavior
+ */
+
+public class PickTranslateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
+ MouseTranslate translate;
+ int pickMode = PickObject.USE_BOUNDS;
+ private PickingCallback callback = null;
+ private TransformGroup currentTG;
+
+ /**
+ * Creates a pick/translate behavior that waits for user mouse events for
+ * the scene graph. This method has its pickMode set to BOUNDS picking.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ **/
+
+ public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
+ super(canvas, root, bounds);
+ translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
+ translate.setTransformGroup(currGrp);
+ currGrp.addChild(translate);
+ translate.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ }
+
+ /**
+ * Creates a pick/translate behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ * @param pickMode specifys PickObject.USE_BOUNDS or PickObject.USE_GEOMETRY.
+ * Note: If pickMode is set to PickObject.USE_GEOMETRY, all geometry object in
+ * the scene graph that allows pickable must have its ALLOW_INTERSECT bit set.
+ **/
+
+ public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
+ int pickMode){
+ super(canvas, root, bounds);
+ translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
+ translate.setTransformGroup(currGrp);
+ currGrp.addChild(translate);
+ translate.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ this.pickMode = pickMode;
+ }
+
+ /**
+ * Sets the pickMode component of this PickTranslateBehavior to the value of
+ * the passed pickMode.
+ * @param pickMode the pickMode to be copied.
+ **/
+
+ public void setPickMode(int pickMode) {
+ this.pickMode = pickMode;
+ }
+
+ /**
+ * Return the pickMode component of this PickTranslaeBehavior.
+ **/
+
+ public int getPickMode() {
+ return pickMode;
+ }
+
+ /**
+ * Update the scene to manipulate any nodes. This is not meant to be
+ * called by users. Behavior automatically calls this. You can call
+ * this only if you know what you are doing.
+ *
+ * @param xpos Current mouse X pos.
+ * @param ypos Current mouse Y pos.
+ **/
+ @Override
+ public void updateScene(int xpos, int ypos){
+ TransformGroup tg = null;
+
+ if (!mevent.isAltDown() && mevent.isMetaDown()){
+
+ tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos, ypos, pickMode),
+ PickObject.TRANSFORM_GROUP);
+ //Check for valid selection.
+ if ((tg != null) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
+
+ translate.setTransformGroup(tg);
+ translate.wakeup();
+ currentTG = tg;
+ } else if (callback!=null)
+ callback.transformChanged( PickingCallback.NO_PICK, null );
+ }
+
+ }
+
+ /**
+ * Callback method from MouseTranslate
+ * This is used when the Picking callback is enabled
+ */
+ @Override
+ public void transformChanged( int type, Transform3D transform ) {
+ callback.transformChanged( PickingCallback.TRANSLATE, currentTG );
+ }
+
+ /**
+ * Register the class @param callback to be called each
+ * time the picked object moves
+ */
+ public void setupCallback( PickingCallback callback ) {
+ this.callback = callback;
+ if (callback==null)
+ translate.setupCallback( null );
+ else
+ translate.setupCallback( this );
+ }
+
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickZoomBehavior.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickZoomBehavior.java
new file mode 100644
index 0000000..2d78309
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickZoomBehavior.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.picking;
+
+import org.jogamp.java3d.Bounds;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehavior;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehaviorCallback;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseZoom;
+
+
+// A mouse behavior that allows user to pick and zoom scene graph objects.
+// Common usage: 1. Create your scene graph. 2. Create this behavior with
+// the root and canvas. See PickRotateBehavior for more details.
+
+/**
+ * @deprecated As of Java 3D version 1.2, replaced by
+ * org.jogamp.java3d.utils.picking.behaviors.PickZoomBehavior
+ *
+ * @see org.jogamp.java3d.utils.picking.behaviors.PickZoomBehavior
+ */
+
+public class PickZoomBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
+ MouseZoom zoom;
+ int pickMode = PickObject.USE_BOUNDS;
+ private PickingCallback callback = null;
+ private TransformGroup currentTG;
+
+ /**
+ * Creates a pick/zoom behavior that waits for user mouse events for
+ * the scene graph. This method has its pickMode set to BOUNDS picking.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ **/
+
+ public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
+ super(canvas, root, bounds);
+ zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
+ zoom.setTransformGroup(currGrp);
+ currGrp.addChild(zoom);
+ zoom.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ }
+
+ /**
+ * Creates a pick/zoom behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ * @param pickMode specifys PickObject.USE_BOUNDS or PickObject.USE_GEOMETRY.
+ * Note: If pickMode is set to PickObject.USE_GEOMETRY, all geometry object in
+ * the scene graph that allows pickable must have its ALLOW_INTERSECT bit set.
+ **/
+
+ public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
+ int pickMode){
+ super(canvas, root, bounds);
+ zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
+ zoom.setTransformGroup(currGrp);
+ currGrp.addChild(zoom);
+ zoom.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ this.pickMode = pickMode;
+ }
+
+ /**
+ * Sets the pickMode component of this PickZoomBehavior to the value of
+ * the passed pickMode.
+ * @param pickMode the pickMode to be copied.
+ **/
+
+ public void setPickMode(int pickMode) {
+ this.pickMode = pickMode;
+ }
+
+
+ /**
+ * Return the pickMode component of this PickZoomBehavior.
+ **/
+
+ public int getPickMode() {
+ return pickMode;
+ }
+
+
+ /**
+ * Update the scene to manipulate any nodes. This is not meant to be
+ * called by users. Behavior automatically calls this. You can call
+ * this only if you know what you are doing.
+ *
+ * @param xpos Current mouse X pos.
+ * @param ypos Current mouse Y pos.
+ **/
+
+ @Override
+ public void updateScene(int xpos, int ypos){
+ TransformGroup tg = null;
+
+ if (mevent.isAltDown() && !mevent.isMetaDown()){
+
+ tg =(TransformGroup)pickScene.pickNode(pickScene.pickClosest(xpos, ypos, pickMode),
+ PickObject.TRANSFORM_GROUP);
+
+ // Check for valid selection
+ if ((tg != null) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
+ zoom.setTransformGroup(tg);
+ zoom.wakeup();
+ currentTG = tg;
+ } else if (callback!=null)
+ callback.transformChanged( PickingCallback.NO_PICK, null );
+ }
+ }
+
+ /**
+ * Callback method from MouseZoom
+ * This is used when the Picking callback is enabled
+ */
+ @Override
+ public void transformChanged( int type, Transform3D transform ) {
+ callback.transformChanged( PickingCallback.ZOOM, currentTG );
+ }
+
+ /**
+ * Register the class @param callback to be called each
+ * time the picked object moves
+ */
+ public void setupCallback( PickingCallback callback ) {
+ this.callback = callback;
+ if (callback==null)
+ zoom.setupCallback( null );
+ else
+ zoom.setupCallback( this );
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickingCallback.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickingCallback.java
new file mode 100644
index 0000000..cc9f636
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/PickingCallback.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.picking;
+
+import org.jogamp.java3d.TransformGroup;
+
+/**
+ * @deprecated As of Java 3D version 1.2, replaced by
+ * org.jogamp.java3d.utils.picking.behaviors.PickingCallback
+ *
+ * @see org.jogamp.java3d.utils.picking.behaviors.PickingCallback
+ */
+
+public interface PickingCallback {
+
+ public final static int ROTATE=0;
+ public final static int TRANSLATE=1;
+ public final static int ZOOM=2;
+
+ /**
+ * The user made a selection but nothing was
+ * actually picked
+ */
+ public final static int NO_PICK=3;
+
+ /**
+ * Called by the Pick Behavior with which this callback
+ * is registered each time the Picked object is moved
+ */
+ public void transformChanged( int type, TransformGroup tg );
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/package.html b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/package.html
new file mode 100644
index 0000000..66a7fd0
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/picking/package.html
@@ -0,0 +1,13 @@
+
+
+
Deprecated: Use org.jogamp.java3d.utils.pickfast.behaviors
+instead.
+ * The default echo is a solid 6-pointed star where each point is aligned
+ * with the axes of the local coordinate system of the sensor, and with
+ * the center of the star at the location of the sensor hotspot.
+ *
+ * @param sensor a 6 degree of freedom Sensor which generates position
+ * and orientation relative to the tracker base.
+ * @param size the physical width of the echo in centimeters.
+ * @param enableLighting a boolean indicating whether the echo geometry
+ * should have lighting enabled.
+ */
+ public Mouse6DPointerBehavior(Sensor sensor, double size,
+ boolean enableLighting) {
+
+ this.sensor = sensor ;
+ echoTransformGroup = new TransformGroup() ;
+ echoTransformGroup.setCapability
+ (TransformGroup.ALLOW_TRANSFORM_WRITE) ;
+
+ Point3d hotspot = new Point3d() ;
+ sensor.getHotspot(hotspot) ;
+
+ Transform3D t3d = new Transform3D() ;
+ Vector3f v3f = new Vector3f(hotspot) ;
+ t3d.set(v3f) ;
+
+ Shape3D echo =
+ new SensorGnomonEcho(t3d, 0.001*size, 0.005*size, enableLighting) ;
+ echoTransformGroup.addChild(echo) ;
+
+ eventAgent = new SensorEventAgent(this) ;
+ eventAgent.addSensorReadListener(sensor, new EchoReadListener()) ;
+ }
+
+ /**
+ * Constructs the behavior with an echo parented by the specified
+ * TransformGroup.
+ *
+ * @param sensor a 6 degree of freedom Sensor which generates position
+ * and orientation relative to the tracker base.
+ * @param tg a TransformGroup with a child defining the visible echo
+ * which will track the Sensor position and orientation; the Transform3D
+ * associated with the TransformGroup will be updated in order to effect
+ * the behavior, so it must have the ALLOW_TRANSFORM_WRITE capability
+ * set before the scene graph is set live
+ */
+ public Mouse6DPointerBehavior(Sensor sensor, TransformGroup tg) {
+ this.sensor = sensor ;
+ echoTransformGroup = tg ;
+ eventAgent = new SensorEventAgent(this) ;
+ eventAgent.addSensorReadListener(sensor, new EchoReadListener()) ;
+ }
+
+ /**
+ * Gets the sensor used by this behavior.
+ *
+ * @return the sensor used by this behavior
+ */
+ public Sensor getSensor() {
+ return sensor ;
+ }
+
+ /**
+ * Gets the echo used by this behavior.
+ *
+ * @return the TransformGroup parenting this behavior's echo geometry
+ */
+ public TransformGroup getEcho() {
+ return echoTransformGroup ;
+ }
+
+ /**
+ * Gets the SensorEventAgent used by this behavior. This can be used to
+ * add customized event bindings to this behavior.
+ *
+ * @return the SensorEventAgent
+ */
+ public SensorEventAgent getSensorEventAgent() {
+ return eventAgent ;
+ }
+
+ /**
+ * Initializes the behavior.
+ * NOTE: Applications should not call this method. It is called by the
+ * Java 3D behavior scheduler.
+ */
+ @Override
+ public void initialize() {
+ wakeupOn(conditions) ;
+ }
+
+ /**
+ * Processes a stimulus meant for this behavior.
+ * NOTE: Applications should not call this method. It is called by the
+ * Java 3D behavior scheduler.
+ */
+ @Override
+ public void processStimulus(Enumeration criteria) {
+ eventAgent.dispatchEvents() ;
+ wakeupOn(conditions) ;
+ }
+
+ /**
+ * This member class updates the echo transform in response to sensor
+ * reads.
+ */
+ public class EchoReadListener implements SensorReadListener {
+ private Transform3D t3d = new Transform3D() ;
+
+ @Override
+ public void read(SensorEvent e) {
+ // Get the Transform3D that transforms points from local sensor
+ // coordinates to virtual world coordinates, based on the primary
+ // view associated with this Behavior. This view is defined to be
+ // the first View attached to a live ViewPlatform.
+ //
+ // Note that this will display frame lag if another behavior such
+ // as OrbitBehavior is used to manipulate the view transform while
+ // the echo is visible. In order to eliminate frame lag the
+ // behavior driving the view transform must also compute the echo
+ // transform as well. See the WandViewBehavior utility for the
+ // appropriate techniques.
+ getView().getSensorToVworld(e.getSensor(), t3d) ;
+ echoTransformGroup.setTransform(t3d) ;
+ }
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorBeamEcho.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorBeamEcho.java
new file mode 100644
index 0000000..39b8d35
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorBeamEcho.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.sensor ;
+
+import org.jogamp.java3d.Appearance;
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.Material;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransparencyAttributes;
+import org.jogamp.java3d.TriangleStripArray;
+import org.jogamp.vecmath.AxisAngle4f;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * A Shape3D representing a beam pointing from the origin of a
+ * sensor's local coordinate system to its hotspot.
+ *
+ * @since Java 3D 1.3
+ */
+public class SensorBeamEcho extends Shape3D {
+ /**
+ * Creates a SensorBeamEcho. Read and write capabilities are granted
+ * for the Appearance, Material, TransparencyAttributes, and
+ * TransparencyAttributes mode and value.
+ *
+ * @param hotspot location of the sensor's hotspot in the sensor's
+ * local coordinate system; this must not be (0, 0, 0)
+ * @param baseWidth width of the beam in meters
+ * @param enableLighting boolean indicating whether normals should be
+ * generated and lighting enabled
+ * @exception IllegalArgumentException if hotspot is (0, 0, 0)
+ */
+ public SensorBeamEcho(Point3d hotspot, double baseWidth,
+ boolean enableLighting) {
+ super() ;
+
+ if (hotspot.distance(new Point3d()) == 0.0)
+ throw new IllegalArgumentException
+ ("\nBeam echo can't have hotspot at origin") ;
+
+ Vector3f axis = new Vector3f((float)hotspot.x,
+ (float)hotspot.y,
+ (float)hotspot.z) ;
+
+ Vector3f axis1 = new Vector3f() ;
+ axis1.normalize(axis) ;
+
+ // Choose an arbitrary vector normal to the beam axis.
+ Vector3f normal = new Vector3f(0.0f, 1.0f, 0.0f) ;
+ normal.cross(axis1, normal) ;
+ if (normal.lengthSquared() < 0.5f) {
+ normal.set(0.0f, 0.0f, 1.0f) ;
+ normal.cross(axis1, normal) ;
+ }
+ normal.normalize() ;
+
+ // Create cap vertices and normals.
+ int divisions = 18 ;
+ Point3f[] cap0 = new Point3f[divisions] ;
+ Point3f[] cap1 = new Point3f[divisions] ;
+ Vector3f[] capNormals = new Vector3f[divisions] ;
+ Vector3f cap0Normal = new Vector3f(axis1) ;
+ Vector3f cap1Normal = new Vector3f(axis1) ;
+ cap0Normal.negate() ;
+
+ AxisAngle4f aa4f = new AxisAngle4f
+ (axis1, -(float)Math.PI/((float)divisions/2.0f)) ;
+ Transform3D t3d = new Transform3D() ;
+ t3d.set(aa4f) ;
+
+ float halfWidth = (float)baseWidth / 2.0f ;
+ for (int i = 0 ; i < divisions ; i++) {
+ capNormals[i] = new Vector3f(normal) ;
+ cap0[i] = new Point3f(normal) ;
+ cap0[i].scale(halfWidth) ;
+ cap1[i] = new Point3f(cap0[i]) ;
+ cap1[i].add(axis) ;
+ t3d.transform(normal) ;
+ }
+
+ // The beam cylinder is created with 3 triangle strips. The first
+ // strip contains the side facets (2 + 2*divisions vertices), and
+ // the other two strips are the caps (divisions vertices each).
+ int vertexCount = 2 + (4 * divisions) ;
+ Point3f[] vertices = new Point3f[vertexCount] ;
+ Vector3f[] normals = new Vector3f[vertexCount] ;
+
+ // Side facets.
+ for (int i = 0 ; i < divisions ; i++) {
+ vertices[i*2] = cap0[i] ;
+ vertices[(i*2) + 1] = cap1[i] ;
+
+ normals[i*2] = capNormals[i] ;
+ normals[(i*2) + 1] = capNormals[i] ;
+ }
+
+ vertices[divisions*2] = cap0[0] ;
+ vertices[(divisions*2) + 1] = cap1[0] ;
+
+ normals[divisions*2] = capNormals[0] ;
+ normals[(divisions*2) + 1] = capNormals[0] ;
+
+ // Strips for caps created by criss-crossing the interior.
+ int v = (divisions+1) * 2 ;
+ vertices[v] = cap0[0] ;
+ normals[v++] = cap0Normal ;
+
+ int j = 1 ;
+ int k = divisions - 1 ;
+ while (j <= k) {
+ vertices[v] = cap0[j++] ;
+ normals[v++] = cap0Normal ;
+ if (j > k) break ;
+ vertices[v] = cap0[k--] ;
+ normals[v++] = cap0Normal ;
+ }
+
+ vertices[v] = cap1[0] ;
+ normals[v++] = cap1Normal ;
+
+ j = 1 ;
+ k = divisions - 1 ;
+ while (j <= k) {
+ vertices[v] = cap1[k--] ;
+ normals[v++] = cap1Normal ;
+ if (j > k) break ;
+ vertices[v] = cap1[j++] ;
+ normals[v++] = cap1Normal ;
+ }
+
+ // Create the TriangleStripArray.
+ int vertexFormat ;
+ Material m = new Material() ;
+ m.setCapability(Material.ALLOW_COMPONENT_READ) ;
+ m.setCapability(Material.ALLOW_COMPONENT_WRITE) ;
+
+ if (enableLighting) {
+ vertexFormat =
+ GeometryArray.COORDINATES | GeometryArray.NORMALS ;
+ m.setLightingEnable(true) ;
+ }
+ else {
+ vertexFormat = GeometryArray.COORDINATES ;
+ m.setLightingEnable(false) ;
+ }
+
+ int[] stripCounts = new int[3] ;
+ stripCounts[0] = 2 + (2 * divisions) ;
+ stripCounts[1] = divisions ;
+ stripCounts[2] = divisions ;
+
+ TriangleStripArray tsa =
+ new TriangleStripArray(vertexCount,
+ vertexFormat, stripCounts) ;
+
+ tsa.setCoordinates(0, vertices) ;
+ if (enableLighting)
+ tsa.setNormals(0, normals) ;
+
+ Appearance a = new Appearance() ;
+ a.setMaterial(m) ;
+ a.setCapability(Appearance.ALLOW_MATERIAL_READ) ;
+ a.setCapability(Appearance.ALLOW_MATERIAL_WRITE) ;
+
+ TransparencyAttributes ta = new TransparencyAttributes() ;
+ ta.setCapability(TransparencyAttributes.ALLOW_MODE_READ) ;
+ ta.setCapability(TransparencyAttributes.ALLOW_MODE_WRITE) ;
+ ta.setCapability(TransparencyAttributes.ALLOW_VALUE_READ) ;
+ ta.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE) ;
+ ta.setCapability
+ (TransparencyAttributes.ALLOW_BLEND_FUNCTION_READ) ;
+ ta.setCapability
+ (TransparencyAttributes.ALLOW_BLEND_FUNCTION_WRITE) ;
+
+ a.setTransparencyAttributes(ta) ;
+ a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_READ) ;
+ a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE) ;
+
+ setGeometry(tsa) ;
+ setAppearance(a) ;
+
+ setCapability(ALLOW_APPEARANCE_READ) ;
+ setCapability(ALLOW_APPEARANCE_WRITE) ;
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorButtonListener.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorButtonListener.java
new file mode 100644
index 0000000..bd3d39b
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorButtonListener.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.sensor ;
+
+/**
+ * This defines the interface for handling a sensor's button events in
+ * conjunction with a SensorEventAgent
instance.
+ *
+ * The events passed to this listener's methods are ephemeral; they
+ * are only valid until the listener has returned. If a listener needs to
+ * retain the event it must be copied using the
+ * SensorEvent(SensorEvent)
constructor.
+ *
+ * @see SensorEvent
+ * @see SensorEventAgent
+ * @see SensorReadListener
+ * @since Java 3D 1.3
+ */
+public interface SensorButtonListener {
+ /**
+ * This method is called when a sensor's button is pressed.
+ *
+ * @param e the sensor event
+ */
+ public void pressed(SensorEvent e) ;
+
+ /**
+ * This method is called when a sensor's button is released.
+ *
+ * @param e the sensor event
+ */
+ public void released(SensorEvent e) ;
+
+ /**
+ * This method is called with each invocation of the
+ * dispatchEvents
method of SensorEventAgent
+ * if any button bound to the listener is down and has not changed
+ * state since the last invocation. The sensor value has not
+ * necessarily changed from the last drag event.
+ *
+ * @param e the sensor event
+ */
+ public void dragged(SensorEvent e) ;
+
+ /**
+ * This method is currently not used by SensorEventAgent
,
+ * but is included here for future possible development. Its
+ * implementations should remain empty for the present.
+ */
+ public void clicked(SensorEvent e) ;
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorEvent.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorEvent.java
new file mode 100644
index 0000000..35cbb2a
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorEvent.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.sensor ;
+
+import org.jogamp.java3d.Sensor;
+import org.jogamp.java3d.Transform3D;
+
+/**
+ * This class defines the event object that is created by a
+ * SensorEventAgent
and passed to registered
+ * SensorReadListener
and SensorButtonListener
+ * implementations.
+ *
+ * The events passed to the listeners are ephemeral; they are only
+ * valid until the listener has returned. This is done to avoid
+ * allocating large numbers of mostly temporary objects, especially for
+ * behaviors that wake up every frame. If a listener needs to retain the
+ * event it must be copied using the SensorEvent(SensorEvent)
+ * constructor.
+ *
+ * @see SensorEventAgent
+ * @see SensorButtonListener
+ * @see SensorReadListener
+ * @since Java 3D 1.3
+ */
+public class SensorEvent {
+ /**
+ * A button pressed event.
+ */
+ public static final int PRESSED = 1 ;
+
+ /**
+ * A button released event.
+ */
+ public static final int RELEASED = 2 ;
+
+ /**
+ * A button dragged event.
+ */
+ public static final int DRAGGED = 3 ;
+
+ /**
+ * A sensor read event.
+ */
+ public static final int READ = 4 ;
+
+ /**
+ * The value that is returned by getButton
when no
+ * buttons have changed state.
+ */
+ public static final int NOBUTTON = -1 ;
+
+ private int id = 0 ;
+ private Object source = null ;
+ private Sensor sensor = null ;
+ private int button = NOBUTTON ;
+ private int[] buttonState = null ;
+ private Transform3D sensorRead = null ;
+ private long time = 0 ;
+ private long lastTime = 0 ;
+ private boolean ephemeral = false ;
+
+ /**
+ * Creates a new SensorEvent
.
+ *
+ * @param source a reference to the originating object which
+ * instantiated the SensorEventAgent
, usually a
+ * Behavior
; may be null
+ * @param id event type
+ * @param sensor a reference to the provoking sensor
+ * @param sensorRead the sensor's read value at the time of the event
+ * @param buttonState the state of the sensor's buttons at the time of
+ * the event, where a 1 in the array indicates that the button at that
+ * index is down, and a 0 indicates that button is up; may be null
+ * @param button index of the button that changed state, from 0 to
+ * (buttonCount - 1)
, or the value NOBUTTON
+ * @param time the time in nanoseconds at which the
+ * dispatchEvents
method of
+ * SensorEventAgent
was called to generate this event,
+ * usually from the processStimulus
method of a Behavior
+ * @param lastTime the time in nanoseconds at which the
+ * dispatchEvents
method of
+ * SensorEventAgent
was last called to generate
+ * events, usually from the processStimulus
method of a
+ * Behavior
; may be used to measure frame time in
+ * behaviors that wake up every frame
+ */
+ public SensorEvent(Object source, int id, Sensor sensor,
+ Transform3D sensorRead, int[] buttonState,
+ int button, long time, long lastTime) {
+
+ this.source = source ;
+ this.id = id ;
+ this.sensor = sensor ;
+ this.button = button ;
+ this.time = time ;
+ this.lastTime = lastTime ;
+ if (sensorRead == null)
+ throw new NullPointerException("sensorRead can't be null") ;
+ this.sensorRead = new Transform3D(sensorRead) ;
+ if (buttonState != null) {
+ this.buttonState = new int[buttonState.length] ;
+ for (int i = 0 ; i < buttonState.length ; i++)
+ this.buttonState[i] = buttonState[i] ;
+ }
+ this.ephemeral = false ;
+ }
+
+ /**
+ * Creates a new ephemeral SensorEvent
. In order
+ * to avoid creating large numbers of sensor event objects, the events
+ * passed to the button and read listeners by the
+ * dispatchEvents
method of SensorEventAgent
+ * are valid only until the listener returns. If the event needs to
+ * be retained then they must be copied with the
+ * SensorEvent(SensorEvent)
constructor.
+ */
+ public SensorEvent() {
+ this.ephemeral = true ;
+ }
+
+ /**
+ * Creates a copy of the given SensorEvent
. Listeners
+ * must use this constructor to copy events that need to be retained.
+ * NOTE: The Sensor
and Object
references
+ * returned by getSensor
and getSource
+ * remain references to the original objects.
+ *
+ * @param e the event to be copied
+ */
+ public SensorEvent(SensorEvent e) {
+ this.source = e.source ;
+ this.id = e.id ;
+ this.sensor = e.sensor ;
+ this.button = e.button ;
+ this.time = e.time ;
+ this.lastTime = e.lastTime ;
+ if (e.sensorRead == null)
+ throw new NullPointerException("sensorRead can't be null") ;
+ this.sensorRead = new Transform3D(e.sensorRead) ;
+ if (e.buttonState != null) {
+ this.buttonState = new int[e.buttonState.length] ;
+ for (int i = 0 ; i < e.buttonState.length ; i++)
+ this.buttonState[i] = e.buttonState[i] ;
+ }
+ this.ephemeral = false ;
+ }
+
+ /**
+ * Sets the fields of an ephemeral event. No objects are copied. An
+ * IllegalStateException
will be thrown if this event
+ * is not ephemeral.
+ *
+ * @param source a reference to the originating object which
+ * instantiated the SensorEventAgent
, usually a
+ * Behavior
; may be null
+ * @param id event type
+ * @param sensor a reference to the provoking sensor
+ * @param sensorRead the sensor's read value at the time of the event
+ * @param buttonState the state of the sensor's buttons at the time of
+ * the event; a 1 in the array indicates that the button at that
+ * index is down, while a 0 indicates that button is up
+ * @param button index of the button that changed state, from 0 to
+ * (buttonCount - 1)
, or the value NOBUTTON
+ * @param time the time in nanoseconds at which the
+ * dispatchEvents
method of
+ * SensorEventAgent
was called to generate this event,
+ * usually from the processStimulus
method of a Behavior
+ * @param lastTime the time in nanoseconds at which the
+ * dispatchEvents
method of
+ * SensorEventAgent
was last called to generate
+ * events, usually from the processStimulus
method of a
+ * Behavior
; may be used to measure frame time in
+ * behaviors that wake up every frame
+ */
+ public void set(Object source, int id, Sensor sensor,
+ Transform3D sensorRead, int[] buttonState,
+ int button, long time, long lastTime) {
+
+ if (!ephemeral)
+ throw new IllegalStateException
+ ("Can't set the fields of non-ephemeral events") ;
+
+ this.source = source ;
+ this.id = id ;
+ this.sensor = sensor ;
+ if (sensorRead == null)
+ throw new NullPointerException("sensorRead can't be null") ;
+ this.sensorRead = sensorRead ;
+ this.buttonState = buttonState ;
+ this.button = button ;
+ this.time = time ;
+ this.lastTime = lastTime ;
+ }
+
+ /**
+ * Gets a reference to the originating object which instantiated the
+ * SensorEventAgent
, usually a Behavior
; may
+ * be null.
+ * @return the originating object
+ */
+ public Object getSource() {
+ return source ;
+ }
+
+ /**
+ * Gets the event type.
+ * @return the event id
+ */
+ public int getID() {
+ return id ;
+ }
+
+
+ /**
+ * Gets a reference to the provoking sensor.
+ * @return the provoking sensor
+ */
+ public Sensor getSensor() {
+ return sensor ;
+ }
+
+ /**
+ * Gets the time in nanoseconds at which the
+ * dispatchEvents
method of SensorEventAgent
+ * was called to generate this event, usually from the
+ * processStimulus
method of a Behavior
.
+ * @return time in nanoseconds
+ */
+ public long getTime() {
+ return time ;
+ }
+
+ /**
+ * Gets the time in nanoseconds at which the
+ * dispatchEvents
method of SensorEventAgent
+ * was last called to generate events, usually from the
+ * processStimulus
method of a Behavior
; may
+ * be used to measure frame time in behaviors that wake up every
+ * frame.
+ * @return last time in nanoseconds
+ */
+ public long getLastTime() {
+ return lastTime ;
+ }
+
+ /**
+ * Copies the sensor's read value at the time of the event into the
+ * given Transform3D
.
+ *
+ * @param t the transform to receive the sensor read
+ */
+ public void getSensorRead(Transform3D t) {
+ t.set(sensorRead) ;
+ }
+
+ /**
+ * Gets the index of the button that changed state when passed to a
+ * pressed
or released
callback. The index
+ * may range from 0 to (sensor.getSensorButtonCount() -
+ * 1)
. The value returned is NOBUTTON
for events
+ * passed to a read
or dragged
callback.
+ * @return the button index
+ */
+ public int getButton() {
+ return button ;
+ }
+
+ /**
+ * Copies the state of the sensor's buttons at the time of the event
+ * into the given array. A 1 in the array indicates that the button
+ * at that index is down, while a 0 indicates that button is up.
+ * @param buttonState the state of the sensor buttons
+ */
+ public void getButtonState(int[] buttonState) {
+ if (buttonState.length != this.buttonState.length)
+ throw new ArrayIndexOutOfBoundsException
+ ("buttonState array is the wrong length") ;
+
+ for (int i = 0 ; i < buttonState.length ; i++)
+ buttonState[i] = this.buttonState[i] ;
+ }
+
+ /**
+ * Returns true if this event is ephemeral and is valid only
+ * until the listener returns. A copy of the event can be created by
+ * passing it to the SensorEvent(SensorEvent)
+ * constructor.
+ */
+ public boolean isEphemeral() {
+ return ephemeral ;
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorEventAgent.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorEventAgent.java
new file mode 100644
index 0000000..6b71f17
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorEventAgent.java
@@ -0,0 +1,715 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.sensor ;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.jogamp.java3d.Sensor;
+import org.jogamp.java3d.Transform3D;
+
+import org.jogamp.java3d.utils.timer.J3DTimer;
+
+/**
+ * This class works in conjunction with the SensorButtonListener
+ * and SensorReadListener
interfaces to support an event-driven
+ * model of sensor interaction. Java 3D defines sensors as delivering
+ * continuous input data which must be polled to retrieve their values, but in
+ * practice it is often convenient to structure application code to respond to
+ * events such as button state transitions.
+ *
+ * Listeners registered with this class are invoked when its
+ * dispatchEvents
method is called. This is usually called from
+ * the processStimulus
method of a Behavior
, but may
+ * also be called directly from the pollAndProcessInput
method of
+ * an event-driven implementation of InputDevice
. In either case
+ * the device is still polled by the Java 3D input device scheduling thread to
+ * get its current values; however, in the former, dispatchEvents
+ * is called from the behavior scheduler thread regardless of whether any new
+ * events are available, while in the latter, the InputDevice
+ * implementation may choose to call dispatchEvents
only if new
+ * events are actually generated.
+ *
+ * Button events are generated by changes in sensor button state, from pressed
+ * to released and vice versa. Button state changes are examined with each
+ * invocation of the dispatchEvents
method. Events are
+ * distributed to interested parties through the button listener interface
+ * using the pressed
and released
callbacks.
+ *
+ * The dragged
method is not necessarily called in response to a
+ * motion event generated by a sensor. dispatchEvents
will call
+ * dragged
whenever any button assigned to the listener is down
+ * and has not changed state since the last time it was called. If
+ * dispatchEvents
is called in the processStimulus
+ * of a Behavior
, then dragged
may be called even if
+ * the sensor value has not changed. This is as a consequence of the core
+ * Java 3D API definition of sensors as continuous devices.
+ *
+ * Like dragged
, the read
method of
+ * SensorReadListener
is not necessarily invoked in response to a
+ * real event. It is called by dispatchEvents
whenever a button
+ * listener has not been called for that sensor. This usually means that no
+ * buttons are down, but clients are free to leave a button listener null, or
+ * to explicitly bind a null button listener to a button so that button's
+ * events are ignored. The sensor value has not necessarily changed since the
+ * last read
callback.
+ *
+ * A mutual exclusion policy can be applied between button
+ * listeners when they are grouped in an array mapped to the sensor's
+ * buttons. If multiple sensor buttons are held down at the same time,
+ * then a listener in the array is invoked only for the button that was
+ * depressed first. The read
callback is separated from the
+ * pressed
, released
, and dragged
+ * callbacks in a separate interface in order to support this policy.
+ *
+ * The events passed to the listeners are ephemeral; they are only
+ * valid until the listener has returned. This is done to avoid
+ * allocating large numbers of mostly temporary objects, especially for
+ * behaviors that wake up every frame. If a listener needs to retain the
+ * event it must be copied using the SensorEvent(SensorEvent)
+ * constructor.
+ *
+ * It is safe to add and remove listeners in response to a callback.
+ *
+ * @see SensorEvent
+ * @see SensorButtonListener
+ * @see SensorReadListener
+ * @since Java 3D 1.3
+ */
+public class SensorEventAgent {
+ private long t0 = 0 ;
+ private Object source = null ;
+ private SensorEvent e = new SensorEvent() ;
+
+ // List of SensorBinding objects and corresponding array.
+ private List bindingsList = new ArrayList() ;
+ private SensorBinding[] bindings = new SensorBinding[0] ;
+
+ // Indicates that lists must be converted to arrays. Need to do this
+ // to allow listeners to add and remove themselves or other listeners
+ // safely during event dispatch.
+ private boolean listsDirty = false ;
+
+ /**
+ * Create a SensorEventAgent
to generate and dispatch
+ * sensor events to registered listeners.
+ *
+ * @param source reference to the originating object for inclusion in
+ * generated SensorEvents
; intended to refer to the
+ * instantiating Behavior but may be any reference, or null
+ */
+ public SensorEventAgent(Object source) {
+ this.source = source ;
+ }
+
+ /**
+ * This class contains all the button and read listeners registered
+ * with a sensor.
+ */
+ private static class SensorBinding {
+ Sensor sensor = null ;
+ int[] buttons = null ;
+ Transform3D read = null ;
+
+ // List of SensorButtonBinding objects and corresponding array.
+ List buttonBindingsList = new ArrayList() ;
+ SensorButtonBinding[] buttonBindings = new SensorButtonBinding[0] ;
+
+ // List of SensorReadListener objects and corresponding array.
+ List readBindingsList = new ArrayList() ;
+ SensorReadListener[] readBindings = new SensorReadListener[0] ;
+
+ SensorBinding(Sensor sensor) {
+ this.sensor = sensor ;
+ buttons = new int[sensor.getSensorButtonCount()] ;
+ read = new Transform3D() ;
+ }
+
+ void updateArrays() {
+ buttonBindings =
+ (SensorButtonBinding[])buttonBindingsList.toArray
+ (new SensorButtonBinding[buttonBindingsList.size()]) ;
+ readBindings =
+ (SensorReadListener[])readBindingsList.toArray
+ (new SensorReadListener[readBindingsList.size()]) ;
+ }
+
+ @Override
+ public String toString() {
+ String s = new String() ;
+ s = "sensor " + sensor + "\nbutton listener arrays:\n" ;
+ for (int i = 0 ; i < buttonBindingsList.size() ; i++)
+ s = s + ((SensorButtonBinding)buttonBindingsList.get(i)) ;
+ s = s + "read listeners:\n" ;
+ for (int i = 0 ; i < readBindingsList.size() ; i++)
+ s = s + " " +
+ ((SensorReadListener)readBindingsList.get(i)) + "\n" ;
+ return s ;
+ }
+ }
+
+ /**
+ * This class contains an array of SensorButtonListener
+ * implementations, one for each sensor button. This array is used to
+ * support a mutual exclusion callback policy. There may be multiple
+ * instances of this class associated with a single sensor.
+ */
+ private static class SensorButtonBinding {
+ int buttonsHandled = 0 ;
+ boolean[] prevButtons = null ;
+ boolean multiButton = false ;
+ SensorButtonListener[] listeners = null ;
+
+ SensorButtonBinding(SensorButtonListener[] listeners,
+ boolean multiButtonEnable) {
+
+ prevButtons = new boolean[listeners.length] ;
+ this.listeners = new SensorButtonListener[listeners.length] ;
+
+ for (int i = 0 ; i < listeners.length ; i++) {
+ prevButtons[i] = false ;
+ this.listeners[i] = listeners[i] ;
+ }
+
+ this.multiButton = multiButtonEnable ;
+ }
+
+ @Override
+ public String toString() {
+ String s = new String() ;
+ s = " length " + listeners.length +
+ ", mutual exclusion " + (!multiButton) + "\n" ;
+ for (int i = 0 ; i < listeners.length ; i++)
+ s = s + " " +
+ (listeners[i] == null?
+ "null" : listeners[i].toString()) + "\n" ;
+ return s ;
+ }
+ }
+
+ /**
+ * Look up the sensor listeners bound to the given sensor.
+ */
+ private SensorBinding getSensorBinding(Sensor sensor) {
+ for (int i = 0 ; i < bindingsList.size() ; i++) {
+ SensorBinding sb = (SensorBinding)bindingsList.get(i) ;
+ if (sb.sensor == sensor)
+ return sb ;
+ }
+ return null ;
+ }
+
+ /**
+ * Creates a binding of the specified sensor button to the given
+ * SensorButtonListener
implementation.
+ *
+ * @param sensor the sensor with the button to be bound
+ * @param button the index of the button to be bound on the specified
+ * sensor; may range from 0 to
+ * (sensor.getSensorButtonCount() - 1)
+ * @param buttonListener the SensorButtonListener
+ * implementation that will be invoked for the sensor's button
+ */
+ public synchronized void addSensorButtonListener
+ (Sensor sensor, int button, SensorButtonListener buttonListener) {
+
+ if (sensor == null)
+ throw new NullPointerException("\nsensor is null") ;
+
+ if (button >= sensor.getSensorButtonCount())
+ throw new ArrayIndexOutOfBoundsException
+ ("\nbutton " + button + " >= sensor button count " +
+ sensor.getSensorButtonCount()) ;
+
+ SensorBinding sb = getSensorBinding(sensor) ;
+ if (sb == null) {
+ sb = new SensorBinding(sensor) ;
+ bindingsList.add(sb) ;
+ }
+
+ SensorButtonListener[] listeners =
+ new SensorButtonListener[sb.buttons.length] ;
+
+ // Assign only the specified button; others remain null.
+ listeners[button] = buttonListener ;
+ SensorButtonBinding sbb =
+ new SensorButtonBinding(listeners, true) ;
+
+ sb.buttonBindingsList.add(sbb) ;
+ listsDirty = true ;
+ }
+
+ /**
+ * Creates a binding from all the buttons on the specified sensor to
+ * the given SensorButtonListener
implementation. If
+ * multiple sensor buttons are held down at the same time, the press
+ * and release callbacks are called for each button in the order that
+ * they occur. This allows actions to be bound to combinations of
+ * button presses, but is also convenient for listeners that don't
+ * care which button was pressed.
+ *
+ * @param sensor the sensor to be bound
+ * @param buttonListener the SensorButtonListener
+ * implementation that will be called for all button events
+ */
+ public synchronized void addSensorButtonListener
+ (Sensor sensor, SensorButtonListener buttonListener) {
+
+ if (sensor == null)
+ throw new NullPointerException("\nsensor is null") ;
+
+ SensorBinding sb = getSensorBinding(sensor) ;
+ if (sb == null) {
+ sb = new SensorBinding(sensor) ;
+ bindingsList.add(sb) ;
+ }
+
+ SensorButtonListener[] listeners =
+ new SensorButtonListener[sb.buttons.length] ;
+
+ // All buttons are bound to the same listener.
+ for (int i = 0 ; i < sb.buttons.length ; i++)
+ listeners[i] = buttonListener ;
+
+ SensorButtonBinding sbb =
+ new SensorButtonBinding(listeners, true) ;
+
+ sb.buttonBindingsList.add(sbb) ;
+ listsDirty = true ;
+ }
+
+ /**
+ * Creates a binding of the specified sensor to the given array of
+ * SensorButtonListener
implementations. The array index
+ * of the listener indicates the index of the sensor button to which
+ * it will be bound.
+ *
+ * This method enforces a mutually exclusive callback policy
+ * among the listeners specified in the array. If multiple sensor
+ * buttons are held down at the same time, callbacks are invoked only
+ * for the button that was depressed first.
+ *
+ * @param sensor the sensor to be bound
+ * @param buttonListeners array of implementations of
+ * SensorButtonListener
; array entries may be null or
+ * duplicates but the array length must equal the sensor's button
+ * count
+ */
+ public synchronized void addSensorButtonListeners
+ (Sensor sensor, SensorButtonListener[] buttonListeners) {
+
+ if (sensor == null)
+ throw new NullPointerException("\nsensor is null") ;
+
+ SensorBinding sb = getSensorBinding(sensor) ;
+ if (sb == null) {
+ sb = new SensorBinding(sensor) ;
+ bindingsList.add(sb) ;
+ }
+
+ if (sb.buttons.length != buttonListeners.length)
+ throw new IllegalArgumentException
+ ("\nbuttonListeners length " + buttonListeners.length +
+ " must equal sensor button count " + sb.buttons.length) ;
+
+ SensorButtonBinding sbb =
+ new SensorButtonBinding(buttonListeners, false) ;
+
+ sb.buttonBindingsList.add(sbb) ;
+ listsDirty = true ;
+ }
+
+ /**
+ * Gets the SensorButtonListener
implementations bound to
+ * the given sensor and button.
+ *
+ * @param sensor the sensor of interest
+ * @param button the button of interest
+ * @return array of SensorButtonListener
implementations
+ * bound to the given sensor and button, or null
+ */
+ public SensorButtonListener[] getSensorButtonListeners(Sensor sensor,
+ int button) {
+ if (sensor == null)
+ throw new NullPointerException("\nsensor is null") ;
+
+ if (button >= sensor.getSensorButtonCount())
+ throw new ArrayIndexOutOfBoundsException
+ ("\nbutton " + button + " >= sensor button count " +
+ sensor.getSensorButtonCount()) ;
+
+ SensorBinding sb = getSensorBinding(sensor) ;
+ if (sb == null)
+ return null ;
+
+ ArrayList listeners = new ArrayList() ;
+ for (int i = 0 ; i < sb.buttonBindingsList.size() ; i++) {
+ SensorButtonBinding sbb =
+ (SensorButtonBinding)sb.buttonBindingsList.get(i) ;
+
+ if (sbb.listeners[button] != null)
+ listeners.add(sbb.listeners[button]) ;
+ }
+
+ if (listeners.size() == 0)
+ return null ;
+ else
+ return (SensorButtonListener[])listeners.toArray
+ (new SensorButtonListener[listeners.size()]) ;
+ }
+
+ /**
+ * Remove the SensorButtonListener from the given SensorBinding.
+ */
+ private void removeSensorButtonListener
+ (SensorBinding sb, SensorButtonListener listener) {
+
+ Iterator i = sb.buttonBindingsList.iterator() ;
+ while (i.hasNext()) {
+ int instanceCount = 0 ;
+ SensorButtonBinding sbb = (SensorButtonBinding)i.next() ;
+
+ for (int j = 0 ; j < sbb.listeners.length ; j++) {
+ if (sbb.listeners[j] == listener)
+ sbb.listeners[j] = null ;
+ else if (sbb.listeners[j] != null)
+ instanceCount++ ;
+ }
+ if (instanceCount == 0) {
+ i.remove() ;
+ }
+ }
+ listsDirty = true ;
+ }
+
+ /**
+ * Remove the given SensorButtonListener
binding from the
+ * specified sensor.
+ *
+ * @param sensor the sensor from which to remove the listener
+ * @param listener the listener to be removed
+ */
+ public synchronized void removeSensorButtonListener
+ (Sensor sensor, SensorButtonListener listener) {
+
+ if (sensor == null)
+ throw new NullPointerException("\nsensor is null") ;
+
+ SensorBinding sb = getSensorBinding(sensor) ;
+ if (sb == null)
+ return ;
+
+ removeSensorButtonListener(sb, listener) ;
+ if (sb.buttonBindingsList.size() == 0 &&
+ sb.readBindingsList.size() == 0)
+ removeSensorBinding(sensor) ;
+
+ listsDirty = true ;
+ }
+
+ /**
+ * Remove the given SensorButtonListener
from all sensors.
+ *
+ * @param listener the listener to remove
+ */
+ public synchronized void removeSensorButtonListener
+ (SensorButtonListener listener) {
+
+ Iterator i = bindingsList.iterator() ;
+ while (i.hasNext()) {
+ SensorBinding sb = (SensorBinding)i.next() ;
+ removeSensorButtonListener(sb, listener) ;
+
+ if (sb.buttonBindingsList.size() == 0 &&
+ sb.readBindingsList.size() == 0) {
+ i.remove() ;
+ }
+ }
+ listsDirty = true ;
+ }
+
+ /**
+ * Creates a binding of the specified sensor to the given
+ * SensorReadListener
. The read listener is invoked
+ * every time dispatchEvents
is called and a button
+ * listener is not invoked.
+ *
+ * @param sensor the sensor to be bound
+ * @param readListener the SensorReadListener
+ * implementation
+ */
+ public synchronized void addSensorReadListener
+ (Sensor sensor, SensorReadListener readListener) {
+
+ if (sensor == null)
+ throw new NullPointerException("\nsensor is null") ;
+
+ SensorBinding sb = getSensorBinding(sensor) ;
+ if (sb == null) {
+ sb = new SensorBinding(sensor) ;
+ bindingsList.add(sb) ;
+ }
+ sb.readBindingsList.add(readListener) ;
+ listsDirty = true ;
+ }
+
+ /**
+ * Gets the SensorReadListeners
bound to the specified
+ * sensor.
+ *
+ * @param sensor the sensor of interest
+ * @return array of SensorReadListeners
bound to the
+ * given sensor, or null
+ */
+ public SensorReadListener[] getSensorReadListeners(Sensor sensor) {
+ if (sensor == null)
+ throw new NullPointerException("\nsensor is null") ;
+
+ SensorBinding sb = getSensorBinding(sensor) ;
+ if (sb == null)
+ return null ;
+ else if (sb.readBindingsList.size() == 0)
+ return null ;
+ else
+ return (SensorReadListener[])sb.readBindingsList.toArray
+ (new SensorReadListener[sb.readBindingsList.size()]) ;
+ }
+
+ /**
+ * Remove the SensorReadListener from the given SensorBinding.
+ */
+ private void removeSensorReadListener
+ (SensorBinding sb, SensorReadListener listener) {
+
+ Iterator i = sb.readBindingsList.iterator() ;
+ while (i.hasNext()) {
+ if (((SensorReadListener)i.next()) == listener)
+ i.remove() ;
+ }
+ listsDirty = true ;
+ }
+
+ /**
+ * Remove the given SensorReadListener
binding from the
+ * specified sensor.
+ *
+ * @param sensor the sensor from which to remove the listener
+ * @param listener the listener to be removed
+ */
+ public synchronized void removeSensorReadListener
+ (Sensor sensor, SensorReadListener listener) {
+
+ if (sensor == null)
+ throw new NullPointerException("\nsensor is null") ;
+
+ SensorBinding sb = getSensorBinding(sensor) ;
+ if (sb == null)
+ return ;
+
+ removeSensorReadListener(sb, listener) ;
+ if (sb.buttonBindingsList.size() == 0 &&
+ sb.readBindingsList.size() == 0)
+ removeSensorBinding(sensor) ;
+
+ listsDirty = true ;
+ }
+
+ /**
+ * Remove the given SensorReadListener
from all sensors.
+ *
+ * @param listener the listener to remove
+ */
+ public synchronized void removeSensorReadListener
+ (SensorReadListener listener) {
+
+ Iterator i = bindingsList.iterator() ;
+ while (i.hasNext()) {
+ SensorBinding sb = (SensorBinding)i.next() ;
+ removeSensorReadListener(sb, listener) ;
+
+ if (sb.buttonBindingsList.size() == 0 &&
+ sb.readBindingsList.size() == 0) {
+ i.remove() ;
+ }
+ }
+ listsDirty = true ;
+ }
+
+ /**
+ * Remove all sensor listeners bound to the given sensor.
+ */
+ public synchronized void removeSensorBinding(Sensor sensor) {
+ Iterator i = bindingsList.iterator() ;
+ while (i.hasNext()) {
+ SensorBinding sb = (SensorBinding)i.next() ;
+ if (sb.sensor == sensor) {
+ i.remove() ;
+ break ;
+ }
+ }
+ listsDirty = true ;
+ }
+
+ /**
+ * Returns an array of references to all sensors that have been bound
+ * to listeners.
+ * @return an array of sensors, or null if no sensors have been bound
+ */
+ public Sensor[] getSensors() {
+ if (bindingsList.size() == 0)
+ return null ;
+
+ Sensor[] s = new Sensor[bindingsList.size()] ;
+ for (int i = 0 ; i < bindingsList.size() ; i++)
+ s[i] = ((SensorBinding)bindingsList.get(i)).sensor ;
+
+ return s ;
+ }
+
+ /**
+ * Copies binding lists to arrays for event dispatch. This allows
+ * listeners to add or remove themselves or other listeners safely.
+ */
+ private synchronized void updateArrays() {
+ bindings = (SensorBinding[])bindingsList.toArray
+ (new SensorBinding[bindingsList.size()]) ;
+
+ for (int i = 0 ; i < bindings.length ; i++) {
+ bindings[i].updateArrays() ;
+ }
+ }
+
+ /**
+ * Reads all sensor button state and dispatches events to registered
+ * button and read listeners. This method is intended to be called from
+ * the processStimulus
implementation of a
+ * Behavior
or the pollAndProcessInput
method of
+ * an event-driven implementation of InputDevice
.
+ */
+ public void dispatchEvents() {
+ long t1 = t0 ;
+ t0 = J3DTimer.getValue() ;
+
+ if (listsDirty) {
+ updateArrays() ;
+ listsDirty = false ;
+ }
+
+ // Loop through all sensor bindings.
+ for (int k = 0 ; k < bindings.length ; k++) {
+ SensorBinding sb = bindings[k] ;
+ Sensor s = sb.sensor ;
+ Transform3D read = sb.read ;
+ int[] buttons = sb.buttons ;
+ int dragButton = 0 ;
+ boolean callReadListeners = true ;
+ boolean callDraggedListener = false ;
+
+ // Get this sensor's readings.
+ s.getRead(read) ;
+ s.lastButtons(buttons) ;
+
+ // Dispatch button listeners.
+ for (int j = 0 ; j < sb.buttonBindings.length ; j++) {
+ SensorButtonBinding sbb = sb.buttonBindings[j] ;
+ for (int i = 0 ; i < buttons.length ; i++) {
+ if (sbb.listeners[i] == null)
+ continue ;
+
+ // Check for button release.
+ if (sbb.prevButtons[i]) {
+ if (buttons[i] == 0) {
+ e.set(source, SensorEvent.RELEASED, s, read,
+ buttons, i, t0, t1) ;
+ sbb.listeners[i].released(e) ;
+ sbb.prevButtons[i] = false ;
+ sbb.buttonsHandled-- ;
+ }
+ else {
+ callDraggedListener = true ;
+ dragButton = i ;
+ }
+ callReadListeners = false ;
+ }
+ // Check for button press.
+ // Ignore multiple button presses if not enabled;
+ // otherwise, one listener is bound to all buttons.
+ else if (buttons[i] == 1) {
+ if (sbb.buttonsHandled == 0 || sbb.multiButton) {
+ e.set(source, SensorEvent.PRESSED, s, read,
+ buttons, i, t0, t1) ;
+ sbb.listeners[i].pressed(e) ;
+ sbb.prevButtons[i] = true ;
+ sbb.buttonsHandled++ ;
+ callReadListeners = false ;
+ }
+ }
+ }
+ if (callDraggedListener) {
+ // One drag event even if multiple buttons down.
+ // Called after all pressed() and released() calls.
+ e.set(source, SensorEvent.DRAGGED, s, read, buttons,
+ SensorEvent.NOBUTTON, t0, t1) ;
+ sbb.listeners[dragButton].dragged(e) ;
+ }
+ }
+ // Dispatch read listeners.
+ if (callReadListeners) {
+ e.set(source, SensorEvent.READ, s, read,
+ buttons, SensorEvent.NOBUTTON, t0, t1) ;
+ for (int r = 0 ; r < sb.readBindings.length ; r++) {
+ sb.readBindings[r].read(e) ;
+ }
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ String s = "SensorEventAgent@" + Integer.toHexString(hashCode()) ;
+ s += "\nsensor bindings:\n\n" ;
+ for (int i = 0 ; i < bindingsList.size() ; i++) {
+ s += ((SensorBinding)bindingsList.get(i)).toString() + "\n" ;
+ }
+ return s ;
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorGnomonEcho.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorGnomonEcho.java
new file mode 100644
index 0000000..47f5799
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorGnomonEcho.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.sensor ;
+
+import org.jogamp.java3d.Appearance;
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.Material;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransparencyAttributes;
+import org.jogamp.java3d.TriangleArray;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * A Shape3D representing a gnomon pointing along each coordinate
+ * axis. The base of the gnomon is a cube, and the coordinate axes are
+ * represented by pyramids attached to each face of the cube.
+ *
+ * @since Java 3D 1.3
+ */
+public class SensorGnomonEcho extends Shape3D {
+ /**
+ * Constructs a SensorGnomonEcho. Read and write capabilities are
+ * granted for the Appearance, Material, TransparencyAttributes,
+ * and TransparencyAttributes mode and value.
+ *
+ * @param transform translation and/or rotation to apply to the gnomon
+ * geometry; this should be the position and orientation of the sensor
+ * hotspot in the sensor's local coordinate system
+ * @param baseWidth width of each edge of the base cube in meters
+ * @param axisLength distance in meters from the gnomon center to
+ * the apex of the pyramid attached to each face of the base cube
+ * @param enableLighting boolean indicating whether normals should be
+ * generated and lighting enabled
+ */
+ public SensorGnomonEcho(Transform3D transform,
+ double baseWidth,
+ double axisLength,
+ boolean enableLighting) {
+ super() ;
+
+ int FRONT = 0 ;
+ int BACK = 1 ;
+ int LEFT = 2 ;
+ int RIGHT = 3 ;
+ int TOP = 4 ;
+ int BOTTOM = 5 ;
+ Point3f[] axes = new Point3f[6] ;
+ float length = (float)axisLength ;
+
+ axes[FRONT] = new Point3f(0f, 0f, length) ;
+ axes[BACK] = new Point3f(0f, 0f, -length) ;
+ axes[LEFT] = new Point3f(-length, 0f, 0f) ;
+ axes[RIGHT] = new Point3f( length, 0f, 0f) ;
+ axes[TOP] = new Point3f(0f, length, 0f) ;
+ axes[BOTTOM] = new Point3f(0f, -length, 0f) ;
+
+ if (transform != null)
+ for (int i = FRONT ; i <= BOTTOM ; i++)
+ transform.transform(axes[i]) ;
+
+ float offset = (float)baseWidth / 2.0f ;
+ Point3f[][] cube = new Point3f[6][4] ;
+
+ cube[FRONT][0] = new Point3f(-offset, -offset, offset) ;
+ cube[FRONT][1] = new Point3f( offset, -offset, offset) ;
+ cube[FRONT][2] = new Point3f( offset, offset, offset) ;
+ cube[FRONT][3] = new Point3f(-offset, offset, offset) ;
+
+ cube[BACK][0] = new Point3f( offset, -offset, -offset) ;
+ cube[BACK][1] = new Point3f(-offset, -offset, -offset) ;
+ cube[BACK][2] = new Point3f(-offset, offset, -offset) ;
+ cube[BACK][3] = new Point3f( offset, offset, -offset) ;
+
+ if (transform != null)
+ for (int i = FRONT ; i <= BACK ; i++)
+ for (int j = 0 ; j < 4 ; j++)
+ transform.transform(cube[i][j]) ;
+
+ cube[LEFT][0] = cube[BACK][1] ;
+ cube[LEFT][1] = cube[FRONT][0] ;
+ cube[LEFT][2] = cube[FRONT][3] ;
+ cube[LEFT][3] = cube[BACK][2] ;
+
+ cube[RIGHT][0] = cube[FRONT][1] ;
+ cube[RIGHT][1] = cube[BACK][0] ;
+ cube[RIGHT][2] = cube[BACK][3] ;
+ cube[RIGHT][3] = cube[FRONT][2] ;
+
+ cube[TOP][0] = cube[FRONT][3] ;
+ cube[TOP][1] = cube[FRONT][2] ;
+ cube[TOP][2] = cube[BACK][3] ;
+ cube[TOP][3] = cube[BACK][2] ;
+
+ cube[BOTTOM][0] = cube[BACK][1] ;
+ cube[BOTTOM][1] = cube[BACK][0] ;
+ cube[BOTTOM][2] = cube[FRONT][1] ;
+ cube[BOTTOM][3] = cube[FRONT][0] ;
+
+ int v = 0 ;
+ Point3f[] vertices = new Point3f[72] ;
+
+ for (int i = 0 ; i < 6 ; i++) {
+ vertices[v++] = cube[i][0] ;
+ vertices[v++] = cube[i][1] ;
+ vertices[v++] = axes[i] ;
+ vertices[v++] = cube[i][1] ;
+ vertices[v++] = cube[i][2] ;
+ vertices[v++] = axes[i] ;
+ vertices[v++] = cube[i][2] ;
+ vertices[v++] = cube[i][3] ;
+ vertices[v++] = axes[i] ;
+ vertices[v++] = cube[i][3] ;
+ vertices[v++] = cube[i][0] ;
+ vertices[v++] = axes[i] ;
+ }
+
+ int vertexFormat ;
+ Material m = new Material() ;
+ m.setCapability(Material.ALLOW_COMPONENT_READ) ;
+ m.setCapability(Material.ALLOW_COMPONENT_WRITE) ;
+
+ if (enableLighting) {
+ vertexFormat =
+ GeometryArray.COORDINATES | GeometryArray.NORMALS ;
+ m.setLightingEnable(true) ;
+ }
+ else {
+ vertexFormat = GeometryArray.COORDINATES ;
+ m.setLightingEnable(false) ;
+ }
+
+ TriangleArray ta = new TriangleArray(72, vertexFormat) ;
+ ta.setCoordinates(0, vertices) ;
+
+ if (enableLighting) {
+ Vector3f v0 = new Vector3f() ;
+ Vector3f v1 = new Vector3f() ;
+ Vector3f[] normals = new Vector3f[72] ;
+
+ for (int i = 0 ; i < 72 ; i += 3) {
+ v0.sub(vertices[i+1], vertices[i]) ;
+ v1.sub(vertices[i+2], vertices[i]) ;
+
+ Vector3f n = new Vector3f() ;
+ n.cross(v0, v1) ;
+ n.normalize() ;
+
+ normals[i] = n ;
+ normals[i+1] = n ;
+ normals[i+2] = n ;
+ }
+ ta.setNormals(0, normals) ;
+ }
+
+ Appearance a = new Appearance() ;
+ a.setMaterial(m) ;
+ a.setCapability(Appearance.ALLOW_MATERIAL_READ) ;
+ a.setCapability(Appearance.ALLOW_MATERIAL_WRITE) ;
+
+ TransparencyAttributes tra = new TransparencyAttributes() ;
+ tra.setCapability(TransparencyAttributes.ALLOW_MODE_READ) ;
+ tra.setCapability(TransparencyAttributes.ALLOW_MODE_WRITE) ;
+ tra.setCapability(TransparencyAttributes.ALLOW_VALUE_READ) ;
+ tra.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE) ;
+ ta.setCapability
+ (TransparencyAttributes.ALLOW_BLEND_FUNCTION_READ) ;
+ ta.setCapability
+ (TransparencyAttributes.ALLOW_BLEND_FUNCTION_WRITE) ;
+
+ a.setTransparencyAttributes(tra) ;
+ a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_READ) ;
+ a.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE) ;
+
+ setGeometry(ta) ;
+ setAppearance(a) ;
+
+ setCapability(ALLOW_APPEARANCE_READ) ;
+ setCapability(ALLOW_APPEARANCE_WRITE) ;
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorInputAdaptor.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorInputAdaptor.java
new file mode 100644
index 0000000..7ffcf43
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorInputAdaptor.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.sensor ;
+
+/**
+ * The adaptor which receives sensor button and read events. The methods
+ * in this class are empty; the ones of interest should be overridden by
+ * classes extending this adaptor.
+ *
+ * @since Java 3D 1.3
+ */
+public class SensorInputAdaptor
+ implements SensorButtonListener, SensorReadListener {
+
+ @Override
+ public void pressed(SensorEvent e) {
+ }
+
+ @Override
+ public void released(SensorEvent e) {
+ }
+
+ @Override
+ public void dragged(SensorEvent e) {
+ }
+
+ @Override
+ public void clicked(SensorEvent e) {
+ }
+
+ @Override
+ public void read(SensorEvent e) {
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorReadListener.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorReadListener.java
new file mode 100644
index 0000000..18dc892
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/SensorReadListener.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.sensor ;
+
+/**
+ * This defines the interface for handling a sensor's read events in
+ * conjuction with a SensorEventAgent
instance.
+ *
+ * The events passed to this listener's methods are ephemeral; they
+ * are only valid until the listener has returned. If a listener needs to
+ * retain the event it must be copied using the
+ * SensorEvent(SensorEvent)
constructor.
+ *
+ * @see SensorEvent
+ * @see SensorEventAgent
+ * @see SensorButtonListener
+ * @since Java 3D 1.3
+ */
+public interface SensorReadListener {
+ /**
+ * This method is called each time the dispatchEvents
+ * method of SensorEventAgent
is called and none of a
+ * sensor's buttons have been handled by a button listener. The
+ * sensor read value has not necessarily changed since the last read
+ * event.
+ *
+ * @param e the sensor event
+ */
+ public void read(SensorEvent e) ;
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/package.html b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/package.html
new file mode 100644
index 0000000..754890d
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/sensor/package.html
@@ -0,0 +1,11 @@
+
+
+
Provides 6DOF sensor behavior classes.
+ + diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/OrbitBehavior.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/OrbitBehavior.java new file mode 100644 index 0000000..9460efd --- /dev/null +++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/OrbitBehavior.java @@ -0,0 +1,1074 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed, licensed or + * intended for use in the design, construction, operation or + * maintenance of any nuclear facility. + * + */ + +package org.jogamp.java3d.utils.behaviors.vp; + +import java.awt.AWTEvent; +import java.awt.event.MouseEvent; + +import org.jogamp.java3d.Canvas3D; +import org.jogamp.java3d.Transform3D; +import org.jogamp.vecmath.Matrix3d; +import org.jogamp.vecmath.Point3d; +import org.jogamp.vecmath.Vector3d; + +import org.jogamp.java3d.internal.J3dUtilsI18N; +import org.jogamp.java3d.utils.universe.ViewingPlatform; + +/** + * Moves the View around a point of interest when the mouse is dragged with + * a mouse button pressed. Includes rotation, zoom, and translation + * actions. Zooming can also be obtained by using mouse wheel. + *
+ * This behavior must be added to the ViewingPlatform
+ * using the ViewingPlatform.setViewPlatformBehavior
method.
+ *
+ * The rotate action rotates the ViewPlatform around the point of interest + * when the mouse is moved with the main mouse button pressed. The + * rotation is in the direction of the mouse movement, with a default + * rotation of 0.01 radians for each pixel of mouse movement. + *
+ * The zoom action moves the ViewPlatform closer to or further from the + * point of interest when the mouse is moved with the middle mouse button + * pressed (or Alt-main mouse button on systems without a middle mouse button). + * The default zoom action is to translate the ViewPlatform 0.01 units for each + * pixel of mouse movement. Moving the mouse up moves the ViewPlatform closer, + * moving the mouse down moves the ViewPlatform further away. + *
+ * By default, the zoom action allows the ViewPlatform to move through
+ * the center of rotation to orbit at a negative radius.
+ * The STOP_ZOOM
constructor flag will stop the ViewPlatform at
+ * a minimum radius from the center. The default minimum radius is 0.0
+ * and can be set using the setMinRadius
method.
+ *
+ * The PROPORTIONAL_ZOOM
constructor flag changes the zoom action
+ * to move the ViewPlatform proportional to its distance from the center
+ * of rotation. For this mode, the default action is to move the ViewPlatform
+ * by 1% of its distance from the center of rotation for each pixel of
+ * mouse movement.
+ *
+ * The translate action translates the ViewPlatform when the mouse is moved + * with the right mouse button pressed (Shift-main mouse button on systems + * without a right mouse button). The translation is in the direction of the + * mouse movement, with a default translation of 0.01 units for each pixel + * of mouse movement. + *
+ * The sensitivity of the actions can be scaled using the
+ * set
ActionFactor()
methods which scale
+ * the default movement by the factor. The rotate and translate actions
+ * have separate factors for x and y.
+ *
+ * The actions can be reversed using the REVERSE_
ACTION
+ * constructor flags. The default action moves the ViewPlatform around the
+ * objects in the scene. The REVERSE_
ACTION flags can
+ * make the objects in the scene appear to be moving in the direction
+ * of the mouse movement.
+ *
+ * The actions can be disabled by either using the
+ * DISABLE_
ACTION constructor flags or the
+ * set
ActionEnable
methods.
+ *
+ * The default center of rotation is (0, 0, 0) and can be set using the
+ *
+ *
+ * NOTE: Applications should not call this method.
+ *
+ * @param vp the target ViewingPlatform for this behavior
+ */
+ public void setViewingPlatform(ViewingPlatform vp) {
+ this.vp = vp;
+
+ if (vp!=null)
+ targetTG = vp.getViewPlatformTransform();
+ else
+ targetTG = null;
+ }
+
+ /**
+ * Returns the ViewingPlatform for this behavior
+ * @return the ViewingPlatform for this behavior
+ */
+ public ViewingPlatform getViewingPlatform() {
+ return vp;
+ }
+
+ /**
+ * Copies the given Transform3D into the "home" transform, used to
+ * position and reorient the ViewingPlatform to a known point of interest.
+ *
+ * @param home source transform to be copied
+ * @since Java 3D 1.3
+ */
+ public void setHomeTransform(Transform3D home) {
+ if (homeTransform == null)
+ homeTransform = new Transform3D(home);
+ else
+ homeTransform.set(home);
+ }
+
+ /**
+ * Returns the behaviors "home" transform.
+ *
+ * @param home transform to be returned
+ * @since Java 3D 1.3
+ */
+ public void getHomeTransform(Transform3D home ) {
+ home.set( homeTransform );
+ }
+
+ /**
+ * Positions and reorients the ViewingPlatform to its "home" transform.
+ * @since Java 3D 1.3
+ */
+ public void goHome() {
+ if (targetTG != null && homeTransform != null)
+ targetTG.setTransform(homeTransform);
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/WandViewBehavior.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/WandViewBehavior.java
new file mode 100644
index 0000000..3dfe7ce
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/WandViewBehavior.java
@@ -0,0 +1,3911 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.vp ;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Map;
+
+import org.jogamp.java3d.Appearance;
+import org.jogamp.java3d.BadTransformException;
+import org.jogamp.java3d.BoundingSphere;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Group;
+import org.jogamp.java3d.Material;
+import org.jogamp.java3d.Sensor;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.java3d.TransparencyAttributes;
+import org.jogamp.java3d.View;
+import org.jogamp.java3d.WakeupCondition;
+import org.jogamp.java3d.WakeupOnElapsedFrames;
+import org.jogamp.vecmath.AxisAngle4d;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Matrix3d;
+import org.jogamp.vecmath.Matrix4d;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Vector3d;
+
+import org.jogamp.java3d.utils.behaviors.sensor.SensorBeamEcho;
+import org.jogamp.java3d.utils.behaviors.sensor.SensorButtonListener;
+import org.jogamp.java3d.utils.behaviors.sensor.SensorEvent;
+import org.jogamp.java3d.utils.behaviors.sensor.SensorEventAgent;
+import org.jogamp.java3d.utils.behaviors.sensor.SensorGnomonEcho;
+import org.jogamp.java3d.utils.behaviors.sensor.SensorInputAdaptor;
+import org.jogamp.java3d.utils.behaviors.sensor.SensorReadListener;
+import org.jogamp.java3d.utils.universe.ConfiguredUniverse;
+import org.jogamp.java3d.utils.universe.SimpleUniverse;
+import org.jogamp.java3d.utils.universe.Viewer;
+import org.jogamp.java3d.utils.universe.ViewingPlatform;
+
+/**
+ * Manipulates view platform transforms using a motion-tracked wand or mouse
+ * equipped with a six degree of freedom (6DOF) sensor. An optional two axis
+ * (2D) valuator sensor is also directly supported. Default operation is set
+ * up to enable both direct manipulation of the view transform and translation
+ * back and forth along the direction the 6DOF sensor is pointing; rotation
+ * is handled by the 2D valuator if available. An arbitrary number of sensors
+ * and action bindings can be customized by accessing this behavior's
+ *
+ * This behavior can be instantiated from the configuration file read by
+ *
+ * {@link #Sensor6D Sensor6D} is the 6DOF sensor to use. This can also be set
+ * directly with the appropriate constructor. This sensor must generate 6
+ * degree of freedom position and orientation reads relative to the tracker
+ * base in physical units. By default this behavior provides an echo for the
+ * 6DOF sensor which indicates its position and orientation in the virtual
+ * world; the echo attributes can be set by the {@link #EchoType EchoType},
+ * {@link #EchoSize EchoSize}, {@link #EchoColor EchoColor}, and {@link
+ * #EchoTransparency EchoTransparency} properties. See also the {@link
+ * #NominalSensorRotation NominalSensorRotation} property, and the
+ *
+ * {@link #Sensor2D Sensor2D} is an optional 2D valuator to use in conjunction
+ * with the 6DOF sensor. This can be set directly with the appropriate
+ * constructor. The valuator should generate X and Y reads ranging from [-1.0
+ * .. +1.0], with a nominal (deadzone) value of 0.0. The default
+ * configuration expects to find these values along the translation components
+ * of the read matrix, at indices 3 and 7, but these indices can be also be
+ * specified by the {@link #MatrixIndices2D MatrixIndices2D} property.
+ *
+ * {@link #ButtonAction6D ButtonAction6D} sets an action for a specific button
+ * on a 6DOF sensor. The actions available are:
+ *
+ * {@link #ReadAction2D ReadAction2D} sets the action bound to 2D valuator
+ * reads; that is, non-zero values generated by the device when no buttons
+ * have been pressed. If the value is (0.0, 0.0) or below the threshold value
+ * set by {@link #Threshold2D Threshold2D}, then this behavior does nothing;
+ * otherwise, the following actions can be performed:
+ *
+ * {@link #ButtonAction2D ButtonAction2D} sets an action for a specific button
+ * on the 2D valuator. The available actions are the same as for
+ *
+ * The view transform may be reset to its home transform by pressing a number
+ * of buttons simultaneously on the 6DOF sensor. The minimum number of
+ * buttons that must be pressed is set by {@link #ResetViewButtonCount6D
+ * ResetViewButtonCount6D}. This value must be greater than one; the default
+ * is three. This action may be disabled by setting the property value to
+ * None. The corresponding property for the 2D valuator is {@link
+ * #ResetViewButtonCount2D ResetViewButtonCount2D}, with a default value of
+ * None. Note, however, that the reset view action will be ineffectual if an
+ * action which always modifies the view transform is bound to reads on the
+ * sensor used to reset the view, since the reset transform will get
+ * overwritten by the read action.
+ *
+ * The special value
+ * Syntax:
+ * This constructor should only be used if either
+ *
+ * This constructor should only be used if either
+ *
+ * If the echo
+ * This constructor should only be used if
+ * If the echo
+ * This is invoked the first time
+ * The rotation direction is controlled by the direction the 2D valuator
+ * is pushed, and the rotation speed is scaled by the magnitude of the 2D
+ * valuator read values.
+ *
+ * This listener will work in conjunction with a 6DOF sensor if supplied
+ * in the constructor. If a 6DOF sensor is provided and
+ *
+ * The translation direction is controlled by the direction the 2D
+ * valuator is pushed, and the speed is the translation speed scaled by
+ * the fast speed factor and the magnitude of the 2D valuator reads.
+ *
+ * This listener will work in conjunction with a 6DOF sensor if supplied
+ * in the constructor. If a 6DOF sensor is provided then the translation
+ * occurs along the basis vectors of the 6DOF sensor's coordinate system;
+ * otherwise, the translation occurs along the view platform's basis
+ * vectors.
+ *
+ * @see #setReadAction2D
+ * @see #setButtonAction2D
+ * @see #setTranslationSpeed
+ * @see #setFastSpeedFactor
+ * @see #setThreshold2D
+ * @see #setMatrixIndices2D
+ */
+ public class TranslationListener2D extends ListenerBase {
+ private Sensor sensor2D, sensor6D ;
+ private double[] m = new double[16] ;
+ private Vector3d v3d = new Vector3d() ;
+ private Transform3D sensor2DRead = new Transform3D() ;
+ private double speedScaled ;
+
+ @Override
+ protected void initAction(Sensor s) {
+ super.initAction(s) ;
+ if (s != null && readAction6D == ECHO) {
+ // Disable the 6DOF echo. It will be updated in this action.
+ eventAgent.removeSensorReadListener(s, echoReadListener6D) ;
+ }
+ }
+
+ @Override
+ protected void endAction(Sensor s) {
+ super.endAction(s) ;
+ if (s != null && readAction6D == ECHO) {
+ // Enable the 6DOF sensor echo.
+ eventAgent.addSensorReadListener(s, echoReadListener6D) ;
+ }
+ }
+
+ /**
+ * Construct an instance of this class using the specified sensors.
+ *
+ * @param sensor2D 2D valuator sensor for translation
+ * @param sensor6D 6DOF sensor for translation direction; may be
+ *
+ * This listener will work in conjunction with a 6DOF sensor if supplied
+ * in the constructor. If
+ * This property is set in the configuration file. The first command form
+ * assumes that a
+ * Syntax:
+ * Alternative Syntax:
+ * This property is set in the configuration file. The first command form
+ * assumes that a
+ * Syntax:
+ * Alternative Syntax:
+ *
+ * Specifying a button index that is greater than that available with the
+ * 6DOF sensor will result in an
+ * This property is set in the configuration file read by
+ *
+ * Syntax:
+ *
+ * Specifying a button index that is greater that that available with the
+ * 6DOF sensor will result in an
+ * This method only configures the button listeners pre-defined by
+ * this behavior. For complete control over the button actions, access
+ * the
+ * The X and Y values from the valuator should have a continuous range
+ * from -1.0 to +1.0, although speeds can be scaled to compensate for a
+ * different range. The X and Y values are found in the sensor's read
+ * matrix at the indices specified by
+ * The default property value of
+ * A property value of
+ * If this property value is to
+ * A value of
+ * This property is set in the configuration file read by
+ *
+ * Syntax:
+ * The X and Y values from the valuator should have a continuous range
+ * from -1.0 to +1.0, although speeds can be scaled to compensate for a
+ * different range. The X and Y values are found in the sensor's read
+ * matrix at the indices specified by the
+ * The default action of
+ * A value of
+ * If the value is to
+ * A value of
+ * This method only configures the read listeners pre-defined by
+ * this behavior. For complete control over the read actions, access
+ * the
+ * Specifying a button index that is greater that that available with the
+ * 2D valuator will result in an
+ * This property is set in the configuration file read by
+ *
+ * Syntax:
+ * Specifying a button index that is greater that that available with the
+ * 2D valuator will result in an
+ * This method only configures the button listeners pre-defined by
+ * this behavior. For complete control over the button actions, access
+ * the
+ * The default is
+ * This property is set in the configuration file read by
+ *
+ * Syntax:
+ * The default is
+ * This method only configures the read listeners pre-defined by
+ * this behavior. For complete control over the read actions, access
+ * the
+ * Syntax:
+ *
+ * Syntax:
+ * Syntax:
+ * Syntax:
+ * Syntax:
+ * Syntax:
+ * Syntax:
+ * This property is set in the configuration file read by
+ *
+ * Syntax:
+ * The scaling applied with each frame is
+ * This property is set in the configuration file read by
+ *
+ * Syntax:
+ * The scaling applied with each frame is
+ * Syntax:
+ * The transform center source can be dynamically updated while the
+ * behavior is running.
+ *
+ * @param source either
+ * Syntax:
+ * The transform center can be dynamically updated while the behavior is
+ * running.
+ *
+ * @param center point in virtual world coordinates about which to rotate
+ * and scale
+ */
+ public void setTransformCenter(Point3d center) {
+ this.transformCenter.set(center) ;
+ }
+
+ /**
+ * Gets the rotation/scale center in virtual world coordinates.
+ * @param center
+ * This behavior assumes that when a hand-held wand is pointed directly at
+ * a screen in an upright position, then its 6DOF sensor's local
+ * coordinate system axes (its basis vectors) are nominally aligned with
+ * the image plate basis vectors; specifically, that the sensor's -Z axis
+ * points toward the screen, the +Y axis points up, and the +X axis points
+ * to the right. The translation and rotation listeners provided by this
+ * behavior assume this orientation to determine the transforms to be
+ * applied to the view platform; for example, translation applies along
+ * the sensor Z axis, while rotation applies about axes defined in the
+ * sensor XY plane.
+ *
+ * This nominal alignment may not hold true depending upon how the sensor
+ * is mounted and how the specific
+ * NOTE: the nominal sensor transform applies only to the
+ * translation directions and rotation axes created by the listeners
+ * defined in this behavior; for compatibility with the core Java 3D API,
+ * sensor reads and the sensor hotspot location are still expressed in the
+ * sensor's local coordinate system.
+ *
+ * This property is set in the configuration file read by
+ *
+ * Syntax:
+ * This behavior assumes that when a hand-held wand is pointed directly at
+ * a screen in an upright position, then its 6DOF sensor's local
+ * coordinate system axes (its basis vectors) are nominally aligned with
+ * the image plate basis vectors; specifically, that the sensor's -Z axis
+ * points toward the screen, the +Y axis points up, and the +X axis points
+ * to the right. The translation and rotation listeners provided by this
+ * behavior assume this orientation to determine the transforms to be
+ * applied to the view platform, in that translation applies along the
+ * sensor Z axis, and rotation applies about axes defined in the sensor XY
+ * plane.
+ *
+ * This nominal alignment may not hold true depending upon how the sensor
+ * is mounted and how the specific
+ * NOTE: the nominal sensor transform applies only to the
+ * translation directions and rotation axes created by the listeners
+ * defined in this behavior; for compatibility with the core Java 3D API,
+ * sensor reads and the sensor hotspot location are still expressed in the
+ * sensor's local coordinate system.
+ *
+ * @param transform Rotates vectors from the nominal sensor coordinate
+ * system system to the sensor's local coordinate system; only the
+ * rotational components are used. May be set
+ * Syntax:
+ * Syntax:
+ * Syntax:
+ * Syntax:
+ * Syntax:
+ * Syntax:
+ * This method must be called before the behavior is made live in order to
+ * have an effect.
+ *
+ * @param echo the Provides ViewPlatform navigation utility classes.
+ *
+ * A compression command includes an 8-bit header and can range up to 72
+ * bits in length. The command with the maximum length is a 2-bit color
+ * command with a 6-bit tag in the header, followed by four 16-bit color
+ * components of data.
+ *
+ * A subcommand is either a position, normal, or color, though in practice
+ * a position subcommand can only be part of a vertex command. Normal and
+ * color subcommands can be parts of separate global normal and color
+ * commands as well as parts of a vertex command.
+ *
+ * A subcommand includes a 6-bit header. Its length is 2 bits less than
+ * the length of the corresponding command.
+ *
+ * @param header contains compression command header bits, right-justified
+ * within the bits of the int
+ * @param headerLength number of bits in header, either 8 for commands or
+ * 6 for subcommands
+ * @param body contains the body of the compression command,
+ * right-justified within the bits of the long
+ * @param bodyLength number of bits in the body
+ */
+ void addCommand(int header, int headerLength, long body, int bodyLength) {
+ addByte(header, headerLength) ;
+ addLong(lastBody, lastBodyLength) ;
+
+ lastBody = body ;
+ lastBodyLength = bodyLength ;
+ }
+
+ //
+ // Add the rightmost bitCount bits of b to the end of the command stream.
+ //
+ private void addByte(int b, int bitCount) {
+ int bitsEmpty = 8 - bitOffset ;
+ b &= (int)CompressionStreamElement.lengthMask[bitCount] ;
+
+ if (bitCount <= bitsEmpty) {
+ bytes[byteOffset] |= (b << (bitsEmpty - bitCount)) ;
+ bitOffset += bitCount ;
+ return ;
+ }
+
+ if (bytes.length == byteOffset + 1) {
+ byte newBytes[] = new byte[bytes.length * 2] ;
+ System.arraycopy(bytes, 0, newBytes, 0, bytes.length) ;
+ bytes = newBytes ;
+ }
+
+ bitOffset = bitCount - bitsEmpty ;
+ bytes[byteOffset] |= (b >>> bitOffset) ;
+
+ byteOffset++ ;
+ bytes[byteOffset] = (byte)(b << (8 - bitOffset)) ;
+ }
+
+ //
+ // Add the rightmost bitCount bits of l to the end of the command stream.
+ //
+ private void addLong(long l, int bitCount) {
+ int byteCount = bitCount / 8 ;
+ int excessBits = bitCount - byteCount * 8 ;
+
+ if (excessBits > 0)
+ addByte((int)(l >>> (byteCount * 8)), excessBits) ;
+
+ while (byteCount > 0) {
+ addByte((int)((l >>> ((byteCount - 1) * 8)) & 0xff), 8) ;
+ byteCount-- ;
+ }
+ }
+
+ /**
+ * Add a no-op and the last command body. Pad out with additional no-ops
+ * to a 64-bit boundary if necessary. A call to this method is required
+ * in order to create a valid compression command stream.
+ */
+ void end() {
+ int excessBytes, padBits ;
+
+ // Add the 1st no-op and the last body.
+ addByte(V_NO_OP, 8) ;
+ addLong(lastBody, lastBodyLength) ;
+
+ excessBytes = (byteOffset + 1) % 8 ;
+ if (excessBytes == 0 && bitOffset == 8)
+ // No padding necessary.
+ return ;
+
+ // Need to add padding with a 2nd no-op.
+ addByte(V_NO_OP, 8) ;
+ excessBytes = (byteOffset + 1) % 8 ;
+
+ if (excessBytes == 0)
+ padBits = 8 - bitOffset ;
+ else {
+ int fillBytes = 8 - excessBytes ;
+ padBits = (8 * fillBytes) + (8 - bitOffset) ;
+ }
+
+ // The minimum length for a no-op command body is 5 bits.
+ if (padBits < 5)
+ // Have to cross the next 64-bit boundary.
+ padBits += 64 ;
+
+ // The maximum length of a no-op body is a 5-bit length + 31 bits of
+ // fill for a total of 36.
+ if (padBits < 37) {
+ // Pad with the body of the 1st no-op.
+ addLong((padBits - 5) << (padBits - 5), padBits) ;
+ return ;
+ }
+
+ // The number of bits to pad at this point is [37..68]. Knock off 24
+ // bits with the body of the 1st no-op to reduce the number of pad
+ // bits to [13..44], which can be filled with 1 more no-op.
+ addLong(19 << 19, 24) ;
+ padBits -= 24 ;
+
+ // Add a 3rd no-op.
+ addByte(V_NO_OP, 8) ;
+ padBits -= 8 ;
+
+ // Complete padding with the body of the 2nd no-op.
+ addLong((padBits - 5) << (padBits - 5), padBits) ;
+ }
+
+ /**
+ * Get the number of bytes in the compression command stream.
+ *
+ * @return size of compressed data in bytes
+ */
+ int getByteCount() {
+ if (byteOffset + bitOffset == 0)
+ return 0 ;
+ else
+ return byteOffset + 1 ;
+ }
+
+ /**
+ * Get the bytes composing the compression command stream.
+ *
+ * @return reference to array of bytes containing the compressed data
+ */
+ byte[] getBytes() {
+ return bytes ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/compression/CompressedGeometryFile.java b/src/classes/share/org/jogamp/java3d/utils/compression/CompressedGeometryFile.java
new file mode 100644
index 0000000..1bd7e87
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/compression/CompressedGeometryFile.java
@@ -0,0 +1,1011 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.compression;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import org.jogamp.java3d.CapabilityNotSetException;
+import org.jogamp.java3d.CompressedGeometry;
+import org.jogamp.java3d.CompressedGeometryHeader;
+
+//
+// The compressed geometry file format supported by this class has a 32
+// byte header followed by multiple compressed geometry objects.
+//
+// Each object consists of a block of compressed data and an 8-byte
+// individual block header describing its contents.
+//
+// The file ends with a directory data structure used for random access,
+// containing a 64-bit offset for each object in the order in which it
+// appears in the file. This is also used to find the size of the largest
+// object in the file and must be present.
+//
+
+/**
+ * This class provides methods to read and write compressed geometry resource
+ * files. These files usually end with the .cg extension and support
+ * sequential as well as random access to multiple compressed geometry
+ * objects.
+ *
+ * @deprecated As of Java 3D 1.5, replaced by
+ * org.jogamp.java3d.utils.geometry.compression.{@link org.jogamp.java3d.utils.geometry.compression.CompressedGeometryFile}.
+ */
+public class CompressedGeometryFile {
+ private static final boolean print = false ;
+ private static final boolean benchmark = false ;
+
+ /**
+ * The magic number which identifies the compressed geometry file type.
+ */
+ static final int MAGIC_NUMBER = 0xbaddfab4 ;
+
+ /**
+ * Byte offset of the magic number from start of file.
+ */
+ static final int MAGIC_NUMBER_OFFSET = 0 ;
+
+ /**
+ * Byte offset of the major version number from start of file.
+ */
+ static final int MAJOR_VERSION_OFFSET = 4 ;
+
+ /**
+ * Byte offset of the minor version number from start of file.
+ */
+ static final int MINOR_VERSION_OFFSET = 8 ;
+
+ /**
+ * Byte offset of the minor minor version number from start of file.
+ */
+ static final int MINOR_MINOR_VERSION_OFFSET = 12 ;
+
+ /**
+ * Byte offset of the number of objects from start of file.
+ */
+ static final int OBJECT_COUNT_OFFSET = 16 ;
+
+ /**
+ * Byte offset of the directory offset from start of file.
+ * This offset is long word aligned since the directory offset is a long.
+ */
+ static final int DIRECTORY_OFFSET_OFFSET = 24 ;
+
+ /**
+ * File header total size in bytes.
+ */
+ static final int HEADER_SIZE = 32 ;
+
+ /**
+ * Byte offset of the object size from start of individual compressed
+ * geometry block.
+ */
+ static final int OBJECT_SIZE_OFFSET = 0 ;
+
+ /**
+ * Byte offset of the compressed geometry data descriptor from start of
+ * individual compressed geometry block.
+ */
+ static final int GEOM_DATA_OFFSET = 4 ;
+
+ /**
+ * Bits in compressed geometry data descriptor which encode the buffer type.
+ */
+ static final int TYPE_MASK = 0x03 ;
+
+ /**
+ * Bit in compressed geometry data descriptor encoding presence of normals.
+ */
+ static final int NORMAL_PRESENT_MASK = 0x04 ;
+
+ /**
+ * Bit in compressed geometry data descriptor encoding presence of colors.
+ */
+ static final int COLOR_PRESENT_MASK = 0x08 ;
+
+ /**
+ * Bit in compressed geometry data descriptor encoding presence of alphas.
+ */
+ static final int ALPHA_PRESENT_MASK = 0x10 ;
+
+ /**
+ * Value in compressed geometry data descriptor for a point buffer type.
+ */
+ static final int TYPE_POINT = 1 ;
+
+ /**
+ * Value in compressed geometry data descriptor for a line buffer type.
+ */
+ static final int TYPE_LINE = 2 ;
+
+ /**
+ * Value in compressed geometry data descriptor for a triangle buffer type.
+ */
+ static final int TYPE_TRIANGLE = 3 ;
+
+ /**
+ * Block header total size in bytes.
+ */
+ static final int BLOCK_HEADER_SIZE = 8 ;
+
+ // The name of the compressed geometry resource file.
+ String fileName = null ;
+
+ // The major, minor, and subminor version number of the most recent
+ // compressor used to compress any of the objects in the compressed
+ // geometry resource file.
+ int majorVersionNumber ;
+ int minorVersionNumber ;
+ int minorMinorVersionNumber ;
+
+ // The number of objects in the compressed geometry resource file.
+ int objectCount ;
+
+ // The index of the current object in the file.
+ int objectIndex = 0 ;
+
+ // The random access file associated with this instance.
+ RandomAccessFile cgFile = null ;
+
+ // The magic number identifying the file type.
+ int magicNumber ;
+
+ // These fields are set from each individual block of compressed geometry.
+ byte cgBuffer[] ;
+ int geomSize ;
+ int geomStart ;
+ int geomDataType ;
+
+ // The directory of object offsets is read from the end of the file.
+ long directory[] ;
+ long directoryOffset ;
+
+ // The object sizes are computed from the directory offsets. These are
+ // used to allocate a buffer large enough to hold the largest object and
+ // to determine how many consecutive objects can be read into that buffer.
+ int objectSizes[] ;
+ int bufferObjectStart ;
+ int bufferObjectCount ;
+ int bufferNextObjectCount ;
+ int bufferNextObjectOffset ;
+
+ // The shared compressed geometry header object.
+ CompressedGeometryHeader cgh ;
+
+ // Flag indicating file update.
+ boolean fileUpdate = false ;
+
+ /**
+ * Construct a new CompressedGeometryFile instance associated with the
+ * specified file. An attempt is made to open the file with read-only
+ * access; if this fails then a FileNotFoundException is thrown.
+ *
+ * @param file path to the compressed geometry resource file
+ * @exception FileNotFoundException if file doesn't exist or
+ * cannot be read
+ * @exception IllegalArgumentException if the file is not a compressed
+ * geometry resource file
+ * @exception IOException if there is a header or directory read error
+ */
+ public CompressedGeometryFile(String file) throws IOException {
+ this(file, false) ;
+ }
+
+ /**
+ * Construct a new CompressedGeometryFile instance associated with the
+ * specified file.
+ *
+ * @param file path to the compressed geometry resource file
+ * @param rw if true, opens the file for read and write access or attempts
+ * to create one if it doesn't exist; if false, opens the file with
+ * read-only access
+ * @exception FileNotFoundException if file doesn't exist or
+ * access permissions disallow access
+ * @exception IllegalArgumentException if the file is not a compressed
+ * geometry resource file
+ * @exception IOException if there is a header or directory read error
+ */
+ public CompressedGeometryFile(String file, boolean rw) throws IOException {
+ // Open the file and read the file header.
+ open(file, rw) ;
+
+ // Copy the file name.
+ fileName = new String(file) ;
+
+ // Set up the file fields.
+ initialize() ;
+ }
+
+ /**
+ * Construct a new CompressedGeometryFile instance associated with a
+ * currently open RandomAccessFile.
+ *
+ * @param file currently open RandomAccessFile
+ * @exception IllegalArgumentException if the file is not a compressed
+ * geometry resource file
+ * @exception IOException if there is a header or directory read error
+ */
+ public CompressedGeometryFile(RandomAccessFile file) throws IOException {
+ // Copy the file reference.
+ cgFile = file ;
+
+ // Set up the file fields.
+ initialize() ;
+ }
+
+ /**
+ * Delete all compressed objects from this instance. This method may only
+ * be called after successfully creating a CompressedGeometryFile instance
+ * with read-write access, so a corrupted or otherwise invalid resource
+ * must be removed manually before it can be rewritten. The close()
+ * method must be called sometime after invoking clear() in order to write
+ * out the new directory structure.
+ *
+ * @exception IOException if clear fails
+ */
+ public void clear() throws IOException {
+ // Truncate the file.
+ cgFile.setLength(0) ;
+
+ // Set up the file fields.
+ initialize() ;
+ }
+
+ /**
+ * Return a string containing the file name associated with this instance
+ * or null if there is none.
+ *
+ * @return file name associated with this instance or null if there is
+ * none
+ */
+ public String getFileName() {
+ return fileName ;
+ }
+
+ /**
+ * Return the major version number of the most recent compressor used to
+ * compress any of the objects in this instance.
+ *
+ * @return major version number
+ */
+ public int getMajorVersionNumber() {
+ return majorVersionNumber ;
+ }
+
+ /**
+ * Return the minor version number of the most recent compressor used to
+ * compress any of the objects in this instance.
+ *
+ * @return minor version number
+ */
+ public int getMinorVersionNumber() {
+ return minorVersionNumber ;
+ }
+
+ /**
+ * Return the subminor version number of the most recent compressor used to
+ * compress any of the objects in this instance.
+ *
+ * @return subminor version number
+ */
+ public int getMinorMinorVersionNumber() {
+ return minorMinorVersionNumber ;
+ }
+
+ /**
+ * Return the number of compressed objects in this instance.
+ *
+ * @return number of compressed objects
+ */
+ public int getObjectCount() {
+ return objectCount ;
+ }
+
+ /**
+ * Return the current object index associated with this instance. This is
+ * the index of the object that would be returned by an immediately
+ * following call to the readNext() method. Its initial value is 0; -1
+ * is returned if the last object has been read.
+ *
+ * @return current object index, or -1 if at end
+ */
+ public int getCurrentIndex() {
+ if (objectIndex == objectCount)
+ return -1 ;
+ else
+ return objectIndex ;
+ }
+
+ /**
+ * Read the next compressed geometry object in the instance. This is
+ * initially the first object (index 0) in the instance; otherwise, it is
+ * whatever object is next after the last one read. The current object
+ * index is incremented by 1 after the read. When the last object is read
+ * the index becomes invalid and an immediately subsequent call to
+ * readNext() returns null.
+ *
+ * @return a CompressedGeometry node component, or null if the last object
+ * has been read
+ * @exception IOException if read fails
+ */
+ public CompressedGeometry readNext() throws IOException {
+ return readNext(cgBuffer.length) ;
+ }
+
+ /**
+ * Read all compressed geometry objects contained in the instance. The
+ * current object index becomes invalid; an immediately following call
+ * to readNext() will return null.
+ *
+ * @return an array of CompressedGeometry node components.
+ * @exception IOException if read fails
+ */
+ public CompressedGeometry[] read() throws IOException {
+ long startTime = 0 ;
+ CompressedGeometry cg[] = new CompressedGeometry[objectCount] ;
+
+ if (benchmark)
+ startTime = System.currentTimeMillis() ;
+
+ objectIndex = 0 ;
+ setFilePointer(directory[0]) ;
+ bufferNextObjectCount = 0 ;
+
+ for (int i = 0 ; i < objectCount ; i++)
+ cg[i] = readNext(cgBuffer.length) ;
+
+ if (benchmark) {
+ long t = System.currentTimeMillis() - startTime ;
+ System.out.println("read " + objectCount +
+ " objects " + cgFile.length() +
+ " bytes in " + (t/1000f) + " sec.") ;
+ System.out.println((cgFile.length()/(float)t) + " Kbytes/sec.") ;
+ }
+
+ return cg ;
+ }
+
+ /**
+ * Read the compressed geometry object at the specified index. The
+ * current object index is set to the subsequent object unless the last
+ * object has been read, in which case the index becomes invalid and an
+ * immediately following call to readNext() will return null.
+ *
+ * @param index compressed geometry object to read
+ * @return a CompressedGeometry node component
+ * @exception IndexOutOfBoundsException if object index is
+ * out of range
+ * @exception IOException if read fails
+ */
+ public CompressedGeometry read(int index) throws IOException {
+ objectIndex = index ;
+
+ if (objectIndex < 0) {
+ throw new IndexOutOfBoundsException
+ ("\nobject index must be >= 0") ;
+ }
+ if (objectIndex >= objectCount) {
+ throw new IndexOutOfBoundsException
+ ("\nobject index must be < " + objectCount) ;
+ }
+
+ // Check if object is in cache.
+ if ((objectIndex >= bufferObjectStart) &&
+ (objectIndex < bufferObjectStart + bufferObjectCount)) {
+ if (print) System.out.println("\ngetting object from cache\n") ;
+
+ bufferNextObjectOffset = (int)
+ (directory[objectIndex] - directory[bufferObjectStart]) ;
+
+ bufferNextObjectCount =
+ bufferObjectCount - (objectIndex - bufferObjectStart) ;
+
+ return readNext() ;
+
+ } else {
+ // Move file pointer to correct offset.
+ setFilePointer(directory[objectIndex]) ;
+
+ // Force a read from current offset. Disable cache read-ahead
+ // since cache hits are unlikely with random access.
+ bufferNextObjectCount = 0 ;
+ return readNext(objectSizes[objectIndex]) ;
+ }
+ }
+
+
+ /**
+ * Add a compressed geometry node component to the end of the instance.
+ * The current object index becomes invalid; an immediately following call
+ * to readNext() will return null. The close() method must be called at
+ * some later time in order to create a valid compressed geometry file.
+ *
+ * @param cg a compressed geometry node component
+ * @exception CapabilityNotSetException if unable to get compressed
+ * geometry data from the node component
+ * @exception IOException if write fails
+ */
+ public void write(CompressedGeometry cg) throws IOException {
+ CompressedGeometryHeader cgh = new CompressedGeometryHeader() ;
+ cg.getCompressedGeometryHeader(cgh) ;
+
+ // Update the read/write buffer size if necessary.
+ if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) {
+ cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ;
+ if (print) System.out.println("\ncgBuffer: reallocated " +
+ (cgh.size+BLOCK_HEADER_SIZE) +
+ " bytes") ;
+ }
+
+ cg.getCompressedGeometry(cgBuffer) ;
+ write(cgh, cgBuffer) ;
+ }
+
+ /**
+ * Add a buffer of compressed geometry data to the end of the
+ * resource. The current object index becomes invalid; an immediately
+ * following call to readNext() will return null. The close() method must
+ * be called at some later time in order to create a valid compressed
+ * geometry file.
+ *
+ * @param cgh a CompressedGeometryHeader object describing the data.
+ * @param geometry the compressed geometry data
+ * @exception IOException if write fails
+ */
+ public void write(CompressedGeometryHeader cgh, byte geometry[])
+ throws IOException {
+
+ // Update the read/write buffer size if necessary. It won't be used
+ // in this method, but should be big enough to read any object in
+ // the file, including the one to be written.
+ if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) {
+ cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ;
+ if (print) System.out.println("\ncgBuffer: reallocated " +
+ (cgh.size+BLOCK_HEADER_SIZE) +
+ " bytes") ;
+ }
+
+ // Assuming backward compatibility, the version number of the file
+ // should be the maximum of all individual compressed object versions.
+ if ((cgh.majorVersionNumber > majorVersionNumber)
+ ||
+ ((cgh.majorVersionNumber == majorVersionNumber) &&
+ (cgh.minorVersionNumber > minorVersionNumber))
+ ||
+ ((cgh.majorVersionNumber == majorVersionNumber) &&
+ (cgh.minorVersionNumber == minorVersionNumber) &&
+ (cgh.minorMinorVersionNumber > minorMinorVersionNumber))) {
+
+ majorVersionNumber = cgh.majorVersionNumber ;
+ minorVersionNumber = cgh.minorVersionNumber ;
+ minorMinorVersionNumber = cgh.minorMinorVersionNumber ;
+
+ this.cgh.majorVersionNumber = cgh.majorVersionNumber ;
+ this.cgh.minorVersionNumber = cgh.minorVersionNumber ;
+ this.cgh.minorMinorVersionNumber = cgh.minorMinorVersionNumber ;
+ }
+
+ // Get the buffer type and see what vertex components are present.
+ int geomDataType = 0 ;
+
+ switch (cgh.bufferType) {
+ case CompressedGeometryHeader.POINT_BUFFER:
+ geomDataType = TYPE_POINT ;
+ break ;
+ case CompressedGeometryHeader.LINE_BUFFER:
+ geomDataType = TYPE_LINE ;
+ break ;
+ case CompressedGeometryHeader.TRIANGLE_BUFFER:
+ geomDataType = TYPE_TRIANGLE ;
+ break ;
+ }
+
+ if ((cgh.bufferDataPresent &
+ CompressedGeometryHeader.NORMAL_IN_BUFFER) != 0)
+ geomDataType |= NORMAL_PRESENT_MASK ;
+
+ if ((cgh.bufferDataPresent &
+ CompressedGeometryHeader.COLOR_IN_BUFFER) != 0)
+ geomDataType |= COLOR_PRESENT_MASK ;
+
+ if ((cgh.bufferDataPresent &
+ CompressedGeometryHeader.ALPHA_IN_BUFFER) != 0)
+ geomDataType |= ALPHA_PRESENT_MASK ;
+
+ // Allocate new directory and object size arrays if necessary.
+ if (objectCount == directory.length) {
+ long newDirectory[] = new long[2*objectCount] ;
+ int newObjectSizes[] = new int[2*objectCount] ;
+
+ System.arraycopy(directory, 0,
+ newDirectory, 0, objectCount) ;
+ System.arraycopy(objectSizes, 0,
+ newObjectSizes, 0, objectCount) ;
+
+ directory = newDirectory ;
+ objectSizes = newObjectSizes ;
+
+ if (print)
+ System.out.println("\ndirectory and size arrays: reallocated " +
+ (2*objectCount) + " entries") ;
+ }
+
+ // Update directory and object size array.
+ directory[objectCount] = directoryOffset ;
+ objectSizes[objectCount] = cgh.size + BLOCK_HEADER_SIZE ;
+ objectCount++ ;
+
+ // Seek to the directory and overwrite from there.
+ setFilePointer(directoryOffset) ;
+ cgFile.writeInt(cgh.size) ;
+ cgFile.writeInt(geomDataType) ;
+ cgFile.write(geometry, 0, cgh.size) ;
+ if (print)
+ System.out.println("\nwrote " + cgh.size +
+ " byte compressed object to " + fileName +
+ "\nfile offset " + directoryOffset) ;
+
+ // Update the directory offset.
+ directoryOffset += cgh.size + BLOCK_HEADER_SIZE ;
+
+ // Return end-of-file on next read.
+ objectIndex = objectCount ;
+
+ // Flag file update so close() will write out the directory.
+ fileUpdate = true ;
+ }
+
+ /**
+ * Release the resources associated with this instance.
+ * Write out final header and directory if contents were updated.
+ * This method must be called in order to create a valid compressed
+ * geometry resource file if any updates were made.
+ */
+ public void close() {
+ if (cgFile != null) {
+ try {
+ if (fileUpdate) {
+ writeFileDirectory() ;
+ writeFileHeader() ;
+ }
+ cgFile.close() ;
+ }
+ catch (IOException e) {
+ // Don't propagate this exception.
+ System.out.println("\nException: " + e.getMessage()) ;
+ System.out.println("failed to close " + fileName) ;
+ }
+ }
+ cgFile = null ;
+ cgBuffer = null ;
+ directory = null ;
+ objectSizes = null ;
+ }
+
+
+ //
+ // Open the file. Specifying a non-existent file creates a new one if
+ // access permissions allow.
+ //
+ void open(String fname, boolean rw)
+ throws FileNotFoundException, IOException {
+
+ cgFile = null ;
+ String mode ;
+
+ if (rw)
+ mode = "rw" ;
+ else
+ mode = "r" ;
+
+ try {
+ cgFile = new RandomAccessFile(fname, mode) ;
+ if (print) System.out.println("\n" + fname +
+ ": opened mode " + mode) ;
+ }
+ catch (FileNotFoundException e) {
+ // N.B. this exception is also thrown on access permission errors
+ throw new FileNotFoundException(e.getMessage() + "\n" + fname +
+ ": open mode " + mode + " failed") ;
+ }
+ }
+
+ //
+ // Seek to the specified offset in the file.
+ //
+ void setFilePointer(long offset) throws IOException {
+ cgFile.seek(offset) ;
+
+ // Reset number of objects that can be read sequentially from cache.
+ bufferNextObjectCount = 0 ;
+ }
+
+ //
+ // Initialize directory, object size array, read/write buffer, and the
+ // shared compressed geometry header.
+ //
+ void initialize() throws IOException {
+ int maxSize = 0 ;
+
+ if (cgFile.length() == 0) {
+ // New file for writing: allocate nominal initial sizes for arrays.
+ objectCount = 0 ;
+ cgBuffer = new byte[32768] ;
+ directory = new long[16] ;
+ objectSizes = new int[directory.length] ;
+
+ // Set fields as if they have been read.
+ magicNumber = MAGIC_NUMBER ;
+ majorVersionNumber = 1 ;
+ minorVersionNumber = 0 ;
+ minorMinorVersionNumber = 0 ;
+ directoryOffset = HEADER_SIZE ;
+
+ // Write the file header.
+ writeFileHeader() ;
+
+ } else {
+ // Read the file header.
+ readFileHeader() ;
+
+ // Check file type.
+ if (magicNumber != MAGIC_NUMBER) {
+ close() ;
+ throw new IllegalArgumentException
+ ("\n" + fileName + " is not a compressed geometry file") ;
+ }
+
+ // Read the directory and determine object sizes.
+ directory = new long[objectCount] ;
+ readDirectory(directoryOffset, directory) ;
+
+ objectSizes = new int[objectCount] ;
+ for (int i = 0 ; i < objectCount-1 ; i++) {
+ objectSizes[i] = (int)(directory[i+1] - directory[i]) ;
+ if (objectSizes[i] > maxSize) maxSize = objectSizes[i] ;
+ }
+
+ if (objectCount > 0) {
+ objectSizes[objectCount-1] =
+ (int)(directoryOffset - directory[objectCount-1]) ;
+
+ if (objectSizes[objectCount-1] > maxSize)
+ maxSize = objectSizes[objectCount-1] ;
+ }
+
+ // Allocate a buffer big enough to read the largest object.
+ cgBuffer = new byte[maxSize] ;
+
+ // Move to the first object.
+ setFilePointer(HEADER_SIZE) ;
+ }
+
+ // Set up common parts of the compressed geometry object header.
+ cgh = new CompressedGeometryHeader() ;
+ cgh.majorVersionNumber = this.majorVersionNumber ;
+ cgh.minorVersionNumber = this.minorVersionNumber ;
+ cgh.minorMinorVersionNumber = this.minorMinorVersionNumber ;
+
+ if (print) {
+ System.out.println(fileName + ": " + objectCount + " objects") ;
+ System.out.println("magic number 0x" +
+ Integer.toHexString(magicNumber) +
+ ", version number " + majorVersionNumber +
+ "." + minorVersionNumber +
+ "." + minorMinorVersionNumber) ;
+ System.out.println("largest object is " + maxSize + " bytes") ;
+ }
+ }
+
+ //
+ // Read the file header.
+ //
+ void readFileHeader() throws IOException {
+ byte header[] = new byte[HEADER_SIZE] ;
+
+ try {
+ setFilePointer(0) ;
+ if (cgFile.read(header) != HEADER_SIZE) {
+ close() ;
+ throw new IOException("failed header read") ;
+ }
+ }
+ catch (IOException e) {
+ if (cgFile != null) {
+ close() ;
+ }
+ throw e ;
+ }
+
+ magicNumber =
+ ((header[MAGIC_NUMBER_OFFSET+0] & 0xff) << 24) |
+ ((header[MAGIC_NUMBER_OFFSET+1] & 0xff) << 16) |
+ ((header[MAGIC_NUMBER_OFFSET+2] & 0xff) << 8) |
+ ((header[MAGIC_NUMBER_OFFSET+3] & 0xff)) ;
+
+ majorVersionNumber =
+ ((header[MAJOR_VERSION_OFFSET+0] & 0xff) << 24) |
+ ((header[MAJOR_VERSION_OFFSET+1] & 0xff) << 16) |
+ ((header[MAJOR_VERSION_OFFSET+2] & 0xff) << 8) |
+ ((header[MAJOR_VERSION_OFFSET+3] & 0xff)) ;
+
+ minorVersionNumber =
+ ((header[MINOR_VERSION_OFFSET+0] & 0xff) << 24) |
+ ((header[MINOR_VERSION_OFFSET+1] & 0xff) << 16) |
+ ((header[MINOR_VERSION_OFFSET+2] & 0xff) << 8) |
+ ((header[MINOR_VERSION_OFFSET+3] & 0xff)) ;
+
+ minorMinorVersionNumber =
+ ((header[MINOR_MINOR_VERSION_OFFSET+0] & 0xff) << 24) |
+ ((header[MINOR_MINOR_VERSION_OFFSET+1] & 0xff) << 16) |
+ ((header[MINOR_MINOR_VERSION_OFFSET+2] & 0xff) << 8) |
+ ((header[MINOR_MINOR_VERSION_OFFSET+3] & 0xff)) ;
+
+ objectCount =
+ ((header[OBJECT_COUNT_OFFSET+0] & 0xff) << 24) |
+ ((header[OBJECT_COUNT_OFFSET+1] & 0xff) << 16) |
+ ((header[OBJECT_COUNT_OFFSET+2] & 0xff) << 8) |
+ ((header[OBJECT_COUNT_OFFSET+3] & 0xff)) ;
+
+ directoryOffset =
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+0] & 0xff) << 56) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+1] & 0xff) << 48) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+2] & 0xff) << 40) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+3] & 0xff) << 32) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+4] & 0xff) << 24) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+5] & 0xff) << 16) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+6] & 0xff) << 8) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+7] & 0xff)) ;
+ }
+
+ //
+ // Write the file header based on current field values.
+ //
+ void writeFileHeader() throws IOException {
+ setFilePointer(0) ;
+ try {
+ cgFile.writeInt(MAGIC_NUMBER) ;
+ cgFile.writeInt(majorVersionNumber) ;
+ cgFile.writeInt(minorVersionNumber) ;
+ cgFile.writeInt(minorMinorVersionNumber) ;
+ cgFile.writeInt(objectCount) ;
+ cgFile.writeInt(0) ; // long word alignment
+ cgFile.writeLong(directoryOffset) ;
+ if (print)
+ System.out.println("wrote file header for " + fileName) ;
+ }
+ catch (IOException e) {
+ throw new IOException
+ (e.getMessage() +
+ "\ncould not write file header for " + fileName) ;
+ }
+ }
+
+ //
+ // Read the directory of compressed geometry object offsets.
+ //
+ void readDirectory(long offset, long[] directory)
+ throws IOException {
+
+ byte buff[] = new byte[directory.length * 8] ;
+ setFilePointer(offset) ;
+
+ try {
+ cgFile.read(buff) ;
+ if (print)
+ System.out.println("read " + buff.length + " byte directory") ;
+ }
+ catch (IOException e) {
+ throw new IOException
+ (e.getMessage() +
+ "\nfailed to read " + buff.length +
+ " byte directory, offset " + offset + " in file " + fileName) ;
+ }
+
+ for (int i = 0 ; i < directory.length ; i++) {
+ directory[i] =
+ ((long)(buff[i*8+0] & 0xff) << 56) |
+ ((long)(buff[i*8+1] & 0xff) << 48) |
+ ((long)(buff[i*8+2] & 0xff) << 40) |
+ ((long)(buff[i*8+3] & 0xff) << 32) |
+ ((long)(buff[i*8+4] & 0xff) << 24) |
+ ((long)(buff[i*8+5] & 0xff) << 16) |
+ ((long)(buff[i*8+6] & 0xff) << 8) |
+ ((long)(buff[i*8+7] & 0xff)) ;
+ }
+ }
+
+ //
+ // Write the file directory.
+ //
+ void writeFileDirectory() throws IOException {
+ setFilePointer(directoryOffset) ;
+
+ int directoryAlign = (int)(directoryOffset % 8) ;
+ if (directoryAlign != 0) {
+ // Align to long word before writing directory of long offsets.
+ byte bytes[] = new byte[8-directoryAlign] ;
+
+ try {
+ cgFile.write(bytes) ;
+ if (print)
+ System.out.println ("wrote " + (8-directoryAlign) +
+ " bytes long alignment") ;
+ }
+ catch (IOException e) {
+ throw new IOException
+ (e.getMessage() +
+ "\ncould not write " + directoryAlign +
+ " bytes to long word align directory for " + fileName) ;
+ }
+ directoryOffset += 8-directoryAlign ;
+ }
+
+ try {
+ for (int i = 0 ; i < objectCount ; i++)
+ cgFile.writeLong(directory[i]) ;
+
+ if (print)
+ System.out.println("wrote file directory for " + fileName) ;
+ }
+ catch (IOException e) {
+ throw new IOException
+ (e.getMessage() +
+ "\ncould not write directory for " + fileName) ;
+ }
+ }
+
+ //
+ // Get the next compressed object in the file, either from the read-ahead
+ // cache or from the file itself.
+ //
+ CompressedGeometry readNext(int bufferReadLimit)
+ throws IOException {
+ if (objectIndex == objectCount)
+ return null ;
+
+ if (bufferNextObjectCount == 0) {
+ // No valid objects are in the cache.
+ int curSize = 0 ;
+ bufferObjectCount = 0 ;
+
+ // See how much we have room to read.
+ for (int i = objectIndex ; i < objectCount ; i++) {
+ if (curSize + objectSizes[i] > bufferReadLimit) break ;
+ curSize += objectSizes[i] ;
+ bufferObjectCount++ ;
+ }
+
+ // Try to read that amount.
+ try {
+ int n = cgFile.read(cgBuffer, 0, curSize) ;
+ if (print)
+ System.out.println("\nread " + n +
+ " bytes from " + fileName) ;
+ }
+ catch (IOException e) {
+ throw new IOException
+ (e.getMessage() +
+ "\nfailed to read " + curSize +
+ " bytes, object " + objectIndex + " in file " + fileName) ;
+ }
+
+ // Point at the first object in the buffer.
+ bufferObjectStart = objectIndex ;
+ bufferNextObjectCount = bufferObjectCount ;
+ bufferNextObjectOffset = 0 ;
+ }
+
+ // Get block header info.
+ geomSize =
+ ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+0]&0xff)<<24) |
+ ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+1]&0xff)<<16) |
+ ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+2]&0xff)<< 8) |
+ ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+3]&0xff)) ;
+
+ geomDataType =
+ ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+0]&0xff) << 24) |
+ ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+1]&0xff) << 16) |
+ ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+2]&0xff) << 8) |
+ ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+3]&0xff)) ;
+
+ // Get offset of compressed geometry data from start of buffer.
+ geomStart = bufferNextObjectOffset + BLOCK_HEADER_SIZE ;
+
+ if (print) {
+ System.out.println("\nobject " + objectIndex +
+ "\nfile offset " + directory[objectIndex] +
+ ", buffer offset " + bufferNextObjectOffset) ;
+ System.out.println("size " + geomSize + " bytes, " +
+ "data descriptor 0x" +
+ Integer.toHexString(geomDataType)) ;
+ }
+
+ // Update cache info.
+ bufferNextObjectOffset += objectSizes[objectIndex] ;
+ bufferNextObjectCount-- ;
+ objectIndex++ ;
+
+ return newCG(geomSize, geomStart, geomDataType) ;
+ }
+
+
+ //
+ // Construct and return a compressed geometry node.
+ //
+ CompressedGeometry newCG(int geomSize,
+ int geomStart,
+ int geomDataType) {
+ cgh.size = geomSize ;
+ cgh.start = geomStart ;
+
+ if ((geomDataType & TYPE_MASK) == TYPE_POINT)
+ cgh.bufferType = CompressedGeometryHeader.POINT_BUFFER ;
+ else if ((geomDataType & TYPE_MASK) == TYPE_LINE)
+ cgh.bufferType = CompressedGeometryHeader.LINE_BUFFER ;
+ else if ((geomDataType & TYPE_MASK) == TYPE_TRIANGLE)
+ cgh.bufferType = CompressedGeometryHeader.TRIANGLE_BUFFER ;
+
+ cgh.bufferDataPresent = 0 ;
+
+ if ((geomDataType & NORMAL_PRESENT_MASK) != 0)
+ cgh.bufferDataPresent |=
+ CompressedGeometryHeader.NORMAL_IN_BUFFER ;
+
+ if ((geomDataType & COLOR_PRESENT_MASK) != 0)
+ cgh.bufferDataPresent |=
+ CompressedGeometryHeader.COLOR_IN_BUFFER ;
+
+ if ((geomDataType & ALPHA_PRESENT_MASK) != 0)
+ cgh.bufferDataPresent |=
+ CompressedGeometryHeader.ALPHA_IN_BUFFER ;
+
+ return new CompressedGeometry(cgh, cgBuffer) ;
+ }
+
+ /**
+ * Release file resources when this object is garbage collected.
+ */
+ @Override
+ protected void finalize() {
+ close() ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStream.java b/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStream.java
new file mode 100644
index 0000000..38958b6
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStream.java
@@ -0,0 +1,2342 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.compression;
+
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.jogamp.java3d.Appearance;
+import org.jogamp.java3d.CompressedGeometryHeader;
+import org.jogamp.java3d.Geometry;
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.GeometryStripArray;
+import org.jogamp.java3d.IndexedGeometryArray;
+import org.jogamp.java3d.IndexedGeometryStripArray;
+import org.jogamp.java3d.IndexedLineArray;
+import org.jogamp.java3d.IndexedLineStripArray;
+import org.jogamp.java3d.IndexedQuadArray;
+import org.jogamp.java3d.IndexedTriangleArray;
+import org.jogamp.java3d.IndexedTriangleFanArray;
+import org.jogamp.java3d.IndexedTriangleStripArray;
+import org.jogamp.java3d.J3DBuffer;
+import org.jogamp.java3d.LineArray;
+import org.jogamp.java3d.LineStripArray;
+import org.jogamp.java3d.Material;
+import org.jogamp.java3d.QuadArray;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.java3d.TriangleArray;
+import org.jogamp.java3d.TriangleFanArray;
+import org.jogamp.java3d.TriangleStripArray;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Point3i;
+import org.jogamp.vecmath.Vector3f;
+
+import org.jogamp.java3d.internal.BufferWrapper;
+import org.jogamp.java3d.utils.geometry.GeometryInfo;
+
+/**
+ * This class is used as input to a geometry compressor. It collects elements
+ * such as vertices, normals, colors, mesh references, and quantization
+ * parameters in an ordered stream. This stream is then traversed during
+ * the compression process and used to build the compressed output buffer.
+ *
+ * @see GeometryCompressor
+ *
+ * @deprecated As of Java 3D 1.5, replaced by
+ * org.jogamp.java3d.utils.geometry.compression.{@link org.jogamp.java3d.utils.geometry.compression.CompressionStream}.
+ */
+public class CompressionStream {
+ //
+ // NOTE: For now, copies are made of all GeometryArray vertex components
+ // even when by-reference access is available.
+ //
+ // TODO: Retrofit all CompressionStreamElements and MeshBuffer to handle
+ // offsets to vertex data array references so that vertex components don't
+ // have to be copied. New CompressionStreamElements could be defined to
+ // set the current array reference during the quantization pass, or the
+ // reference could be included in every CompressionStreamElement along
+ // with the data offsets.
+ //
+ // TODO: Quantize on-the-fly when adding GeometryArray vertex data so that
+ // CompressionStreamElements don't need references to the original float,
+ // double, or byte data. Quantization is currently a separate pass since
+ // the 1st pass adds vertex data and gets the total object bounds, but
+ // this can be computed by merging the bounds of each GeometryArray
+ // compressed into a single object. The 2nd pass quantization is still
+ // needed for vertex data which isn't retrieved from a GeometryArray; for
+ // example, apps that might use the addVertex() methods directly instead
+ // of addGeometryArray().
+ //
+ // TODO: To further optimize memory, create new subclasses of
+ // CompressionStream{Color, Normal} for bundled attributes and add them as
+ // explicit stream elements. Then CompressionStreamVertex won't need to
+ // carry references to them. This memory savings might be negated by the
+ // extra overhead of adding more elements to the stream, however.
+ //
+ // TODO: Keep the absolute quantized values in the mesh buffer mirror so
+ // that unmeshed CompressionStreamElements don't need to carry them.
+ //
+ // TODO: Support texture coordinate compression even though Level II is
+ // not supported by any hardware decompressor on any graphics card.
+ // Software decompression is still useful for applications interested in
+ // minimizing file space, transmission time, and object loading time.
+ //
+ private static final boolean debug = false ;
+ private static final boolean benchmark = false ;
+
+ // Mesh buffer normal substitution is unavailable in Level I.
+ private static final boolean noMeshNormalSubstitution = true ;
+
+ /**
+ * This flag indicates that a vertex starts a new triangle or line strip.
+ */
+ static final int RESTART = 1 ;
+
+ /**
+ * This flag indicates that the next triangle in the strip is defined by
+ * replacing the middle vertex of the previous triangle in the strip.
+ * Equivalent to REPLACE_OLDEST for line strips.
+ */
+ static final int REPLACE_MIDDLE = 2 ;
+
+ /**
+ * This flag indicates that the next triangle in the strip is defined by
+ * replacing the oldest vertex of the previous triangle in the strip.
+ * Equivalent to REPLACE_MIDDLE for line strips.
+ */
+ static final int REPLACE_OLDEST = 3 ;
+
+ /**
+ * This flag indicates that a vertex is to be pushed into the mesh buffer.
+ */
+ static final int MESH_PUSH = 1 ;
+
+ /**
+ * This flag indicates that a vertex does not use the mesh buffer.
+ */
+ static final int NO_MESH_PUSH = 0 ;
+
+ /**
+ * Byte to float scale factor for scaling byte color components.
+ */
+ static final float ByteToFloatScale = 1.0f/255.0f;
+
+ /**
+ * Type of this stream, either CompressedGeometryHeader.POINT_BUFFER,
+ * CompressedGeometryHeader.LINE_BUFFER, or
+ * CompressedGeometryHeader.TRIANGLE_BUFFER
+ */
+ int streamType ;
+
+ /**
+ * A mask indicating which components are present in each vertex, as
+ * defined by GeometryArray.
+ */
+ int vertexComponents ;
+
+ /**
+ * Boolean indicating colors are bundled with the vertices.
+ */
+ boolean vertexColors ;
+
+ /**
+ * Boolean indicating RGB colors are bundled with the vertices.
+ */
+ boolean vertexColor3 ;
+
+ /**
+ * Boolean indicating RGBA colors are bundled with the vertices.
+ */
+ boolean vertexColor4 ;
+
+ /**
+ * Boolean indicating normals are bundled with the vertices.
+ */
+ boolean vertexNormals ;
+
+ /**
+ * Boolean indicating texture coordinates are present.
+ */
+ boolean vertexTextures ;
+
+ /**
+ * Boolean indicating that 2D texture coordinates are used.
+ * Currently only used to skip over textures in interleaved data.
+ */
+ boolean vertexTexture2 ;
+
+ /**
+ * Boolean indicating that 3D texture coordinates are used.
+ * Currently only used to skip over textures in interleaved data.
+ */
+ boolean vertexTexture3 ;
+
+ /**
+ * Boolean indicating that 4D texture coordinates are used.
+ * Currently only used to skip over textures in interleaved data.
+ */
+ boolean vertexTexture4 ;
+
+ /**
+ * Axes-aligned box enclosing all vertices in model coordinates.
+ */
+ Point3d mcBounds[] = new Point3d[2] ;
+
+ /**
+ * Axes-aligned box enclosing all vertices in normalized coordinates.
+ */
+ Point3d ncBounds[] = new Point3d[2] ;
+
+ /**
+ * Axes-aligned box enclosing all vertices in quantized coordinates.
+ */
+ Point3i qcBounds[] = new Point3i[2] ;
+
+ /**
+ * Center for normalizing positions to the unit cube.
+ */
+ double center[] = new double[3] ;
+
+ /**
+ * Maximum position range along the 3 axes.
+ */
+ double positionRangeMaximum ;
+
+ /**
+ * Scale for normalizing positions to the unit cube.
+ */
+ double scale ;
+
+ /**
+ * Current position component (X, Y, and Z) quantization value. This can
+ * range from 1 to 16 bits and has a default of 16.
+ *
+ * At 1 bit of quantization it is not possible to express positive
+ * absolute or delta positions.
+ */
+ int positionQuant ;
+
+ /**
+ * Current color component (R, G, B, A) quantization value. This can
+ * range from 2 to 16 bits and has a default of 9.
+ *
+ * A color component is represented with a signed fixed-point value in
+ * order to be able express negative deltas; the default of 9 bits
+ * corresponds to the 8-bit color component range of the graphics hardware
+ * commonly available. Colors must be non-negative, so the lower limit of
+ * quantization is 2 bits.
+ */
+ int colorQuant ;
+
+ /**
+ * Current normal component (U and V) quantization value. This can range
+ * from 0 to 6 bits and has a default of 6.
+ *
+ * At 0 bits of quantization normals are represented only as 6 bit
+ * sextant/octant pairs and 14 specially encoded normals (the 6 axis
+ * normals and the 8 octant midpoint normals); since U and V can only be 0
+ * at the minimum quantization, the totally number of unique normals is
+ * 12 + 14 = 26.
+ */
+ int normalQuant ;
+
+ /**
+ * Flag indicating position quantization change.
+ */
+ boolean positionQuantChanged ;
+
+ /**
+ * Flag indicating color quantization change.
+ */
+ boolean colorQuantChanged ;
+
+ /**
+ * Flag indicating normal quantization change.
+ */
+ boolean normalQuantChanged ;
+
+ /**
+ * Last quantized position.
+ */
+ int lastPosition[] = new int[3] ;
+
+ /**
+ * Last quantized color.
+ */
+ int lastColor[] = new int[4] ;
+
+ /**
+ * Last quantized normal's sextant.
+ */
+ int lastSextant ;
+
+ /**
+ * Last quantized normal's octant.
+ */
+ int lastOctant ;
+
+ /**
+ * Last quantized normal's U encoding parameter.
+ */
+ int lastU ;
+
+ /**
+ * Last quantized normal's V encoding parameter.
+ */
+ int lastV ;
+
+ /**
+ * Flag indicating last normal used a special encoding.
+ */
+ boolean lastSpecialNormal ;
+
+ /**
+ * Flag indicating the first position in this stream.
+ */
+ boolean firstPosition ;
+
+ /**
+ * Flag indicating the first color in this stream.
+ */
+ boolean firstColor ;
+
+ /**
+ * Flag indicating the first normal in this stream.
+ */
+ boolean firstNormal ;
+
+ /**
+ * The total number of bytes used to create the uncompressed geometric
+ * elements in this stream, useful for performance analysis. This
+ * excludes mesh buffer references.
+ */
+ int byteCount ;
+
+ /**
+ * The number of vertices created for this stream, excluding mesh buffer
+ * references.
+ */
+ int vertexCount ;
+
+ /**
+ * The number of mesh buffer references created for this stream.
+ */
+ int meshReferenceCount ;
+
+ /**
+ * Mesh buffer mirror used for computing deltas during quantization pass
+ * and a limited meshing algorithm for unstripped data.
+ */
+ MeshBuffer meshBuffer = new MeshBuffer() ;
+
+
+ // Collection which holds the elements of this stream.
+ private Collection stream ;
+
+ // True if preceding stream elements were colors or normals. Used to flag
+ // color and normal mesh buffer substitution when computing deltas during
+ // quantization pass.
+ private boolean lastElementColor = false ;
+ private boolean lastLastElementColor = false ;
+ private boolean lastElementNormal = false ;
+ private boolean lastLastElementNormal = false ;
+
+ // Some convenient temporary holding variables.
+ private Point3f p3f = new Point3f() ;
+ private Color3f c3f = new Color3f() ;
+ private Color4f c4f = new Color4f() ;
+ private Vector3f n3f = new Vector3f() ;
+
+
+ // Private constructor for common initializations.
+ private CompressionStream() {
+ this.stream = new LinkedList() ;
+
+ byteCount = 0 ;
+ vertexCount = 0 ;
+ meshReferenceCount = 0 ;
+
+ mcBounds[0] = new Point3d(Double.POSITIVE_INFINITY,
+ Double.POSITIVE_INFINITY,
+ Double.POSITIVE_INFINITY) ;
+ mcBounds[1] = new Point3d(Double.NEGATIVE_INFINITY,
+ Double.NEGATIVE_INFINITY,
+ Double.NEGATIVE_INFINITY) ;
+
+ qcBounds[0] = new Point3i(Integer.MAX_VALUE,
+ Integer.MAX_VALUE,
+ Integer.MAX_VALUE) ;
+ qcBounds[1] = new Point3i(Integer.MIN_VALUE,
+ Integer.MIN_VALUE,
+ Integer.MIN_VALUE) ;
+
+ /* normalized bounds computed from quantized bounds */
+ ncBounds[0] = new Point3d() ;
+ ncBounds[1] = new Point3d() ;
+ }
+
+ /**
+ * Creates a new CompressionStream for the specified geometry type and
+ * vertex format.
+ *
+ * @param streamType type of data in this stream, either
+ * CompressedGeometryHeader.POINT_BUFFER,
+ * CompressedGeometryHeader.LINE_BUFFER, or
+ * CompressedGeometryHeader.TRIANGLE_BUFFER
+ *
+ * @param vertexComponents a mask indicating which components are present
+ * in each vertex, as defined by GeometryArray: COORDINATES, NORMALS, and
+ * COLOR_3 or COLOR_4.
+ *
+ * @see GeometryCompressor
+ * @see GeometryArray
+ */
+ CompressionStream(int streamType, int vertexComponents) {
+ this() ;
+ this.streamType = streamType ;
+ this.vertexComponents = getVertexComponents(vertexComponents) ;
+ }
+
+ // See what vertex geometry components are present. The byReference,
+ // interleaved, useNIOBuffer, and useCoordIndexOnly flags are not
+ // examined.
+ private int getVertexComponents(int vertexFormat) {
+ int components = 0 ;
+
+ vertexColors = vertexColor3 = vertexColor4 = vertexNormals =
+ vertexTextures = vertexTexture2 = vertexTexture3 = vertexTexture4 =
+ false ;
+
+ if ((vertexFormat & GeometryArray.NORMALS) != 0) {
+ vertexNormals = true ;
+ components &= GeometryArray.NORMALS ;
+ if (debug) System.out.println("vertexNormals") ;
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR_3) != 0) {
+ vertexColors = true ;
+
+ if ((vertexFormat & GeometryArray.COLOR_4) != 0) {
+ vertexColor4 = true ;
+ components &= GeometryArray.COLOR_4 ;
+ if (debug) System.out.println("vertexColor4") ;
+ }
+ else {
+ vertexColor3 = true ;
+ components &= GeometryArray.COLOR_3 ;
+ if (debug) System.out.println("vertexColor3") ;
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
+ vertexTextures = true ;
+ vertexTexture2 = true ;
+ components &= GeometryArray.TEXTURE_COORDINATE_2 ;
+ if (debug) System.out.println("vertexTexture2") ;
+ }
+ else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ vertexTextures = true ;
+ vertexTexture3 = true ;
+ components &= GeometryArray.TEXTURE_COORDINATE_3 ;
+ if (debug) System.out.println("vertexTexture3") ;
+ }
+ else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ vertexTextures = true ;
+ vertexTexture4 = true ;
+ components &= GeometryArray.TEXTURE_COORDINATE_4 ;
+ if (debug) System.out.println("vertexTexture4") ;
+ }
+
+ if (vertexTextures)
+ // Throw exception for now until texture is supported.
+ throw new UnsupportedOperationException
+ ("\ncompression of texture coordinates is not supported") ;
+
+ return components ;
+ }
+
+ // Get the streamType associated with a GeometryArray instance.
+ private int getStreamType(GeometryArray ga) {
+ if (ga instanceof TriangleStripArray ||
+ ga instanceof IndexedTriangleStripArray ||
+ ga instanceof TriangleFanArray ||
+ ga instanceof IndexedTriangleFanArray ||
+ ga instanceof TriangleArray ||
+ ga instanceof IndexedTriangleArray ||
+ ga instanceof QuadArray ||
+ ga instanceof IndexedQuadArray)
+
+ return CompressedGeometryHeader.TRIANGLE_BUFFER ;
+
+ else if (ga instanceof LineArray ||
+ ga instanceof IndexedLineArray ||
+ ga instanceof LineStripArray ||
+ ga instanceof IndexedLineStripArray)
+
+ return CompressedGeometryHeader.LINE_BUFFER ;
+
+ else
+ return CompressedGeometryHeader.POINT_BUFFER ;
+ }
+
+ /**
+ * Iterates across all compression stream elements and applies
+ * quantization parameters, encoding consecutive vertices as delta values
+ * whenever possible. Each geometric element is mapped to a HuffmanNode
+ * object containing its resulting bit length, right shift (trailing 0
+ * count), and absolute or relative status.
+ *
+ * Positions are normalized to span a unit cube via an offset and a
+ * uniform scale factor that maps the midpoint of the object extents along
+ * each dimension to the origin, and the longest dimension of the object to
+ * the open interval (-1.0 .. +1.0). The geometric endpoints along that
+ * dimension are both one quantum away from unity; for example, at a
+ * position quantization of 6 bits, an object would be normalized so that
+ * its most negative dimension is at (-1 + 1/64) and the most positive is
+ * at (1 - 1/64).
+ *
+ * Normals are assumed to be of unit length. Color components are clamped
+ * to the [0..1) range, where the right endpoint is one quantum less
+ * than 1.0.
+ *
+ * @param huffmanTable Table which will map geometric compression stream
+ * elements to HuffmanNode objects describing each element's data
+ * representation. This table can then be processed with Huffman's
+ * algorithm to optimize the bit length of descriptor tags according to
+ * the number of geometric elements mapped to each tag.
+ */
+ void quantize(HuffmanTable huffmanTable) {
+ // Set up default initial quantization parameters. The position and
+ // color parameters specify the number of bits for each X, Y, Z, R, G,
+ // B, or A component. The normal quantization parameter specifies the
+ // number of bits for each U and V component.
+ positionQuant = 16 ;
+ colorQuant = 9 ;
+ normalQuant = 6 ;
+
+ // Compute position center and scaling for normalization to the unit
+ // cube. This is a volume bounded by the open intervals (-1..1) on
+ // each axis.
+ center[0] = (mcBounds[1].x + mcBounds[0].x) / 2.0 ;
+ center[1] = (mcBounds[1].y + mcBounds[0].y) / 2.0 ;
+ center[2] = (mcBounds[1].z + mcBounds[0].z) / 2.0 ;
+
+ double xRange = mcBounds[1].x - mcBounds[0].x ;
+ double yRange = mcBounds[1].y - mcBounds[0].y ;
+ double zRange = mcBounds[1].z - mcBounds[0].z ;
+
+ if (xRange > yRange)
+ positionRangeMaximum = xRange ;
+ else
+ positionRangeMaximum = yRange ;
+
+ if (zRange > positionRangeMaximum)
+ positionRangeMaximum = zRange ;
+
+ // Adjust the range of the unit cube to match the default
+ // quantization.
+ //
+ // This scale factor along with the center values computed above will
+ // produce 16-bit integer representations of the floating point
+ // position coordinates ranging symmetrically about 0 from -32767 to
+ // +32767. -32768 is not used and the normalized floating point
+ // position coordinates of -1.0 as well as +1.0 will not be
+ // represented.
+ //
+ // Applications which wish to seamlessly stitch together compressed
+ // objects will need to be aware that the range of normalized
+ // positions will be one quantum away from the [-1..1] endpoints of
+ // the unit cube and should adjust scale factors accordingly.
+ scale = (2.0 / positionRangeMaximum) * (32767.0 / 32768.0) ;
+
+ // Flag quantization change.
+ positionQuantChanged = colorQuantChanged = normalQuantChanged = true ;
+
+ // Flag first position, color, and normal.
+ firstPosition = firstColor = firstNormal = true ;
+
+ // Apply quantization.
+ Iterator i = stream.iterator() ;
+ while (i.hasNext()) {
+ Object o = i.next() ;
+
+ if (o instanceof CompressionStreamElement) {
+ ((CompressionStreamElement)o).quantize(this, huffmanTable) ;
+
+ // Keep track of whether last two elements were colors or
+ // normals for mesh buffer component substitution semantics.
+ lastLastElementColor = lastElementColor ;
+ lastLastElementNormal = lastElementNormal ;
+ lastElementColor = lastElementNormal = false ;
+
+ if (o instanceof CompressionStreamColor)
+ lastElementColor = true ;
+ else if (o instanceof CompressionStreamNormal)
+ lastElementNormal = true ;
+ }
+ }
+
+ // Compute the bounds in normalized coordinates.
+ ncBounds[0].x = (double)qcBounds[0].x / 32768.0 ;
+ ncBounds[0].y = (double)qcBounds[0].y / 32768.0 ;
+ ncBounds[0].z = (double)qcBounds[0].z / 32768.0 ;
+
+ ncBounds[1].x = (double)qcBounds[1].x / 32768.0 ;
+ ncBounds[1].y = (double)qcBounds[1].y / 32768.0 ;
+ ncBounds[1].z = (double)qcBounds[1].z / 32768.0 ;
+ }
+
+ /**
+ * Iterates across all compression stream elements and builds the
+ * compressed geometry command stream output.
+ *
+ * @param huffmanTable Table which maps geometric elements in this stream
+ * to tags describing the encoding parameters (length, shift, and
+ * absolute/relative status) to be used for their representations in the
+ * compressed output. All tags must be 6 bits or less in length, and the
+ * sum of the number of bits in the tag plus the number of bits in the
+ * data it describes must be at least 6 bits in length.
+ *
+ * @param outputBuffer CommandStream to use for collecting the compressed
+ * bits.
+ */
+ void outputCommands(HuffmanTable huffmanTable, CommandStream outputBuffer) {
+ //
+ // The first command output is setState to indicate what data is
+ // bundled with each vertex. Although the semantics of geometry
+ // decompression allow setState to appear anywhere in the stream, this
+ // cannot be handled by the current Java 3D software decompressor,
+ // which internally decompresses an entire compressed buffer into a
+ // single retained object sharing a single consistent vertex format.
+ // This limitation may be removed in subsequent releases of Java 3D.
+ //
+ int bnv = (vertexNormals? 1 : 0) ;
+ int bcv = ((vertexColor3 || vertexColor4)? 1 : 0) ;
+ int cap = (vertexColor4? 1 : 0) ;
+
+ int command = CommandStream.SET_STATE | bnv ;
+ long data = (bcv << 2) | (cap << 1) ;
+
+ // Output the setState command.
+ outputBuffer.addCommand(command, 8, data, 3) ;
+
+ // Output the Huffman table commands.
+ huffmanTable.outputCommands(outputBuffer) ;
+
+ // Output each compression stream element's data.
+ Iterator i = stream.iterator() ;
+ while (i.hasNext()) {
+ Object o = i.next() ;
+ if (o instanceof CompressionStreamElement)
+ ((CompressionStreamElement)o).outputCommand(huffmanTable,
+ outputBuffer) ;
+ }
+
+ // Finish the header-forwarding interleave and long-word align.
+ outputBuffer.end() ;
+ }
+
+ /**
+ * Retrieve the total size of the uncompressed geometric data in bytes,
+ * excluding mesh buffer references.
+ * @return uncompressed byte count
+ */
+ int getByteCount() {
+ return byteCount ;
+ }
+
+ /**
+ * Retrieve the the number of vertices created for this stream, excluding
+ * mesh buffer references.
+ * @return vertex count
+ */
+ int getVertexCount() {
+ return vertexCount ;
+ }
+
+ /**
+ * Retrieve the number of mesh buffer references created for this stream.
+ * @return mesh buffer reference count
+ */
+ int getMeshReferenceCount() {
+ return meshReferenceCount ;
+ }
+
+ /**
+ * Stream element that sets position quantization during quantize pass.
+ */
+ private class PositionQuant extends CompressionStreamElement {
+ int value ;
+
+ PositionQuant(int value) {
+ this.value = value ;
+ }
+
+ @Override
+ void quantize(CompressionStream s, HuffmanTable t) {
+ positionQuant = value ;
+ positionQuantChanged = true ;
+
+ // Adjust range of unit cube scaling to match quantization.
+ scale = (2.0 / positionRangeMaximum) *
+ (((double)((1 << (value-1)) - 1))/((double)(1 << (value-1)))) ;
+ }
+
+ @Override
+ public String toString() {
+ return "positionQuant: " + value ;
+ }
+ }
+
+ /**
+ * Stream element that sets normal quantization during quantize pass.
+ */
+ private class NormalQuant extends CompressionStreamElement {
+ int value ;
+
+ NormalQuant(int value) {
+ this.value = value ;
+ }
+
+ @Override
+ void quantize(CompressionStream s, HuffmanTable t) {
+ normalQuant = value ;
+ normalQuantChanged = true ;
+ }
+
+ @Override
+ public String toString() {
+ return "normalQuant: " + value ;
+ }
+ }
+
+ /**
+ * Stream element that sets color quantization during quantize pass.
+ */
+ private class ColorQuant extends CompressionStreamElement {
+ int value ;
+
+ ColorQuant(int value) {
+ this.value = value ;
+ }
+
+ @Override
+ void quantize(CompressionStream s, HuffmanTable t) {
+ colorQuant = value ;
+ colorQuantChanged = true ;
+ }
+
+ @Override
+ public String toString() {
+ return "colorQuant: " + value ;
+ }
+ }
+
+ /**
+ * Stream element that references the mesh buffer.
+ */
+ private class MeshReference extends CompressionStreamElement {
+ int stripFlag, meshIndex ;
+
+ MeshReference(int stripFlag, int meshIndex) {
+ this.stripFlag = stripFlag ;
+ this.meshIndex = meshIndex ;
+ meshReferenceCount++ ;
+ }
+
+ @Override
+ void quantize(CompressionStream s, HuffmanTable t) {
+ // Retrieve the vertex from the mesh buffer mirror and set up the
+ // data needed for the next stream element to compute its deltas.
+ CompressionStreamVertex v = meshBuffer.getVertex(meshIndex) ;
+ lastPosition[0] = v.xAbsolute ;
+ lastPosition[1] = v.yAbsolute ;
+ lastPosition[2] = v.zAbsolute ;
+
+ // Set up last color data if it exists and previous elements
+ // don't override it.
+ if (v.color != null && !lastElementColor &&
+ !(lastElementNormal && lastLastElementColor)) {
+ lastColor[0] = v.color.rAbsolute ;
+ lastColor[1] = v.color.gAbsolute ;
+ lastColor[2] = v.color.bAbsolute ;
+ lastColor[3] = v.color.aAbsolute ;
+ }
+
+ // Set up last normal data if it exists and previous element
+ // doesn't override it.
+ if (v.normal != null && !lastElementNormal &&
+ !(lastElementColor && lastLastElementNormal)) {
+ lastSextant = v.normal.sextant ;
+ lastOctant = v.normal.octant ;
+ lastU = v.normal.uAbsolute ;
+ lastV = v.normal.vAbsolute ;
+ lastSpecialNormal = v.normal.specialNormal ;
+ }
+ }
+
+ @Override
+ void outputCommand(HuffmanTable t, CommandStream outputBuffer) {
+ int command = CommandStream.MESH_B_R ;
+ long data = stripFlag & 0x1 ;
+
+ command |= (((meshIndex & 0xf) << 1) | (stripFlag >> 1)) ;
+ outputBuffer.addCommand(command, 8, data, 1) ;
+ }
+
+ @Override
+ public String toString() {
+ return
+ "meshReference: stripFlag " + stripFlag +
+ " meshIndex " + meshIndex ;
+ }
+ }
+
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, int stripFlag) {
+ stream.add(new CompressionStreamVertex(this, pos,
+ (Vector3f)null, (Color3f)null,
+ stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, Vector3f norm, int stripFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, (Color3f)null, stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, Color3f color, int stripFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, Color4f color, int stripFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, Vector3f norm, Color3f color,
+ int stripFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, Vector3f norm, Color4f color,
+ int stripFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, (Vector3f)null, (Color3f)null, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Vector3f norm,
+ int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, (Color3f)null, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Color3f color,
+ int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Color4f color,
+ int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Vector3f norm, Color3f color,
+ int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, color, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Vector3f norm, Color4f color,
+ int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, color, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param color color data, either Color3f or Color4f, determined by
+ * current vertex format
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Vector3f norm,
+ Object color, int stripFlag, int meshFlag) {
+
+ if (vertexColor3)
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, (Color3f)color, stripFlag, meshFlag)) ;
+ else
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, (Color4f)color, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Add a mesh buffer reference to this stream.
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshIndex index of vertex to retrieve from the mesh buffer
+ */
+ void addMeshReference(int stripFlag, int meshIndex) {
+ stream.add(new MeshReference(stripFlag, meshIndex)) ;
+ }
+
+ /**
+ * Copy the given color to the end of this stream and use it as a global
+ * state change that applies to all subsequent vertices.
+ */
+ void addColor(Color3f c3f) {
+ stream.add(new CompressionStreamColor(this, c3f)) ;
+ }
+
+ /**
+ * Copy the given color to the end of this stream and use it as a global
+ * state change that applies to all subsequent vertices.
+ */
+ void addColor(Color4f c4f) {
+ stream.add(new CompressionStreamColor(this, c4f)) ;
+ }
+
+ /**
+ * Copy the given normal to the end of this stream and use it as a global
+ * state change that applies to all subsequent vertices.
+ */
+ void addNormal(Vector3f n) {
+ stream.add(new CompressionStreamNormal(this, n)) ;
+ }
+
+ /**
+ * Add a new position quantization value to the end of this stream that
+ * will apply to all subsequent vertex positions.
+ *
+ * @param value number of bits to quantize each position's X, Y,
+ * and Z components, ranging from 1 to 16 with a default of 16
+ */
+ void addPositionQuantization(int value) {
+ stream.add(new PositionQuant(value)) ;
+ }
+
+ /**
+ * Add a new color quantization value to the end of this stream that will
+ * apply to all subsequent colors.
+ *
+ * @param value number of bits to quantize each color's R, G, B, and
+ * alpha components, ranging from 2 to 16 with a default of 9
+ */
+ void addColorQuantization(int value) {
+ stream.add(new ColorQuant(value)) ;
+ }
+
+ /**
+ * Add a new normal quantization value to the end of this stream that will
+ * apply to all subsequent normals. This value specifies the number of
+ * bits for each normal's U and V components.
+ *
+ * @param value number of bits for quantizing U and V, ranging from 0 to
+ * 6 with a default of 6
+ */
+ void addNormalQuantization(int value) {
+ stream.add(new NormalQuant(value)) ;
+ }
+
+ /**
+ * Interface to access GeometryArray vertex components and add them to the
+ * compression stream.
+ *
+ * A processVertex() implementation retrieves vertex components using the
+ * appropriate access semantics of a particular GeometryArray, and adds
+ * them to the compression stream.
+ *
+ * The implementation always pushes vertices into the mesh buffer unless
+ * they match ones already there; if they do, it generates mesh buffer
+ * references instead. This reduces the number of vertices when
+ * non-stripped abutting facets are added to the stream.
+ *
+ * Note: Level II geometry compression semantics allow the mesh buffer
+ * normals to be substituted with the value of an immediately
+ * preceding SetNormal command, but this is unavailable in Level I.
+ *
+ * @param index vertex offset from the beginning of its data array
+ * @param stripFlag RESTART, REPLACE_MIDDLE, or REPLACE_OLDEST
+ */
+ private interface GeometryAccessor {
+ void processVertex(int index, int stripFlag) ;
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for geometry
+ * arrays accessed with by-copy semantics.
+ */
+ private class ByCopyGeometry implements GeometryAccessor {
+ Point3f[] positions = null ;
+ Vector3f[] normals = null ;
+ Color3f[] colors3 = null ;
+ Color4f[] colors4 = null ;
+
+ ByCopyGeometry(GeometryArray ga) {
+ this(ga, ga.getInitialVertexIndex(), ga.getValidVertexCount()) ;
+ }
+
+ ByCopyGeometry(GeometryArray ga,
+ int firstVertex, int validVertexCount) {
+ int i ;
+ positions = new Point3f[validVertexCount] ;
+ for (i = 0 ; i < validVertexCount ; i++)
+ positions[i] = new Point3f() ;
+
+ ga.getCoordinates(firstVertex, positions) ;
+
+ if (vertexNormals) {
+ normals = new Vector3f[validVertexCount] ;
+ for (i = 0 ; i < validVertexCount ; i++)
+ normals[i] = new Vector3f() ;
+
+ ga.getNormals(firstVertex, normals) ;
+ }
+
+ if (vertexColor3) {
+ colors3 = new Color3f[validVertexCount] ;
+ for (i = 0 ; i < validVertexCount ; i++)
+ colors3[i] = new Color3f() ;
+
+ ga.getColors(firstVertex, colors3) ;
+ }
+ else if (vertexColor4) {
+ colors4 = new Color4f[validVertexCount] ;
+ for (i = 0 ; i < validVertexCount ; i++)
+ colors4[i] = new Color4f() ;
+
+ ga.getColors(firstVertex, colors4) ;
+ }
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ Point3f p = positions[v] ;
+ int r = meshBuffer.getMeshReference(p) ;
+
+ if ((r == meshBuffer.NOT_FOUND) ||
+ (vertexNormals && noMeshNormalSubstitution &&
+ (! normals[v].equals(meshBuffer.getNormal(r))))) {
+
+ Vector3f n = vertexNormals? normals[v] : null ;
+ Object c = vertexColor3? (Object)colors3[v] :
+ vertexColor4? (Object)colors4[v] : null ;
+
+ addVertex(p, n, c, stripFlag, MESH_PUSH) ;
+ meshBuffer.push(p, c, n) ;
+ }
+ else {
+ if (vertexNormals && !noMeshNormalSubstitution &&
+ (! normals[v].equals(meshBuffer.getNormal(r))))
+ addNormal(normals[v]) ;
+
+ if (vertexColor3 &&
+ (! colors3[v].equals(meshBuffer.getColor3(r))))
+ addColor(colors3[v]) ;
+
+ else if (vertexColor4 &&
+ (! colors4[v].equals(meshBuffer.getColor4(r))))
+ addColor(colors4[v]) ;
+
+ addMeshReference(stripFlag, r) ;
+ }
+ }
+ }
+
+ /**
+ * Class which holds index array references for a geometry array.
+ */
+ private static class IndexArrays {
+ int colorIndices[] = null ;
+ int normalIndices[] = null ;
+ int positionIndices[] = null ;
+ }
+
+ /**
+ * Retrieves index array references for the specified IndexedGeometryArray.
+ * Index arrays are copied starting from initialIndexIndex.
+ */
+ private void getIndexArrays(GeometryArray ga, IndexArrays ia) {
+ IndexedGeometryArray iga = (IndexedGeometryArray)ga ;
+
+ int initialIndexIndex = iga.getInitialIndexIndex() ;
+ int indexCount = iga.getValidIndexCount() ;
+ int vertexFormat = iga.getVertexFormat() ;
+
+ boolean useCoordIndexOnly = false ;
+ if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) {
+ if (debug) System.out.println("useCoordIndexOnly") ;
+ useCoordIndexOnly = true ;
+ }
+
+ ia.positionIndices = new int[indexCount] ;
+ iga.getCoordinateIndices(initialIndexIndex, ia.positionIndices) ;
+
+ if (vertexNormals) {
+ if (useCoordIndexOnly) {
+ ia.normalIndices = ia.positionIndices ;
+ }
+ else {
+ ia.normalIndices = new int[indexCount] ;
+ iga.getNormalIndices(initialIndexIndex, ia.normalIndices) ;
+ }
+ }
+ if (vertexColor3 || vertexColor4) {
+ if (useCoordIndexOnly) {
+ ia.colorIndices = ia.positionIndices ;
+ }
+ else {
+ ia.colorIndices = new int[indexCount] ;
+ iga.getColorIndices(initialIndexIndex, ia.colorIndices) ;
+ }
+ }
+ }
+
+ /**
+ * Class which holds indices for a specific vertex of an
+ * IndexedGeometryArray.
+ */
+ private static class VertexIndices {
+ int pi, ni, ci ;
+ }
+
+ /**
+ * Retrieves vertex indices for a specific vertex in an
+ * IndexedGeometryArray.
+ */
+ private void getVertexIndices(int v, IndexArrays ia, VertexIndices vi) {
+ vi.pi = ia.positionIndices[v] ;
+ if (vertexNormals)
+ vi.ni = ia.normalIndices[v] ;
+ if (vertexColors)
+ vi.ci = ia.colorIndices[v] ;
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for indexed
+ * geometry arrays accessed with by-copy semantics.
+ */
+ private class IndexedByCopyGeometry extends ByCopyGeometry {
+ IndexArrays ia = new IndexArrays() ;
+ VertexIndices vi = new VertexIndices() ;
+
+ IndexedByCopyGeometry(GeometryArray ga) {
+ super(ga, 0, ga.getVertexCount()) ;
+ getIndexArrays(ga, ia) ;
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ getVertexIndices(v, ia, vi) ;
+ int r = meshBuffer.getMeshReference(vi.pi) ;
+
+ if ((r == meshBuffer.NOT_FOUND) ||
+ (vertexNormals && noMeshNormalSubstitution &&
+ (vi.ni != meshBuffer.getNormalIndex(r)))) {
+
+ Point3f p = positions[vi.pi] ;
+ Vector3f n = vertexNormals? normals[vi.ni] : null ;
+ Object c = vertexColor3? (Object)colors3[vi.ci] :
+ vertexColor4? (Object)colors4[vi.ci] : null ;
+
+ addVertex(p, n, c, stripFlag, MESH_PUSH) ;
+ meshBuffer.push(vi.pi, vi.ci, vi.ni) ;
+ }
+ else {
+ if (vertexNormals && !noMeshNormalSubstitution &&
+ vi.ni != meshBuffer.getNormalIndex(r))
+ addNormal(normals[vi.ni]) ;
+
+ if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r))
+ addColor(colors3[vi.ci]) ;
+
+ else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r))
+ addColor(colors4[vi.ci]) ;
+
+ addMeshReference(stripFlag, r) ;
+ }
+ }
+ }
+
+ //
+ // NOTE: For now, copies are made of all GeometryArray vertex components
+ // even when by-reference access is available.
+ //
+ private static class VertexCopy {
+ Object c = null ;
+ Point3f p = null ;
+ Vector3f n = null ;
+ Color3f c3 = null ;
+ Color4f c4 = null ;
+ }
+
+ private void processVertexCopy(VertexCopy vc, int stripFlag) {
+ int r = meshBuffer.getMeshReference(vc.p) ;
+
+ if ((r == meshBuffer.NOT_FOUND) ||
+ (vertexNormals && noMeshNormalSubstitution &&
+ (! vc.n.equals(meshBuffer.getNormal(r))))) {
+
+ addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ;
+ meshBuffer.push(vc.p, vc.c, vc.n) ;
+ }
+ else {
+ if (vertexNormals && !noMeshNormalSubstitution &&
+ (! vc.n.equals(meshBuffer.getNormal(r))))
+ addNormal(vc.n) ;
+
+ if (vertexColor3 && (! vc.c3.equals(meshBuffer.getColor3(r))))
+ addColor(vc.c3) ;
+
+ else if (vertexColor4 && (! vc.c4.equals(meshBuffer.getColor4(r))))
+ addColor(vc.c4) ;
+
+ addMeshReference(stripFlag, r) ;
+ }
+ }
+
+ private void processIndexedVertexCopy(VertexCopy vc,
+ VertexIndices vi,
+ int stripFlag) {
+
+ int r = meshBuffer.getMeshReference(vi.pi) ;
+
+ if ((r == meshBuffer.NOT_FOUND) ||
+ (vertexNormals && noMeshNormalSubstitution &&
+ (vi.ni != meshBuffer.getNormalIndex(r)))) {
+
+ addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ;
+ meshBuffer.push(vi.pi, vi.ci, vi.ni) ;
+ }
+ else {
+ if (vertexNormals && !noMeshNormalSubstitution &&
+ vi.ni != meshBuffer.getNormalIndex(r))
+ addNormal(vc.n) ;
+
+ if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r))
+ addColor(vc.c3) ;
+
+ else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r))
+ addColor(vc.c4) ;
+
+ addMeshReference(stripFlag, r) ;
+ }
+ }
+
+ /**
+ * This abstract class implements the GeometryAccessor interface for
+ * concrete subclasses which handle float and NIO interleaved geometry
+ * arrays.
+ */
+ private abstract class InterleavedGeometry implements GeometryAccessor {
+ VertexCopy vc = new VertexCopy() ;
+
+ int vstride = 0 ;
+ int coffset = 0 ;
+ int noffset = 0 ;
+ int poffset = 0 ;
+ int tstride = 0 ;
+ int tcount = 0 ;
+
+ InterleavedGeometry(GeometryArray ga) {
+ if (vertexTextures) {
+ if (vertexTexture2) tstride = 2 ;
+ else if (vertexTexture3) tstride = 3 ;
+ else if (vertexTexture4) tstride = 4 ;
+
+ tcount = ga.getTexCoordSetCount() ;
+ vstride += tcount * tstride ;
+ }
+
+ if (vertexColors) {
+ coffset = vstride ;
+ if (vertexColor3) vstride += 3 ;
+ else vstride += 4 ;
+ }
+
+ if (vertexNormals) {
+ noffset = vstride ;
+ vstride += 3 ;
+ }
+
+ poffset = vstride ;
+ vstride += 3 ;
+ }
+
+ abstract void copyVertex(int pi, int ni, int ci, VertexCopy vc) ;
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ copyVertex(v, v, v, vc) ;
+ processVertexCopy(vc, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for float
+ * interleaved geometry arrays.
+ */
+ private class InterleavedGeometryFloat extends InterleavedGeometry {
+ float[] vdata = null ;
+
+ InterleavedGeometryFloat(GeometryArray ga) {
+ super(ga) ;
+ vdata = ga.getInterleavedVertices() ;
+ }
+
+ @Override
+ void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
+ int voffset ;
+ voffset = pi * vstride ;
+ vc.p = new Point3f(vdata[voffset + poffset + 0],
+ vdata[voffset + poffset + 1],
+ vdata[voffset + poffset + 2]) ;
+
+ if (vertexNormals) {
+ voffset = ni * vstride ;
+ vc.n = new Vector3f(vdata[voffset + noffset + 0],
+ vdata[voffset + noffset + 1],
+ vdata[voffset + noffset + 2]) ;
+ }
+ if (vertexColor3) {
+ voffset = ci * vstride ;
+ vc.c3 = new Color3f(vdata[voffset + coffset + 0],
+ vdata[voffset + coffset + 1],
+ vdata[voffset + coffset + 2]) ;
+ vc.c = vc.c3 ;
+ }
+ else if (vertexColor4) {
+ voffset = ci * vstride ;
+ vc.c4 = new Color4f(vdata[voffset + coffset + 0],
+ vdata[voffset + coffset + 1],
+ vdata[voffset + coffset + 2],
+ vdata[voffset + coffset + 3]) ;
+ vc.c = vc.c4 ;
+ }
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for indexed
+ * interleaved geometry arrays.
+ */
+ private class IndexedInterleavedGeometryFloat
+ extends InterleavedGeometryFloat {
+
+ IndexArrays ia = new IndexArrays() ;
+ VertexIndices vi = new VertexIndices() ;
+
+ IndexedInterleavedGeometryFloat(GeometryArray ga) {
+ super(ga) ;
+ getIndexArrays(ga, ia) ;
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ getVertexIndices(v, ia, vi) ;
+ copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
+ processIndexedVertexCopy(vc, vi, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for
+ * interleaved NIO geometry arrays.
+ */
+ private class InterleavedGeometryNIO extends InterleavedGeometry {
+ FloatBuffer fbw = null ;
+
+ InterleavedGeometryNIO(GeometryArray ga) {
+ super(ga) ;
+ J3DBuffer buffer = ga.getInterleavedVertexBuffer() ;
+ if (BufferWrapper.getBufferType(buffer) ==
+ BufferWrapper.TYPE_FLOAT) {
+ fbw = (FloatBuffer)buffer.getBuffer();
+ }
+ else {
+ throw new IllegalArgumentException
+ ("\ninterleaved vertex buffer must be FloatBuffer") ;
+ }
+ }
+
+ @Override
+ void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
+ int voffset ;
+ voffset = pi * vstride ;
+ vc.p = new Point3f(fbw.get(voffset + poffset + 0),
+ fbw.get(voffset + poffset + 1),
+ fbw.get(voffset + poffset + 2)) ;
+
+ if (vertexNormals) {
+ voffset = ni * vstride ;
+ vc.n = new Vector3f(fbw.get(voffset + noffset + 0),
+ fbw.get(voffset + noffset + 1),
+ fbw.get(voffset + noffset + 2)) ;
+ }
+ if (vertexColor3) {
+ voffset = ci * vstride ;
+ vc.c3 = new Color3f(fbw.get(voffset + coffset + 0),
+ fbw.get(voffset + coffset + 1),
+ fbw.get(voffset + coffset + 2)) ;
+ vc.c = vc.c3 ;
+ }
+ else if (vertexColor4) {
+ voffset = ci * vstride ;
+ vc.c4 = new Color4f(fbw.get(voffset + coffset + 0),
+ fbw.get(voffset + coffset + 1),
+ fbw.get(voffset + coffset + 2),
+ fbw.get(voffset + coffset + 3)) ;
+ vc.c = vc.c4 ;
+ }
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for indexed
+ * interleaved NIO geometry arrays.
+ */
+ private class IndexedInterleavedGeometryNIO extends InterleavedGeometryNIO {
+ IndexArrays ia = new IndexArrays() ;
+ VertexIndices vi = new VertexIndices() ;
+
+ IndexedInterleavedGeometryNIO(GeometryArray ga) {
+ super(ga) ;
+ getIndexArrays(ga, ia) ;
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ getVertexIndices(v, ia, vi) ;
+ copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
+ processIndexedVertexCopy(vc, vi, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for
+ * non-interleaved geometry arrays accessed with by-reference semantics.
+ */
+ private class ByRefGeometry implements GeometryAccessor {
+ VertexCopy vc = new VertexCopy() ;
+
+ byte[] colorsB = null ;
+ float[] colorsF = null ;
+ float[] normals = null ;
+ float[] positionsF = null ;
+ double[] positionsD = null ;
+
+ int initialPositionIndex = 0 ;
+ int initialNormalIndex = 0 ;
+ int initialColorIndex = 0 ;
+
+ ByRefGeometry(GeometryArray ga) {
+ positionsF = ga.getCoordRefFloat() ;
+ if (debug && positionsF != null)
+ System.out.println("float positions") ;
+
+ positionsD = ga.getCoordRefDouble() ;
+ if (debug && positionsD != null)
+ System.out.println("double positions") ;
+
+ if (positionsF == null && positionsD == null)
+ throw new UnsupportedOperationException
+ ("\nby-reference access to Point3{d,f} arrays") ;
+
+ initialPositionIndex = ga.getInitialCoordIndex() ;
+
+ if (vertexColors) {
+ colorsB = ga.getColorRefByte() ;
+ if (debug && colorsB != null)
+ System.out.println("byte colors") ;
+
+ colorsF = ga.getColorRefFloat() ;
+ if (debug && colorsF != null)
+ System.out.println("float colors") ;
+
+ if (colorsB == null && colorsF == null)
+ throw new UnsupportedOperationException
+ ("\nby-reference access to Color{3b,3f,4b,4f} arrays") ;
+
+ initialColorIndex = ga.getInitialColorIndex() ;
+ }
+
+ if (vertexNormals) {
+ normals = ga.getNormalRefFloat() ;
+ if (debug && normals != null)
+ System.out.println("float normals") ;
+
+ if (normals == null)
+ throw new UnsupportedOperationException
+ ("\nby-reference access to Normal3f array") ;
+
+ initialNormalIndex = ga.getInitialNormalIndex() ;
+ }
+ }
+
+ void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
+ pi *= 3 ;
+ if (positionsF != null) {
+ vc.p = new Point3f(positionsF[pi + 0],
+ positionsF[pi + 1],
+ positionsF[pi + 2]) ;
+ }
+ else {
+ vc.p = new Point3f((float)positionsD[pi + 0],
+ (float)positionsD[pi + 1],
+ (float)positionsD[pi + 2]) ;
+ }
+
+ ni *= 3 ;
+ if (vertexNormals) {
+ vc.n = new Vector3f(normals[ni + 0],
+ normals[ni + 1],
+ normals[ni + 2]) ;
+ }
+
+ if (vertexColor3) {
+ ci *= 3 ;
+ if (colorsB != null) {
+ vc.c3 = new Color3f
+ ((colorsB[ci + 0] & 0xff) * ByteToFloatScale,
+ (colorsB[ci + 1] & 0xff) * ByteToFloatScale,
+ (colorsB[ci + 2] & 0xff) * ByteToFloatScale) ;
+ }
+ else {
+ vc.c3 = new Color3f(colorsF[ci + 0],
+ colorsF[ci + 1],
+ colorsF[ci + 2]) ;
+ }
+ vc.c = vc.c3 ;
+ }
+ else if (vertexColor4) {
+ ci *= 4 ;
+ if (colorsB != null) {
+ vc.c4 = new Color4f
+ ((colorsB[ci + 0] & 0xff) * ByteToFloatScale,
+ (colorsB[ci + 1] & 0xff) * ByteToFloatScale,
+ (colorsB[ci + 2] & 0xff) * ByteToFloatScale,
+ (colorsB[ci + 3] & 0xff) * ByteToFloatScale) ;
+ }
+ else {
+ vc.c4 = new Color4f(colorsF[ci + 0],
+ colorsF[ci + 1],
+ colorsF[ci + 2],
+ colorsF[ci + 3]) ;
+ }
+ vc.c = vc.c4 ;
+ }
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ copyVertex(v + initialPositionIndex,
+ v + initialNormalIndex,
+ v + initialColorIndex, vc) ;
+
+ processVertexCopy(vc, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for indexed
+ * non-interleaved geometry arrays accessed with by-reference semantics.
+ */
+ private class IndexedByRefGeometry extends ByRefGeometry {
+ IndexArrays ia = new IndexArrays() ;
+ VertexIndices vi = new VertexIndices() ;
+
+ IndexedByRefGeometry(GeometryArray ga) {
+ super(ga) ;
+ getIndexArrays(ga, ia) ;
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ getVertexIndices(v, ia, vi) ;
+ copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
+ processIndexedVertexCopy(vc, vi, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for
+ * non-interleaved geometry arrays accessed with NIO.
+ */
+ private class ByRefGeometryNIO implements GeometryAccessor {
+ VertexCopy vc = new VertexCopy() ;
+
+ ByteBuffer colorsB = null ;
+ FloatBuffer colorsF = null ;
+ FloatBuffer normals = null ;
+ FloatBuffer positionsF = null ;
+ DoubleBuffer positionsD = null ;
+
+ int initialPositionIndex = 0 ;
+ int initialNormalIndex = 0 ;
+ int initialColorIndex = 0 ;
+
+ ByRefGeometryNIO(GeometryArray ga) {
+ J3DBuffer buffer ;
+ buffer = ga.getCoordRefBuffer() ;
+ initialPositionIndex = ga.getInitialCoordIndex() ;
+
+ switch (BufferWrapper.getBufferType(buffer)) {
+ case BufferWrapper.TYPE_FLOAT:
+ positionsF = (FloatBuffer)buffer.getBuffer();
+ if (debug) System.out.println("float positions buffer") ;
+ break ;
+ case BufferWrapper.TYPE_DOUBLE:
+ positionsD = (DoubleBuffer)buffer.getBuffer();
+ if (debug) System.out.println("double positions buffer") ;
+ break ;
+ default:
+ throw new IllegalArgumentException
+ ("\nposition buffer must be FloatBuffer or DoubleBuffer") ;
+ }
+
+ if (vertexColors) {
+ buffer = ga.getColorRefBuffer() ;
+ initialColorIndex = ga.getInitialColorIndex() ;
+
+ switch (BufferWrapper.getBufferType(buffer)) {
+ case BufferWrapper.TYPE_BYTE:
+ colorsB = (ByteBuffer)buffer.getBuffer();
+ if (debug) System.out.println("byte colors buffer") ;
+ break ;
+ case BufferWrapper.TYPE_FLOAT:
+ colorsF = (FloatBuffer)buffer.getBuffer();
+ if (debug) System.out.println("float colors buffer") ;
+ break ;
+ default:
+ throw new IllegalArgumentException
+ ("\ncolor buffer must be ByteBuffer or FloatBuffer") ;
+ }
+ }
+
+ if (vertexNormals) {
+ buffer = ga.getNormalRefBuffer() ;
+ initialNormalIndex = ga.getInitialNormalIndex() ;
+
+ switch (BufferWrapper.getBufferType(buffer)) {
+ case BufferWrapper.TYPE_FLOAT:
+ normals = (FloatBuffer)buffer.getBuffer();
+ if (debug) System.out.println("float normals buffer") ;
+ break ;
+ default:
+ throw new IllegalArgumentException
+ ("\nnormal buffer must be FloatBuffer") ;
+ }
+ }
+ }
+
+ void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
+ pi *= 3 ;
+ if (positionsF != null) {
+ vc.p = new Point3f(positionsF.get(pi + 0),
+ positionsF.get(pi + 1),
+ positionsF.get(pi + 2)) ;
+ }
+ else {
+ vc.p = new Point3f((float)positionsD.get(pi + 0),
+ (float)positionsD.get(pi + 1),
+ (float)positionsD.get(pi + 2)) ;
+ }
+
+ ni *= 3 ;
+ if (vertexNormals) {
+ vc.n = new Vector3f(normals.get(ni + 0),
+ normals.get(ni + 1),
+ normals.get(ni + 2)) ;
+ }
+
+ if (vertexColor3) {
+ ci *= 3 ;
+ if (colorsB != null) {
+ vc.c3 = new Color3f
+ ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale,
+ (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale,
+ (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale) ;
+ }
+ else {
+ vc.c3 = new Color3f(colorsF.get(ci + 0),
+ colorsF.get(ci + 1),
+ colorsF.get(ci + 2)) ;
+ }
+ vc.c = vc.c3 ;
+ }
+ else if (vertexColor4) {
+ ci *= 4 ;
+ if (colorsB != null) {
+ vc.c4 = new Color4f
+ ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale,
+ (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale,
+ (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale,
+ (colorsB.get(ci + 3) & 0xff) * ByteToFloatScale) ;
+ }
+ else {
+ vc.c4 = new Color4f(colorsF.get(ci + 0),
+ colorsF.get(ci + 1),
+ colorsF.get(ci + 2),
+ colorsF.get(ci + 3)) ;
+ }
+ vc.c = vc.c4 ;
+ }
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ copyVertex(v + initialPositionIndex,
+ v + initialNormalIndex,
+ v + initialColorIndex, vc) ;
+
+ processVertexCopy(vc, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for
+ * non-interleaved indexed geometry arrays accessed with NIO.
+ */
+ private class IndexedByRefGeometryNIO extends ByRefGeometryNIO {
+ IndexArrays ia = new IndexArrays() ;
+ VertexIndices vi = new VertexIndices() ;
+
+ IndexedByRefGeometryNIO(GeometryArray ga) {
+ super(ga) ;
+ getIndexArrays(ga, ia) ;
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ getVertexIndices(v, ia, vi) ;
+ copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
+ processIndexedVertexCopy(vc, vi, stripFlag) ;
+ }
+ }
+
+ /**
+ * Convert a GeometryArray to compression stream elements and add them to
+ * this stream.
+ *
+ * @param ga GeometryArray to convert
+ * @exception IllegalArgumentException if GeometryArray has a
+ * dimensionality or vertex format inconsistent with the CompressionStream
+ */
+ void addGeometryArray(GeometryArray ga) {
+ int firstVertex = 0 ;
+ int validVertexCount = 0 ;
+ int vertexFormat = ga.getVertexFormat() ;
+ GeometryAccessor geometryAccessor = null ;
+
+ if (streamType != getStreamType(ga))
+ throw new IllegalArgumentException
+ ("GeometryArray has inconsistent dimensionality") ;
+
+ if (vertexComponents != getVertexComponents(vertexFormat))
+ throw new IllegalArgumentException
+ ("GeometryArray has inconsistent vertex components") ;
+
+ // Set up for vertex data access semantics.
+ boolean NIO = (vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 ;
+ boolean byRef = (vertexFormat & GeometryArray.BY_REFERENCE) != 0 ;
+ boolean interleaved = (vertexFormat & GeometryArray.INTERLEAVED) != 0 ;
+ boolean indexedGeometry = ga instanceof IndexedGeometryArray ;
+
+ if (indexedGeometry) {
+ if (debug) System.out.println("indexed") ;
+ // Index arrays will be copied such that valid indices start at
+ // offset 0 in the copied arrays.
+ firstVertex = 0 ;
+ validVertexCount = ((IndexedGeometryArray)ga).getValidIndexCount() ;
+ }
+
+ if (!byRef) {
+ if (debug) System.out.println("by-copy") ;
+ if (indexedGeometry) {
+ geometryAccessor = new IndexedByCopyGeometry(ga) ;
+ }
+ else {
+ firstVertex = 0 ;
+ validVertexCount = ga.getValidVertexCount() ;
+ geometryAccessor = new ByCopyGeometry(ga) ;
+ }
+ }
+ else if (interleaved && NIO) {
+ if (debug) System.out.println("interleaved NIO") ;
+ if (indexedGeometry) {
+ geometryAccessor = new IndexedInterleavedGeometryNIO(ga) ;
+ }
+ else {
+ firstVertex = ga.getInitialVertexIndex() ;
+ validVertexCount = ga.getValidVertexCount() ;
+ geometryAccessor = new InterleavedGeometryNIO(ga) ;
+ }
+ }
+ else if (interleaved && !NIO) {
+ if (debug) System.out.println("interleaved") ;
+ if (indexedGeometry) {
+ geometryAccessor = new IndexedInterleavedGeometryFloat(ga) ;
+ }
+ else {
+ firstVertex = ga.getInitialVertexIndex() ;
+ validVertexCount = ga.getValidVertexCount() ;
+ geometryAccessor = new InterleavedGeometryFloat(ga) ;
+ }
+ }
+ else if (!interleaved && NIO) {
+ if (debug) System.out.println("non-interleaved NIO") ;
+ if (indexedGeometry) {
+ geometryAccessor = new IndexedByRefGeometryNIO(ga) ;
+ }
+ else {
+ firstVertex = 0 ;
+ validVertexCount = ga.getValidVertexCount() ;
+ geometryAccessor = new ByRefGeometryNIO(ga) ;
+ }
+ }
+ else if (!interleaved && !NIO) {
+ if (debug) System.out.println("non-interleaved by-ref") ;
+ if (indexedGeometry) {
+ geometryAccessor = new IndexedByRefGeometry(ga) ;
+ }
+ else {
+ firstVertex = 0 ;
+ validVertexCount = ga.getValidVertexCount() ;
+ geometryAccessor = new ByRefGeometry(ga) ;
+ }
+ }
+
+ // Set up for topology.
+ int stripCount = 0 ;
+ int stripCounts[] = null ;
+ int constantStripLength = 0 ;
+ int replaceCode = RESTART ;
+ boolean strips = false ;
+ boolean implicitStrips = false ;
+
+ if (ga instanceof TriangleStripArray ||
+ ga instanceof IndexedTriangleStripArray ||
+ ga instanceof LineStripArray ||
+ ga instanceof IndexedLineStripArray) {
+
+ strips = true ;
+ replaceCode = REPLACE_OLDEST ;
+ if (debug) System.out.println("strips") ;
+ }
+ else if (ga instanceof TriangleFanArray ||
+ ga instanceof IndexedTriangleFanArray) {
+
+ strips = true ;
+ replaceCode = REPLACE_MIDDLE ;
+ if (debug) System.out.println("fans") ;
+ }
+ else if (ga instanceof QuadArray ||
+ ga instanceof IndexedQuadArray) {
+
+ // Handled as fan arrays with 4 vertices per fan.
+ implicitStrips = true ;
+ constantStripLength = 4 ;
+ replaceCode = REPLACE_MIDDLE ;
+ if (debug) System.out.println("quads") ;
+ }
+
+ // Get strip counts.
+ if (strips) {
+ if (indexedGeometry) {
+ IndexedGeometryStripArray igsa ;
+ igsa = (IndexedGeometryStripArray)ga ;
+
+ stripCount = igsa.getNumStrips() ;
+ stripCounts = new int[stripCount] ;
+ igsa.getStripIndexCounts(stripCounts) ;
+
+ } else {
+ GeometryStripArray gsa ;
+ gsa = (GeometryStripArray)ga ;
+
+ stripCount = gsa.getNumStrips() ;
+ stripCounts = new int[stripCount] ;
+ gsa.getStripVertexCounts(stripCounts) ;
+ }
+ }
+
+ // Build the compression stream for this shape's geometry.
+ int v = firstVertex ;
+ if (strips) {
+ for (int i = 0 ; i < stripCount ; i++) {
+ geometryAccessor.processVertex(v++, RESTART) ;
+ for (int j = 1 ; j < stripCounts[i] ; j++) {
+ geometryAccessor.processVertex(v++, replaceCode) ;
+ }
+ }
+ }
+ else if (implicitStrips) {
+ while (v < firstVertex + validVertexCount) {
+ geometryAccessor.processVertex(v++, RESTART) ;
+ for (int j = 1 ; j < constantStripLength ; j++) {
+ geometryAccessor.processVertex(v++, replaceCode) ;
+ }
+ }
+ }
+ else {
+ while (v < firstVertex + validVertexCount) {
+ geometryAccessor.processVertex(v++, RESTART) ;
+ }
+ }
+ }
+
+ /**
+ * Print the stream to standard output.
+ */
+ void print() {
+ System.out.println("\nstream has " + stream.size() + " entries") ;
+ System.out.println("uncompressed size " + byteCount + " bytes") ;
+ System.out.println("upper position bound: " + mcBounds[1].toString()) ;
+ System.out.println("lower position bound: " + mcBounds[0].toString()) ;
+ System.out.println("X, Y, Z centers (" +
+ ((float)center[0]) + " " +
+ ((float)center[1]) + " " +
+ ((float)center[2]) + ")\n" +
+ "scale " + ((float)scale) + "\n") ;
+
+ Iterator i = stream.iterator() ;
+ while (i.hasNext()) {
+ System.out.println(i.next().toString() + "\n") ;
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ // //
+ // The following constructors and methods are currently the only public //
+ // members of this class. All other members are subject to revision. //
+ // //
+ ////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates a CompressionStream from an array of Shape3D scene graph
+ * objects. These Shape3D objects may only consist of a GeometryArray
+ * component and an optional Appearance component. The resulting stream
+ * may be used as input to the GeometryCompressor methods.
+ *
+ * Each Shape3D in the array must be of the same dimensionality (point,
+ * line, or surface) and have the same vertex format as the others.
+ * Texture coordinates are ignored.
+ *
+ * If a color is specified in the material attributes for a Shape3D then
+ * that color is added to the CompressionStream as the current global
+ * color. Subsequent colors as well as any colors bundled with vertices
+ * will override it. Only the material diffuse colors are used; all other
+ * appearance attributes are ignored.
+ *
+ * @param positionQuant
+ * number of bits to quantize each position's X, Y,
+ * and Z components, ranging from 1 to 16
+ *
+ * @param colorQuant
+ * number of bits to quantize each color's R, G, B, and
+ * alpha components, ranging from 2 to 16
+ *
+ * @param normalQuant
+ * number of bits for quantizing each normal's U and V components, ranging
+ * from 0 to 6
+ *
+ * @param shapes
+ * an array of Shape3D scene graph objects containing
+ * GeometryArray objects, all with the same vertex format and
+ * dimensionality
+ *
+ * @exception IllegalArgumentException if any Shape3D has an inconsistent
+ * dimensionality or vertex format, or if any Shape3D contains a geometry
+ * component that is not a GeometryArray
+ *
+ * @see Shape3D
+ * @see GeometryArray
+ * @see GeometryCompressor
+ */
+ public CompressionStream(int positionQuant, int colorQuant,
+ int normalQuant, Shape3D shapes[]) {
+ this() ;
+ if (debug) System.out.println("CompressionStream(Shape3D[]):") ;
+
+ if (shapes == null)
+ throw new IllegalArgumentException("null Shape3D array") ;
+
+ if (shapes.length == 0)
+ throw new IllegalArgumentException("zero-length Shape3D array") ;
+
+ if (shapes[0] == null)
+ throw new IllegalArgumentException("Shape3D at index 0 is null") ;
+
+ long startTime = 0 ;
+ if (benchmark) startTime = System.currentTimeMillis() ;
+
+ Geometry g = shapes[0].getGeometry() ;
+ if (! (g instanceof GeometryArray))
+ throw new IllegalArgumentException
+ ("Shape3D at index 0 is not a GeometryArray") ;
+
+ GeometryArray ga = (GeometryArray)g ;
+ this.streamType = getStreamType(ga) ;
+ this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ;
+
+ // Add global quantization parameters to the start of the stream.
+ addPositionQuantization(positionQuant) ;
+ addColorQuantization(colorQuant) ;
+ addNormalQuantization(normalQuant) ;
+
+ // Loop through all shapes.
+ for (int s = 0 ; s < shapes.length ; s++) {
+ if (debug) System.out.println("\nShape3D " + s + ":") ;
+
+ g = shapes[s].getGeometry() ;
+ if (! (g instanceof GeometryArray))
+ throw new IllegalArgumentException
+ ("Shape3D at index " + s + " is not a GeometryArray") ;
+
+ // Check for material color and add it to the stream if it exists.
+ Appearance a = shapes[s].getAppearance() ;
+ if (a != null) {
+ Material m = a.getMaterial() ;
+ if (m != null) {
+ m.getDiffuseColor(c3f) ;
+ if (vertexColor4) {
+ c4f.set(c3f.x, c3f.y, c3f.z, 1.0f) ;
+ addColor(c4f) ;
+ } else
+ addColor(c3f) ;
+ }
+ }
+
+ // Add the geometry array to the stream.
+ addGeometryArray((GeometryArray)g) ;
+ }
+
+ if (benchmark) {
+ long t = System.currentTimeMillis() - startTime ;
+ System.out.println
+ ("\nCompressionStream:\n" + shapes.length + " shapes in " +
+ (t / 1000f) + " sec") ;
+ }
+ }
+
+ /**
+ * Creates a CompressionStream from an array of Shape3D scene graph
+ * objects. These Shape3D objects may only consist of a GeometryArray
+ * component and an optional Appearance component. The resulting stream
+ * may be used as input to the GeometryCompressor methods.
+ *
+ * Each Shape3D in the array must be of the same dimensionality (point,
+ * line, or surface) and have the same vertex format as the others.
+ * Texture coordinates are ignored.
+ *
+ * If a color is specified in the material attributes for a Shape3D then
+ * that color is added to the CompressionStream as the current global
+ * color. Subsequent colors as well as any colors bundled with vertices
+ * will override it. Only the material diffuse colors are used; all other
+ * appearance attributes are ignored.
+ *
+ * Defaults of 16, 9, and 6 bits are used as the quantization values for
+ * positions, colors, and normals respectively. These are the maximum
+ * resolution values defined for positions and normals; the default of 9
+ * for color is the equivalent of the 8 bits of RGBA component resolution
+ * commonly available in graphics frame buffers.
+ *
+ * @param shapes
+ * an array of Shape3D scene graph objects containing
+ * GeometryArray objects, all with the same vertex format and
+ * dimensionality.
+ *
+ * @exception IllegalArgumentException if any Shape3D has an inconsistent
+ * dimensionality or vertex format, or if any Shape3D contains a geometry
+ * component that is not a GeometryArray
+ *
+ * @see Shape3D
+ * @see GeometryArray
+ * @see GeometryCompressor
+ */
+ public CompressionStream(Shape3D shapes[]) {
+ this(16, 9, 6, shapes) ;
+ }
+
+ /**
+ * Creates a CompressionStream from an array of GeometryInfo objects. The
+ * resulting stream may be used as input to the GeometryCompressor
+ * methods.
+ *
+ * Each GeometryInfo in the array must be of the same dimensionality
+ * (point, line, or surface) and have the same vertex format as the
+ * others. Texture coordinates are ignored.
+ *
+ * @param positionQuant
+ * number of bits to quantize each position's X, Y,
+ * and Z components, ranging from 1 to 16
+ *
+ * @param colorQuant
+ * number of bits to quantize each color's R, G, B, and
+ * alpha components, ranging from 2 to 16
+ *
+ * @param normalQuant
+ * number of bits for quantizing each normal's U and V components, ranging
+ * from 0 to 6
+ *
+ * @param geometry
+ * an array of GeometryInfo objects, all with the same
+ * vertex format and dimensionality
+ *
+ * @exception IllegalArgumentException if any GeometryInfo object has an
+ * inconsistent dimensionality or vertex format
+ *
+ * @see GeometryInfo
+ * @see GeometryCompressor
+ */
+ public CompressionStream(int positionQuant, int colorQuant,
+ int normalQuant, GeometryInfo geometry[]) {
+ this() ;
+ if (debug) System.out.println("CompressionStream(GeometryInfo[])") ;
+
+ if (geometry == null)
+ throw new IllegalArgumentException("null GeometryInfo array") ;
+
+ if (geometry.length == 0)
+ throw new IllegalArgumentException
+ ("zero-length GeometryInfo array") ;
+
+ if (geometry[0] == null)
+ throw new IllegalArgumentException
+ ("GeometryInfo at index 0 is null") ;
+
+ long startTime = 0 ;
+ if (benchmark) startTime = System.currentTimeMillis() ;
+
+ GeometryArray ga = geometry[0].getGeometryArray() ;
+ this.streamType = getStreamType(ga) ;
+ this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ;
+
+ // Add global quantization parameters to the start of the stream.
+ addPositionQuantization(positionQuant) ;
+ addColorQuantization(colorQuant) ;
+ addNormalQuantization(normalQuant) ;
+
+ // Loop through all GeometryInfo objects and add them to the stream.
+ for (int i = 0 ; i < geometry.length ; i++) {
+ if (debug) System.out.println("\nGeometryInfo " + i + ":") ;
+ addGeometryArray(geometry[i].getGeometryArray()) ;
+ }
+
+ if (benchmark) {
+ long t = System.currentTimeMillis() - startTime ;
+ System.out.println
+ ("\nCompressionStream:\n" + geometry.length +
+ " GeometryInfo objects in " + (t / 1000f) + " sec") ;
+ }
+ }
+
+ /**
+ * Creates a CompressionStream from an array of GeometryInfo objects. The
+ * resulting stream may be used as input to the GeometryCompressor
+ * methods.
+ *
+ * Each GeometryInfo in the array must be of the same dimensionality
+ * (point, line, or surface) and have the same vertex format as the
+ * others. Texture coordinates are ignored.
+ *
+ * Defaults of 16, 9, and 6 bits are used as the quantization values for
+ * positions, colors, and normals respectively. These are the maximum
+ * resolution values defined for positions and normals; the default of 9
+ * for color is the equivalent of the 8 bits of RGBA component resolution
+ * commonly available in graphics frame buffers.
+ *
+ * @param geometry
+ * an array of GeometryInfo objects, all with the same
+ * vertex format and dimensionality
+ *
+ * @exception IllegalArgumentException if any GeometryInfo object has an
+ * inconsistent dimensionality or vertex format
+ *
+ * @see GeometryInfo
+ * @see GeometryCompressor
+ */
+ public CompressionStream(GeometryInfo geometry[]) {
+ this(16, 9, 6, geometry) ;
+ }
+
+ /**
+ * Get the original bounds of the coordinate data, in modeling coordinates.
+ * Coordinate data is positioned and scaled to a normalized cube after
+ * compression.
+ *
+ * @return Point3d array of length 2, where the 1st Point3d is the lower
+ * bounds and the 2nd Point3d is the upper bounds.
+ * @since Java 3D 1.3
+ */
+ public Point3d[] getModelBounds() {
+ Point3d[] bounds = new Point3d[2] ;
+ bounds[0] = new Point3d(mcBounds[0]) ;
+ bounds[1] = new Point3d(mcBounds[1]) ;
+ return bounds ;
+ }
+
+ /**
+ * Get the bounds of the compressed object in normalized coordinates.
+ * These have an maximum bounds by [-1.0 .. +1.0] across each axis.
+ *
+ * @return Point3d array of length 2, where the 1st Point3d is the lower
+ * bounds and the 2nd Point3d is the upper bounds.
+ * @since Java 3D 1.3
+ */
+ public Point3d[] getNormalizedBounds() {
+ Point3d[] bounds = new Point3d[2] ;
+ bounds[0] = new Point3d(ncBounds[0]) ;
+ bounds[1] = new Point3d(ncBounds[1]) ;
+ return bounds ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamColor.java b/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamColor.java
new file mode 100644
index 0000000..c8c18be
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamColor.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.compression;
+
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4f;
+
+/**
+ * This class represents a color in a compression stream. It maintains both
+ * floating-point and quantized representations. This color may be bundled
+ * with a vertex or exist separately as a global color.
+ */
+class CompressionStreamColor extends CompressionStreamElement {
+ private int R, G, B, A ;
+ private boolean color3 ;
+ private boolean color4 ;
+ private float colorR, colorG, colorB, colorA ;
+
+ int rAbsolute, gAbsolute, bAbsolute, aAbsolute ;
+
+ /**
+ * Create a CompressionStreamColor.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param color3 floating-point representation to be encoded
+ */
+ CompressionStreamColor(CompressionStream stream, Color3f c3) {
+ this.color4 = false ;
+ this.color3 = true ;
+ colorR = c3.x ;
+ colorG = c3.y ;
+ colorB = c3.z ;
+ colorA = 0.0f ;
+ stream.byteCount += 12 ;
+ }
+
+ /**
+ * Create a CompressionStreamColor.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param color4 floating-point representation to be encoded
+ */
+ CompressionStreamColor(CompressionStream stream, Color4f c4) {
+ this.color3 = false ;
+ this.color4 = true ;
+ colorR = c4.x ;
+ colorG = c4.y ;
+ colorB = c4.z ;
+ colorA = c4.w ;
+ stream.byteCount += 16 ;
+ }
+
+ /**
+ * Quantize a floating point color to fixed point integer components of
+ * the specified number of bits. The bit length can range from a maximum
+ * of 16 to a minimum of 2 bits since negative colors are not defined.
+ *
+ * The bit length is the total number of bits in the signed version of the
+ * fixed point representation of the input color, which is assumed to
+ * be normalized into the [0..1) range. With the maximum bit length of
+ * 16, 15 bits of positive colors can be represented; a bit length of 9 is
+ * needed to get the 8 bit positive color size in common use.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param table HuffmanTable for collecting data about the quantized
+ * representation of this element
+ */
+ @Override
+ void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
+ // Clamp quantization.
+ int quant =
+ (stream.colorQuant < 2? 2 :
+ (stream.colorQuant > 16? 16 : stream.colorQuant)) ;
+
+ absolute = false ;
+ if (stream.firstColor || stream.colorQuantChanged) {
+ absolute = true ;
+ stream.lastColor[0] = 0 ;
+ stream.lastColor[1] = 0 ;
+ stream.lastColor[2] = 0 ;
+ stream.lastColor[3] = 0 ;
+ stream.firstColor = false ;
+ stream.colorQuantChanged = false ;
+ }
+
+ // Convert the floating point position to s.15 2's complement.
+ if (color3) {
+ R = (int)(colorR * 32768.0) ;
+ G = (int)(colorG * 32768.0) ;
+ B = (int)(colorB * 32768.0) ;
+ A = 0 ;
+ } else if (color4) {
+ R = (int)(colorR * 32768.0) ;
+ G = (int)(colorG * 32768.0) ;
+ B = (int)(colorB * 32768.0) ;
+ A = (int)(colorA * 32768.0) ;
+ }
+
+ // Clamp color components.
+ R = (R > 32767? 32767: (R < 0? 0: R)) ;
+ G = (G > 32767? 32767: (G < 0? 0: G)) ;
+ B = (B > 32767? 32767: (B < 0? 0: B)) ;
+ A = (A > 32767? 32767: (A < 0? 0: A)) ;
+
+ // Compute quantized values.
+ R &= quantizationMask[quant] ;
+ G &= quantizationMask[quant] ;
+ B &= quantizationMask[quant] ;
+ A &= quantizationMask[quant] ;
+
+ // Copy and retain absolute color for mesh buffer lookup.
+ rAbsolute = R ;
+ gAbsolute = G ;
+ bAbsolute = B ;
+ aAbsolute = A ;
+
+ // Compute deltas.
+ R -= stream.lastColor[0] ;
+ G -= stream.lastColor[1] ;
+ B -= stream.lastColor[2] ;
+ A -= stream.lastColor[3] ;
+
+ // Update last values.
+ stream.lastColor[0] += R ;
+ stream.lastColor[1] += G ;
+ stream.lastColor[2] += B ;
+ stream.lastColor[3] += A ;
+
+ // Compute length and shift common to all components.
+ if (color3)
+ computeLengthShift(R, G, B) ;
+
+ else if (color4)
+ computeLengthShift(R, G, B, A) ;
+
+ // 0-length components are allowed only for normals.
+ if (length == 0)
+ length = 1 ;
+
+ // Add this element to the Huffman table associated with this stream.
+ huffmanTable.addColorEntry(length, shift, absolute) ;
+ }
+
+ /**
+ * Output a setColor command.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ @Override
+ void outputCommand(HuffmanTable table, CommandStream output) {
+ outputColor(table, output, CommandStream.SET_COLOR, 8) ;
+ }
+
+ /**
+ * Output a color subcommand.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ void outputSubcommand(HuffmanTable table, CommandStream output) {
+
+ outputColor(table, output, 0, 6) ;
+ }
+
+ //
+ // Output the final compressed bits to the output command stream.
+ //
+ private void outputColor(HuffmanTable table, CommandStream output,
+ int header, int headerLength) {
+ HuffmanNode t ;
+
+ // Look up the Huffman token for this compression stream element.
+ t = table.getColorEntry(length, shift, absolute) ;
+
+ // Construct the color subcommand components. The maximum length of a
+ // color subcommand is 70 bits (a tag with a length of 6 followed by 4
+ // components of 16 bits each). The subcommand is therefore
+ // constructed initially using just the first 3 components, with the
+ // 4th component added later after the tag has been shifted into the
+ // subcommand header.
+ int componentLength = t.dataLength - t.shift ;
+ int subcommandLength = t.tagLength + (3 * componentLength) ;
+
+ R = (R >> t.shift) & (int)lengthMask[componentLength] ;
+ G = (G >> t.shift) & (int)lengthMask[componentLength] ;
+ B = (B >> t.shift) & (int)lengthMask[componentLength] ;
+
+ long colorSubcommand =
+ (((long)t.tag) << (3 * componentLength)) |
+ (((long)R) << (2 * componentLength)) |
+ (((long)G) << (1 * componentLength)) |
+ (((long)B) << (0 * componentLength)) ;
+
+ if (subcommandLength < 6) {
+ // The header will have some empty bits. The Huffman tag
+ // computation will prevent this if necessary.
+ header |= (int)(colorSubcommand << (6 - subcommandLength)) ;
+ subcommandLength = 0 ;
+ }
+ else {
+ // Move the 1st 6 bits of the subcommand into the header.
+ header |= (int)(colorSubcommand >>> (subcommandLength - 6)) ;
+ subcommandLength -= 6 ;
+ }
+
+ // Add alpha if present.
+ if (color4) {
+ A = (A >> t.shift) & (int)lengthMask[componentLength] ;
+ colorSubcommand = (colorSubcommand << componentLength) | A ;
+ subcommandLength += componentLength ;
+ }
+
+ // Add the header and body to the output buffer.
+ output.addCommand(header, headerLength,
+ colorSubcommand, subcommandLength) ;
+ }
+
+ @Override
+ public String toString() {
+ String d = absolute? "" : "delta " ;
+ String c = (colorR + " " + colorG + " " + colorB +
+ (color4? (" " + colorA): "")) ;
+
+ return
+ "color: " + c + "\n" +
+ " fixed point " + d + + R + " " + G + " " + B + "\n" +
+ " length " + length + " shift " + shift +
+ (absolute? " absolute" : " relative") ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamElement.java b/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamElement.java
new file mode 100644
index 0000000..5d7cede
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamElement.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.compression;
+
+/**
+ * Instances of this class are used as elements in a CompressionStream.
+ * @see CompressionStream
+ */
+abstract class CompressionStreamElement {
+ /**
+ * Bit length of quantized geometric components.
+ */
+ int length ;
+
+ /**
+ * Number of trailing zeros in quantized geometric components.
+ */
+ int shift ;
+
+ /**
+ * If false, geometric component values are represented as differences
+ * from those of the preceding element in the stream.
+ */
+ boolean absolute ;
+
+ /**
+ * Array with elements that can be used as masks to apply a quantization
+ * to the number of bits indicated by the referencing index [0..16].
+ */
+ static final int quantizationMask[] = {
+ 0xFFFF0000, 0xFFFF8000, 0xFFFFC000, 0xFFFFE000,
+ 0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00,
+ 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0,
+ 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE,
+ 0xFFFFFFFF
+ } ;
+
+ /**
+ * Array with elements that can be used as masks to retain the number of
+ * trailing bits of data indicated by the referencing index [0..64]. Used
+ * to clear the leading sign bits of fixed-point 2's complement numbers
+ * and in building the compressed output stream.
+ */
+ static final long lengthMask[] = {
+ 0x0000000000000000L, 0x0000000000000001L,
+ 0x0000000000000003L, 0x0000000000000007L,
+ 0x000000000000000FL, 0x000000000000001FL,
+ 0x000000000000003FL, 0x000000000000007FL,
+ 0x00000000000000FFL, 0x00000000000001FFL,
+ 0x00000000000003FFL, 0x00000000000007FFL,
+ 0x0000000000000FFFL, 0x0000000000001FFFL,
+ 0x0000000000003FFFL, 0x0000000000007FFFL,
+ 0x000000000000FFFFL, 0x000000000001FFFFL,
+ 0x000000000003FFFFL, 0x000000000007FFFFL,
+ 0x00000000000FFFFFL, 0x00000000001FFFFFL,
+ 0x00000000003FFFFFL, 0x00000000007FFFFFL,
+ 0x0000000000FFFFFFL, 0x0000000001FFFFFFL,
+ 0x0000000003FFFFFFL, 0x0000000007FFFFFFL,
+ 0x000000000FFFFFFFL, 0x000000001FFFFFFFL,
+ 0x000000003FFFFFFFL, 0x000000007FFFFFFFL,
+ 0x00000000FFFFFFFFL, 0x00000001FFFFFFFFL,
+ 0x00000003FFFFFFFFL, 0x00000007FFFFFFFFL,
+ 0x0000000FFFFFFFFFL, 0x0000001FFFFFFFFFL,
+ 0x0000003FFFFFFFFFL, 0x0000007FFFFFFFFFL,
+ 0x000000FFFFFFFFFFL, 0x000001FFFFFFFFFFL,
+ 0x000003FFFFFFFFFFL, 0x000007FFFFFFFFFFL,
+ 0x00000FFFFFFFFFFFL, 0x00001FFFFFFFFFFFL,
+ 0x00003FFFFFFFFFFFL, 0x00007FFFFFFFFFFFL,
+ 0x0000FFFFFFFFFFFFL, 0x0001FFFFFFFFFFFFL,
+ 0x0003FFFFFFFFFFFFL, 0x0007FFFFFFFFFFFFL,
+ 0x000FFFFFFFFFFFFFL, 0x001FFFFFFFFFFFFFL,
+ 0x003FFFFFFFFFFFFFL, 0x007FFFFFFFFFFFFFL,
+ 0x00FFFFFFFFFFFFFFL, 0x01FFFFFFFFFFFFFFL,
+ 0x03FFFFFFFFFFFFFFL, 0x07FFFFFFFFFFFFFFL,
+ 0x0FFFFFFFFFFFFFFFL, 0x1FFFFFFFFFFFFFFFL,
+ 0x3FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL,
+ 0xFFFFFFFFFFFFFFFFL
+ } ;
+
+
+ /**
+ * Computes the quantized representation of this stream element.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param table HuffmanTable for collecting data about the quantized
+ * representation of this element
+ */
+ abstract void quantize(CompressionStream stream, HuffmanTable table) ;
+
+ /**
+ * Outputs the compressed bits representing this stream element.
+ * Some instances of CompressionStreamElement don't require an
+ * implementation and will inherit the stub provided here.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ void outputCommand(HuffmanTable table, CommandStream output) {
+ }
+
+ /**
+ * Finds the minimum bits needed to represent the given 16-bit signed 2's
+ * complement integer. For positive integers, this include the first
+ * 1 starting from the left, plus a 0 sign bit; for negative integers,
+ * this includes the first 0 starting from the left, plus a 1 sign bit.
+ * 0 is a special case returning 0; however, 0-length components are valid
+ * ONLY for normals.
+ *
+ * The decompressor uses the data length to determine how many bits of
+ * sign extension to add to the data coming in from the compressed stream
+ * in order to create a 16-bit signed 2's complement integer. E.g., a data
+ * length of 12 indicates that 16-12=4 bits of sign are to be extended.
+ *
+ * @param number a signed 2's complement integer representable in 16 bits
+ * or less
+ * @return minimum number of bits to represent the number
+ */
+ private static final int getLength(int number) {
+ if (number == 0)
+ return 0 ;
+
+ else if ((number & 0x8000) > 0) {
+ // negative numbers
+ if ((number & 0x4000) == 0) return 16 ;
+ if ((number & 0x2000) == 0) return 15 ;
+ if ((number & 0x1000) == 0) return 14 ;
+ if ((number & 0x0800) == 0) return 13 ;
+ if ((number & 0x0400) == 0) return 12 ;
+ if ((number & 0x0200) == 0) return 11 ;
+ if ((number & 0x0100) == 0) return 10 ;
+ if ((number & 0x0080) == 0) return 9 ;
+ if ((number & 0x0040) == 0) return 8 ;
+ if ((number & 0x0020) == 0) return 7 ;
+ if ((number & 0x0010) == 0) return 6 ;
+ if ((number & 0x0008) == 0) return 5 ;
+ if ((number & 0x0004) == 0) return 4 ;
+ if ((number & 0x0002) == 0) return 3 ;
+ if ((number & 0x0001) == 0) return 2 ;
+
+ return 1 ;
+
+ } else {
+ // positive numbers
+ if ((number & 0x4000) > 0) return 16 ;
+ if ((number & 0x2000) > 0) return 15 ;
+ if ((number & 0x1000) > 0) return 14 ;
+ if ((number & 0x0800) > 0) return 13 ;
+ if ((number & 0x0400) > 0) return 12 ;
+ if ((number & 0x0200) > 0) return 11 ;
+ if ((number & 0x0100) > 0) return 10 ;
+ if ((number & 0x0080) > 0) return 9 ;
+ if ((number & 0x0040) > 0) return 8 ;
+ if ((number & 0x0020) > 0) return 7 ;
+ if ((number & 0x0010) > 0) return 6 ;
+ if ((number & 0x0008) > 0) return 5 ;
+ if ((number & 0x0004) > 0) return 4 ;
+ if ((number & 0x0002) > 0) return 3 ;
+
+ return 2 ;
+ }
+ }
+
+ /**
+ * Finds the rightmost 1 bit in the given 16-bit integer. This value is
+ * used by the decompressor to indicate the number of trailing zeros to be
+ * added to the end of the data coming in from the compressed stream,
+ * accomplished by left shifting the data by the indicated amount.
+ * 0 is a special case returning 0.
+ *
+ * @param number an integer representable in 16 bits or less
+ * @return number of trailing zeros
+ */
+ private static final int getShift(int number) {
+ if (number == 0) return 0 ;
+
+ if ((number & 0x0001) > 0) return 0 ;
+ if ((number & 0x0002) > 0) return 1 ;
+ if ((number & 0x0004) > 0) return 2 ;
+ if ((number & 0x0008) > 0) return 3 ;
+ if ((number & 0x0010) > 0) return 4 ;
+ if ((number & 0x0020) > 0) return 5 ;
+ if ((number & 0x0040) > 0) return 6 ;
+ if ((number & 0x0080) > 0) return 7 ;
+ if ((number & 0x0100) > 0) return 8 ;
+ if ((number & 0x0200) > 0) return 9 ;
+ if ((number & 0x0400) > 0) return 10 ;
+ if ((number & 0x0800) > 0) return 11 ;
+ if ((number & 0x1000) > 0) return 12 ;
+ if ((number & 0x2000) > 0) return 13 ;
+ if ((number & 0x4000) > 0) return 14 ;
+
+ return 15 ;
+ }
+
+ /**
+ * Computes common length and shift of 2 numbers.
+ */
+ final void computeLengthShift(int n0, int n1) {
+ int s0 = n0 & 0x8000 ;
+ int s1 = n1 & 0x8000 ;
+
+ // equal sign optimization
+ if (s0 == s1)
+ if (s0 == 0)
+ this.length = getLength(n0 | n1) ;
+ else
+ this.length = getLength(n0 & n1) ;
+ else
+ this.length = getMaximum(getLength(n0), getLength(n1)) ;
+
+ this.shift = getShift(n0 | n1) ;
+ }
+
+
+ /**
+ * Computes common length and shift of 3 numbers.
+ */
+ final void computeLengthShift(int n0, int n1, int n2) {
+ int s0 = n0 & 0x8000 ;
+ int s1 = n1 & 0x8000 ;
+ int s2 = n2 & 0x8000 ;
+
+ // equal sign optimization
+ if (s0 == s1)
+ if (s1 == s2)
+ if (s2 == 0)
+ this.length = getLength(n0 | n1 | n2) ;
+ else
+ this.length = getLength(n0 & n1 & n2) ;
+ else
+ if (s1 == 0)
+ this.length = getMaximum(getLength(n0 | n1),
+ getLength(n2)) ;
+ else
+ this.length = getMaximum(getLength(n0 & n1),
+ getLength(n2)) ;
+ else
+ if (s1 == s2)
+ if (s2 == 0)
+ this.length = getMaximum(getLength(n1 | n2),
+ getLength(n0)) ;
+ else
+ this.length = getMaximum(getLength(n1 & n2),
+ getLength(n0)) ;
+ else
+ if (s0 == 0)
+ this.length = getMaximum(getLength(n0 | n2),
+ getLength(n1)) ;
+ else
+ this.length = getMaximum(getLength(n0 & n2),
+ getLength(n1)) ;
+
+ this.shift = getShift(n0 | n1 | n2) ;
+ }
+
+
+ /**
+ * Computes common length and shift of 4 numbers.
+ */
+ final void computeLengthShift(int n0, int n1, int n2, int n3) {
+ this.length = getMaximum(getLength(n0), getLength(n1),
+ getLength(n2), getLength(n3)) ;
+
+ this.shift = getShift(n0 | n1 | n2 | n3) ;
+ }
+
+
+ /**
+ * Finds the maximum of two integers.
+ */
+ private static final int getMaximum(int x, int y) {
+ if (x > y)
+ return x ;
+ else
+ return y ;
+ }
+
+ /**
+ * Finds the maximum of three integers.
+ */
+ private static final int getMaximum(int x, int y, int z) {
+ if (x > y)
+ if (x > z)
+ return x ;
+ else
+ return z ;
+ else
+ if (y > z)
+ return y ;
+ else
+ return z ;
+ }
+
+ /**
+ * Finds the maximum of four integers.
+ */
+ private static final int getMaximum(int x, int y, int z, int w) {
+ int n0, n1 ;
+
+ if (x > y)
+ n0 = x ;
+ else
+ n0 = y ;
+
+ if (z > w)
+ n1 = z ;
+ else
+ n1 = w ;
+
+ if (n0 > n1)
+ return n0 ;
+ else
+ return n1 ;
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamNormal.java b/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamNormal.java
new file mode 100644
index 0000000..2dc99c3
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamNormal.java
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.compression;
+
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * This class represents a normal in a compression stream. It maintains both
+ * floating-point and quantized representations. This normal may be bundled
+ * with a vertex or exist separately as a global normal.
+ */
+class CompressionStreamNormal extends CompressionStreamElement {
+ private int u, v ;
+ private int specialOctant, specialSextant ;
+ private float normalX, normalY, normalZ ;
+
+ int octant, sextant ;
+ boolean specialNormal ;
+ int uAbsolute, vAbsolute ;
+
+ /**
+ * Create a CompressionStreamNormal.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param normal floating-point representation to be encoded
+ */
+ CompressionStreamNormal(CompressionStream stream, Vector3f normal) {
+ this.normalX = normal.x ;
+ this.normalY = normal.y ;
+ this.normalZ = normal.z ;
+ stream.byteCount += 12 ;
+ }
+
+ //
+ // Normal Encoding Parameterization
+ //
+ // A floating point normal is quantized to a desired number of bits by
+ // comparing it to candidate entries in a table of every possible normal
+ // at that quantization and finding the closest match. This table of
+ // normals is indexed by the following encoding:
+ //
+ // First, points on a unit radius sphere are parameterized by two angles,
+ // th and psi, using usual spherical coordinates. th is the angle about
+ // the y axis, psi is the inclination to the plane containing the point.
+ // The mapping between rectangular and spherical coordinates is:
+ //
+ // x = cos(th)*cos(psi)
+ // y = sin(psi)
+ // z = sin(th)*cos(psi)
+ //
+ // Points on sphere are folded first by octant, and then by sort order
+ // of xyz into one of six sextants. All the table encoding takes place in
+ // the positive octant, in the region bounded by the half spaces:
+ //
+ // x >= z
+ // z >= y
+ // y >= 0
+ //
+ // This triangular shaped patch runs from 0 to 45 degrees in th, and
+ // from 0 to as much as 0.615479709 (MAX_Y_ANG) in psi. The xyz bounds
+ // of the patch is:
+ //
+ // (1, 0, 0) (1/sqrt(2), 0, 1/sqrt(2)) (1/sqrt(3), 1/sqrt(3), 1/sqrt(3))
+ //
+ // When dicing this space up into discrete points, the choice for y is
+ // linear quantization in psi. This means that if the y range is to be
+ // divided up into n segments, the angle of segment j is:
+ //
+ // psi(j) = MAX_Y_ANG*(j/n)
+ //
+ // The y height of the patch (in arc length) is *not* the same as the xz
+ // dimension. However, the subdivision quantization needs to treat xz and
+ // y equally. To achieve this, the th angles are re-parameterized as
+ // reflected psi angles. That is, the i-th point's th is:
+ //
+ // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*(i/n)))
+ //
+ // To go the other direction, the angle th corresponds to the real index r
+ // (in the same 0-n range as i):
+ //
+ // r(th) = n*atan(sin(th))/MAX_Y_ANG
+ //
+ // Rounded to the nearest integer, this gives the closest integer index i
+ // to the xz angle th. Because the triangle has a straight edge on the
+ // line x=z, it is more intuitive to index the xz angles in reverse
+ // order. Thus the two equations above are replaced by:
+ //
+ // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*((n-i)/n)))
+ //
+ // r(th) = n*(1 - atan(sin(th))/MAX_Y_ANG)
+ //
+ // Each level of quantization subdivides the triangular patch twice as
+ // densely. The case in which only the three vertices of the triangle are
+ // present is the first logical stage of representation, but because of
+ // how the table is encoded the first usable case starts one level of
+ // sub-division later. This three point level has an n of 2 by the above
+ // conventions.
+ //
+ private static final int MAX_UV_BITS = 6 ;
+ private static final int MAX_UV_ENTRIES = 64 ;
+
+ private static final double cgNormals[][][][] =
+ new double[MAX_UV_BITS+1][MAX_UV_ENTRIES+1][MAX_UV_ENTRIES+1][3] ;
+
+ private static final double MAX_Y_ANG = 0.615479709 ;
+ private static final double UNITY_14 = 16384.0 ;
+
+ private static void computeNormals() {
+ int inx, iny, inz, n ;
+ double th, psi, qnx, qny, qnz ;
+
+ for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) {
+ n = 1 << quant ;
+
+ for (int j = 0 ; j <= n ; j++) {
+ for (int i = 0 ; i <= n ; i++) {
+ if (i+j > n) continue ;
+
+ psi = MAX_Y_ANG*(j/((double) n)) ;
+ th = Math.asin(Math.tan(MAX_Y_ANG*((n-i)/((double) n)))) ;
+
+ qnx = Math.cos(th)*Math.cos(psi) ;
+ qny = Math.sin(psi) ;
+ qnz = Math.sin(th)*Math.cos(psi) ;
+
+ // The normal table uses 16-bit components and must be
+ // able to represent both +1.0 and -1.0, so convert the
+ // floating point normal components to fixed point with 14
+ // fractional bits, a unity bit, and a sign bit (s1.14).
+ // Set them back to get the float equivalent.
+ qnx = qnx*UNITY_14 ; inx = (int)qnx ;
+ qnx = inx ; qnx = qnx/UNITY_14 ;
+
+ qny = qny*UNITY_14 ; iny = (int)qny ;
+ qny = iny ; qny = qny/UNITY_14 ;
+
+ qnz = qnz*UNITY_14 ; inz = (int)qnz ;
+ qnz = inz ; qnz = qnz/UNITY_14 ;
+
+ cgNormals[quant][j][i][0] = qnx ;
+ cgNormals[quant][j][i][1] = qny ;
+ cgNormals[quant][j][i][2] = qnz ;
+ }
+ }
+ }
+ }
+
+ //
+ // An inverse sine table is used for each quantization level to take the Y
+ // component of a normal (which is the sine of the inclination angle) and
+ // obtain the closest quantized Y angle.
+ //
+ // At any level of compression, there are a fixed number of different Y
+ // angles (between 0 and MAX_Y_ANG). The inverse table is built to have
+ // slightly more than twice as many entries as y angles at any particular
+ // level; this ensures that the inverse look-up will get within one angle
+ // of the right one. The size of the table should be as small as
+ // possible, but with its delta sine still smaller than the delta sine
+ // between the last two angles to be encoded.
+ //
+ // Example: the inverse sine table has a maximum angle of 0.615479709. At
+ // the maximum resolution of 6 bits there are 65 discrete angles used,
+ // but twice as many are needed for thresholding between angles, so the
+ // delta angle is 0.615479709/128. The difference then between the last
+ // two angles to be encoded is:
+ // sin(0.615479709*128.0/128.0) - sin(0.615479709*127.0/128.0) = 0.003932730
+ //
+ // Using 8 significent bits below the binary point, fixed point can
+ // represent sines in increments of 0.003906250, just slightly smaller.
+ // However, because the maximum Y angle sine is 0.577350269, only 148
+ // instead of 256 table entries are needed.
+ //
+ private static final short inverseSine[][] = new short[MAX_UV_BITS+1][] ;
+
+ // UNITY_14 * sin(MAX_Y_ANGLE)
+ private static final short MAX_SIN_14BIT = 9459 ;
+
+ private static void computeInverseSineTables() {
+ int intSin, deltaSin, intAngle ;
+ double floatSin, floatAngle ;
+ short sin14[] = new short[MAX_UV_ENTRIES+1] ;
+
+ // Build table of sines in s1.14 fixed point for each of the
+ // discrete angles used at maximum resolution.
+ for (int i = 0 ; i <= MAX_UV_ENTRIES ; i++) {
+ sin14[i] = (short)(UNITY_14*Math.sin(i*MAX_Y_ANG/MAX_UV_ENTRIES)) ;
+ }
+
+ for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) {
+ switch (quant) {
+ default:
+ case 6:
+ // Delta angle: MAX_Y_ANGLE/128.0
+ // Bits below binary point for fixed point delta sine: 8
+ // Integer delta sine: 64
+ // Inverse sine table size: 148 entries
+ deltaSin = 1 << (14 - 8) ;
+ break ;
+ case 5:
+ // Delta angle: MAX_Y_ANGLE/64.0
+ // Bits below binary point for fixed point delta sine: 7
+ // Integer delta sine: 128
+ // Inverse sine table size: 74 entries
+ deltaSin = 1 << (14 - 7) ;
+ break ;
+ case 4:
+ // Delta angle: MAX_Y_ANGLE/32.0
+ // Bits below binary point for fixed point delta sine: 6
+ // Integer delta sine: 256
+ // Inverse sine table size: 37 entries
+ deltaSin = 1 << (14 - 6) ;
+ break ;
+ case 3:
+ // Delta angle: MAX_Y_ANGLE/16.0
+ // Bits below binary point for fixed point delta sine: 5
+ // Integer delta sine: 512
+ // Inverse sine table size: 19 entries
+ deltaSin = 1 << (14 - 5) ;
+ break ;
+ case 2:
+ // Delta angle: MAX_Y_ANGLE/8.0
+ // Bits below binary point for fixed point delta sine: 4
+ // Integer delta sine: 1024
+ // Inverse sine table size: 10 entries
+ deltaSin = 1 << (14 - 4) ;
+ break ;
+ case 1:
+ // Delta angle: MAX_Y_ANGLE/4.0
+ // Bits below binary point for fixed point delta sine: 3
+ // Integer delta sine: 2048
+ // Inverse sine table size: 5 entries
+ deltaSin = 1 << (14 - 3) ;
+ break ;
+ case 0:
+ // Delta angle: MAX_Y_ANGLE/2.0
+ // Bits below binary point for fixed point delta sine: 2
+ // Integer delta sine: 4096
+ // Inverse sine table size: 3 entries
+ deltaSin = 1 << (14 - 2) ;
+ break ;
+ }
+
+ inverseSine[quant] = new short[(MAX_SIN_14BIT/deltaSin) + 1] ;
+
+ intSin = 0 ;
+ for (int i = 0 ; i < inverseSine[quant].length ; i++) {
+ // Compute float representation of integer sine with desired
+ // number of fractional bits by effectively right shifting 14.
+ floatSin = intSin/UNITY_14 ;
+
+ // Compute the angle with this sine value and quantize it.
+ floatAngle = Math.asin(floatSin) ;
+ intAngle = (int)((floatAngle/MAX_Y_ANG) * (1 << quant)) ;
+
+ // Choose the closest of the three nearest quantized values
+ // intAngle-1, intAngle, and intAngle+1.
+ if (intAngle > 0) {
+ if (Math.abs(sin14[intAngle << (6-quant)] - intSin) >
+ Math.abs(sin14[(intAngle-1) << (6-quant)] - intSin))
+ intAngle = intAngle-1 ;
+ }
+
+ if (intAngle < (1 << quant)) {
+ if (Math.abs(sin14[intAngle << (6-quant)] - intSin) >
+ Math.abs(sin14[(intAngle+1) << (6-quant)] - intSin))
+ intAngle = intAngle+1 ;
+ }
+
+ inverseSine[quant][i] = (short)intAngle ;
+ intSin += deltaSin ;
+ }
+ }
+ }
+
+ /**
+ * Compute static tables needed for normal quantization.
+ */
+ static {
+ computeNormals() ;
+ computeInverseSineTables() ;
+ }
+
+ /**
+ * Quantize the floating point normal to a 6-bit octant/sextant plus u,v
+ * components of [0..6] bits. Full resolution is 18 bits and the minimum
+ * is 6 bits.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param table HuffmanTable for collecting data about the quantized
+ * representation of this element
+ */
+ @Override
+ void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
+ double nx, ny, nz, t ;
+
+ // Clamp UV quantization.
+ int quant =
+ (stream.normalQuant < 0? 0 :
+ (stream.normalQuant > 6? 6 : stream.normalQuant)) ;
+
+ nx = normalX ;
+ ny = normalY ;
+ nz = normalZ ;
+
+ octant = 0 ;
+ sextant = 0 ;
+ u = 0 ;
+ v = 0 ;
+
+ // Normalize the fixed point normal to the positive signed octant.
+ if (nx < 0.0) {
+ octant |= 4 ;
+ nx = -nx ;
+ }
+ if (ny < 0.0) {
+ octant |= 2 ;
+ ny = -ny ;
+ }
+ if (nz < 0.0) {
+ octant |= 1 ;
+ nz = -nz ;
+ }
+
+ // Normalize the fixed point normal to the proper sextant of the octant.
+ if (nx < ny) {
+ sextant |= 1 ;
+ t = nx ;
+ nx = ny ;
+ ny = t ;
+ }
+ if (nz < ny) {
+ sextant |= 2 ;
+ t = ny ;
+ ny = nz ;
+ nz = t ;
+ }
+ if (nx < nz) {
+ sextant |= 4 ;
+ t = nx ;
+ nx = nz ;
+ nz = t ;
+ }
+
+ // Convert the floating point y component to s1.14 fixed point.
+ int yInt = (int)(ny * UNITY_14) ;
+
+ // The y component of the normal is the sine of the y angle. Quantize
+ // the y angle by using the fixed point y component as an index into
+ // the inverse sine table of the correct size for the quantization
+ // level. (12 - quant) bits of the s1.14 y normal component are
+ // rolled off with a right shift; the remaining bits then match the
+ // number of bits used to represent the delta sine of the table.
+ int yIndex = inverseSine[quant][yInt >> (12-quant)] ;
+
+ // Search the two xz rows near y for the best match.
+ int ii = 0 ;
+ int jj = 0 ;
+ int n = 1 << quant ;
+ double dot, bestDot = -1 ;
+
+ for (int j = yIndex-1 ; j < yIndex+1 && j <= n ; j++) {
+ if (j < 0)
+ continue ;
+
+ for (int i = 0 ; i <= n ; i++) {
+ if (i+j > n)
+ continue ;
+
+ dot = nx * cgNormals[quant][j][i][0] +
+ ny * cgNormals[quant][j][i][1] +
+ nz * cgNormals[quant][j][i][2] ;
+
+ if (dot > bestDot) {
+ bestDot = dot ;
+ ii = i ;
+ jj = j ;
+ }
+ }
+ }
+
+ // Convert u and v to standard grid form.
+ u = ii << (6 - quant) ;
+ v = jj << (6 - quant) ;
+
+ // Check for special normals and specially encode them.
+ specialNormal = false ;
+ if (u == 64 && v == 0) {
+ // six coordinate axes case
+ if (sextant == 0 || sextant == 2) {
+ // +/- x-axis
+ specialSextant = 0x6 ;
+ specialOctant = ((octant & 4) != 0)? 0x2 : 0 ;
+
+ } else if (sextant == 3 || sextant == 1) {
+ // +/- y-axis
+ specialSextant = 0x6 ;
+ specialOctant = 4 | (((octant & 2) != 0)? 0x2 : 0) ;
+
+ } else if (sextant == 5 || sextant == 4) {
+ // +/- z-axis
+ specialSextant = 0x7 ;
+ specialOctant = ((octant & 1) != 0)? 0x2 : 0 ;
+ }
+ specialNormal = true ;
+ u = v = 0 ;
+
+ } else if (u == 0 && v == 64) {
+ // eight mid point case
+ specialSextant = 6 | (octant >> 2) ;
+ specialOctant = ((octant & 0x3) << 1) | 1 ;
+ specialNormal = true ;
+ u = v = 0 ;
+ }
+
+ // Compute deltas if possible.
+ // Use the non-normalized ii and jj indices.
+ int du = 0 ;
+ int dv = 0 ;
+ int uv64 = 64 >> (6 - quant) ;
+
+ absolute = false ;
+ if (stream.firstNormal || stream.normalQuantChanged ||
+ stream.lastSpecialNormal || specialNormal) {
+ // The first normal by definition is absolute, and normals cannot
+ // be represented as deltas to or from special normals, nor from
+ // normals with a different quantization.
+ absolute = true ;
+ stream.firstNormal = false ;
+ stream.normalQuantChanged = false ;
+
+ } else if (stream.lastOctant == octant &&
+ stream.lastSextant == sextant) {
+ // Deltas are always allowed within the same sextant/octant.
+ du = ii - stream.lastU ;
+ dv = jj - stream.lastV ;
+
+ } else if (stream.lastOctant != octant &&
+ stream.lastSextant == sextant &&
+ (((sextant == 1 || sextant == 5) &&
+ (stream.lastOctant & 3) == (octant & 3)) ||
+ ((sextant == 0 || sextant == 4) &&
+ (stream.lastOctant & 5) == (octant & 5)) ||
+ ((sextant == 2 || sextant == 3) &&
+ (stream.lastOctant & 6) == (octant & 6)))) {
+ // If the sextants are the same, the octants can differ only when
+ // they are bordering each other on the same edge that the
+ // sextant has.
+ du = ii - stream.lastU ;
+ dv = -jj - stream.lastV ;
+
+ // Can't delta by less than -64.
+ if (dv < -uv64) absolute = true ;
+
+ // Can't delta doubly defined points.
+ if (jj == 0) absolute = true ;
+
+ } else if (stream.lastOctant == octant &&
+ stream.lastSextant != sextant &&
+ ((sextant == 0 && stream.lastSextant == 4) ||
+ (sextant == 4 && stream.lastSextant == 0) ||
+ (sextant == 1 && stream.lastSextant == 5) ||
+ (sextant == 5 && stream.lastSextant == 1) ||
+ (sextant == 2 && stream.lastSextant == 3) ||
+ (sextant == 3 && stream.lastSextant == 2))) {
+ // If the octants are the same, the sextants must border on
+ // the i side (this case) or the j side (next case).
+ du = -ii - stream.lastU ;
+ dv = jj - stream.lastV ;
+
+ // Can't delta by less than -64.
+ if (du < -uv64) absolute = true ;
+
+ // Can't delta doubly defined points.
+ if (ii == 0) absolute = true ;
+
+ } else if (stream.lastOctant == octant &&
+ stream.lastSextant != sextant &&
+ ((sextant == 0 && stream.lastSextant == 2) ||
+ (sextant == 2 && stream.lastSextant == 0) ||
+ (sextant == 1 && stream.lastSextant == 3) ||
+ (sextant == 3 && stream.lastSextant == 1) ||
+ (sextant == 4 && stream.lastSextant == 5) ||
+ (sextant == 5 && stream.lastSextant == 4))) {
+ // If the octants are the same, the sextants must border on
+ // the j side (this case) or the i side (previous case).
+ if (((ii + jj ) != uv64) && (ii != 0) && (jj != 0)) {
+ du = uv64 - ii - stream.lastU ;
+ dv = uv64 - jj - stream.lastV ;
+
+ // Can't delta by greater than +63.
+ if ((du >= uv64) || (dv >= uv64))
+ absolute = true ;
+ } else
+ // Can't delta doubly defined points.
+ absolute = true ;
+
+ } else
+ // Can't delta this normal.
+ absolute = true ;
+
+ if (absolute == false) {
+ // Convert du and dv to standard grid form.
+ u = du << (6 - quant) ;
+ v = dv << (6 - quant) ;
+ }
+
+ // Compute length and shift common to all components.
+ computeLengthShift(u, v) ;
+
+ if (absolute && length > 6) {
+ // Absolute normal u, v components are unsigned 6-bit integers, so
+ // truncate the 0 sign bit for values > 0x001f.
+ length = 6 ;
+ }
+
+ // Add this element to the Huffman table associated with this stream.
+ huffmanTable.addNormalEntry(length, shift, absolute) ;
+
+ // Save current normal as last.
+ stream.lastSextant = sextant ;
+ stream.lastOctant = octant ;
+ stream.lastU = ii ;
+ stream.lastV = jj ;
+ stream.lastSpecialNormal = specialNormal ;
+
+ // Copy and retain absolute normal for mesh buffer lookup.
+ uAbsolute = ii ;
+ vAbsolute = jj ;
+ }
+
+ /**
+ * Output a setNormal command.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ @Override
+ void outputCommand(HuffmanTable table, CommandStream output) {
+ outputNormal(table, output, CommandStream.SET_NORM, 8) ;
+ }
+
+ /**
+ * Output a normal subcommand.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ void outputSubcommand(HuffmanTable table, CommandStream output) {
+ outputNormal(table, output, 0, 6) ;
+ }
+
+ //
+ // Output the final compressed bits to the output command stream.
+ //
+ private void outputNormal(HuffmanTable table, CommandStream output,
+ int header, int headerLength) {
+
+ HuffmanNode t ;
+
+ // Look up the Huffman token for this compression stream element.
+ t = table.getNormalEntry(length, shift, absolute) ;
+
+ // Construct the normal subcommand.
+ int componentLength = t.dataLength - t.shift ;
+ int subcommandLength = 0 ;
+ long normalSubcommand = 0 ;
+
+ if (absolute) {
+ // A 3-bit sextant and a 3-bit octant are always present.
+ subcommandLength = t.tagLength + 6 ;
+
+ if (specialNormal)
+ // Use the specially-encoded sextant and octant.
+ normalSubcommand =
+ (t.tag << 6) | (specialSextant << 3) | specialOctant ;
+ else
+ // Use the general encoding rule.
+ normalSubcommand =
+ (t.tag << 6) | (sextant << 3) | octant ;
+ } else {
+ // The tag is immediately followed by the u and v delta components.
+ subcommandLength = t.tagLength ;
+ normalSubcommand = t.tag ;
+ }
+
+ // Add the u and v values to the subcommand.
+ subcommandLength += (2 * componentLength) ;
+
+ u = (u >> t.shift) & (int)lengthMask[componentLength] ;
+ v = (v >> t.shift) & (int)lengthMask[componentLength] ;
+
+ normalSubcommand =
+ (normalSubcommand << (2 * componentLength)) |
+ (u << (1 * componentLength)) |
+ (v << (0 * componentLength)) ;
+
+ if (subcommandLength < 6) {
+ // The header will have some empty bits. The Huffman tag
+ // computation will prevent this if necessary.
+ header |= (int)(normalSubcommand << (6 - subcommandLength)) ;
+ subcommandLength = 0 ;
+ }
+ else {
+ // Move the 1st 6 bits of the subcommand into the header.
+ header |= (int)(normalSubcommand >>> (subcommandLength - 6)) ;
+ subcommandLength -= 6 ;
+ }
+
+ // Add the header and body to the output buffer.
+ output.addCommand(header, headerLength,
+ normalSubcommand, subcommandLength) ;
+ }
+
+ @Override
+ public String toString() {
+ String fixed ;
+
+ if (specialNormal)
+ fixed = " special normal, sextant " + specialSextant +
+ " octant " + specialOctant ;
+
+ else if (absolute)
+ fixed = " sextant " + sextant + " octant " + octant +
+ " u " + u + " v " + v ;
+ else
+ fixed = " du " + u + " dv " + v ;
+
+ return
+ "normal: " + normalX + " " + normalY + " " + normalZ + "\n"
+ + fixed + "\n" + " length " + length + " shift " + shift +
+ (absolute? " absolute" : " relative") ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamVertex.java b/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamVertex.java
new file mode 100644
index 0000000..3a5d12b
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/compression/CompressionStreamVertex.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.compression;
+
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * This class represents a vertex in a compression stream. It maintains both
+ * floating-point and quantized representations of the vertex position along
+ * with meshing and vertex replacement flags for line and surface
+ * primitives. If normals or colors are bundled with geometry vertices then
+ * instances of this class will also contain references to normal or color
+ * stream elements.
+ */
+class CompressionStreamVertex extends CompressionStreamElement {
+ private int X, Y, Z ;
+ private int meshFlag ;
+ private int stripFlag ;
+ private float floatX, floatY, floatZ ;
+
+ int xAbsolute, yAbsolute, zAbsolute ;
+ CompressionStreamColor color = null ;
+ CompressionStreamNormal normal = null ;
+
+ /**
+ * Create a CompressionStreamVertex with the given parameters.
+ *
+ * @param stream CompressionStream associated with this vertex
+ * @param p position
+ * @param n normal bundled with this vertex or null if not bundled
+ * @param c color bundled with this vertex or null if not bundled
+ * @param stripFlag CompressionStream.RESTART,
+ * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
+ * @param meshFlag CompressionStream.MESH_PUSH or
+ * CompressionStream.NO_MESH_PUSH
+ */
+ CompressionStreamVertex(CompressionStream stream,
+ Point3f p, Vector3f n, Color3f c,
+ int stripFlag, int meshFlag) {
+
+ this(stream, p, n, stripFlag, meshFlag) ;
+
+ if (stream.vertexColor3)
+ color = new CompressionStreamColor(stream, c) ;
+ }
+
+ /**
+ * Create a CompressionStreamVertex with the given parameters.
+ *
+ * @param stream CompressionStream associated with this vertex
+ * @param p position
+ * @param n normal bundled with this vertex or null if not bundled
+ * @param c color bundled with this vertex or null if not bundled
+ * @param stripFlag CompressionStream.RESTART,
+ * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
+ * @param meshFlag CompressionStream.MESH_PUSH or
+ * CompressionStream.NO_MESH_PUSH
+ */
+ CompressionStreamVertex(CompressionStream stream,
+ Point3f p, Vector3f n, Color4f c,
+ int stripFlag, int meshFlag) {
+
+ this(stream, p, n, stripFlag, meshFlag) ;
+
+ if (stream.vertexColor4)
+ color = new CompressionStreamColor(stream, c) ;
+ }
+
+ /**
+ * Create a CompressionStreamVertex with the given parameters.
+ *
+ * @param stream CompressionStream associated with this vertex
+ * @param p position
+ * @param n normal bundled with this vertex or null if not bundled
+ * @param stripFlag CompressionStream.RESTART,
+ * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
+ * @param meshFlag CompressionStream.MESH_PUSH or
+ * CompressionStream.NO_MESH_PUSH
+ */
+ CompressionStreamVertex(CompressionStream stream, Point3f p, Vector3f n,
+ int stripFlag, int meshFlag) {
+
+ this.stripFlag = stripFlag ;
+ this.meshFlag = meshFlag ;
+ this.floatX = p.x ;
+ this.floatY = p.y ;
+ this.floatZ = p.z ;
+
+ stream.byteCount += 12 ;
+ stream.vertexCount++ ;
+
+ if (p.x < stream.mcBounds[0].x) stream.mcBounds[0].x = p.x ;
+ if (p.y < stream.mcBounds[0].y) stream.mcBounds[0].y = p.y ;
+ if (p.z < stream.mcBounds[0].z) stream.mcBounds[0].z = p.z ;
+
+ if (p.x > stream.mcBounds[1].x) stream.mcBounds[1].x = p.x ;
+ if (p.y > stream.mcBounds[1].y) stream.mcBounds[1].y = p.y ;
+ if (p.z > stream.mcBounds[1].z) stream.mcBounds[1].z = p.z ;
+
+ if (stream.vertexNormals)
+ normal = new CompressionStreamNormal(stream, n) ;
+ }
+
+ /**
+ * Quantize the floating point position to fixed point integer components
+ * of the specified number of bits. The bit length can range from 1 to 16.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param table HuffmanTable for collecting data about the quantized
+ * representation of this element
+ */
+ @Override
+ void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
+ double px, py, pz ;
+
+ // Clamp quantization.
+ int quant =
+ (stream.positionQuant < 1? 1 :
+ (stream.positionQuant > 16? 16 : stream.positionQuant)) ;
+
+ absolute = false ;
+ if (stream.firstPosition || stream.positionQuantChanged) {
+ absolute = true ;
+ stream.lastPosition[0] = 0 ;
+ stream.lastPosition[1] = 0 ;
+ stream.lastPosition[2] = 0 ;
+ stream.firstPosition = false ;
+ stream.positionQuantChanged = false ;
+ }
+
+ // Normalize position to the unit cube. This is bounded by the open
+ // intervals (-1..1) on each axis.
+ px = (floatX - stream.center[0]) * stream.scale ;
+ py = (floatY - stream.center[1]) * stream.scale ;
+ pz = (floatZ - stream.center[2]) * stream.scale ;
+
+ // Convert the floating point position to s.15 2's complement.
+ // ~1.0 -> 32767 (0x00007fff) [ ~1.0 = 32767.0/32768.0]
+ // ~-1.0 -> -32767 (0xffff8001) [~-1.0 = -32767.0/32768.0]
+ X = (int)(px * 32768.0) ;
+ Y = (int)(py * 32768.0) ;
+ Z = (int)(pz * 32768.0) ;
+
+ // Compute quantized values.
+ X &= quantizationMask[quant] ;
+ Y &= quantizationMask[quant] ;
+ Z &= quantizationMask[quant] ;
+
+ // Update quantized bounds.
+ if (X < stream.qcBounds[0].x) stream.qcBounds[0].x = X ;
+ if (Y < stream.qcBounds[0].y) stream.qcBounds[0].y = Y ;
+ if (Z < stream.qcBounds[0].z) stream.qcBounds[0].z = Z ;
+
+ if (X > stream.qcBounds[1].x) stream.qcBounds[1].x = X ;
+ if (Y > stream.qcBounds[1].y) stream.qcBounds[1].y = Y ;
+ if (Z > stream.qcBounds[1].z) stream.qcBounds[1].z = Z ;
+
+ // Copy and retain absolute position for mesh buffer lookup.
+ xAbsolute = X ;
+ yAbsolute = Y ;
+ zAbsolute = Z ;
+
+ // Compute deltas.
+ X -= stream.lastPosition[0] ;
+ Y -= stream.lastPosition[1] ;
+ Z -= stream.lastPosition[2] ;
+
+ // Update last values.
+ stream.lastPosition[0] += X ;
+ stream.lastPosition[1] += Y ;
+ stream.lastPosition[2] += Z ;
+
+ // Deltas which exceed the range of 16-bit signed 2's complement
+ // numbers are handled by sign-extension of the 16th bit in order to
+ // effect a 16-bit wrap-around.
+ X = (X << 16) >> 16 ;
+ Y = (Y << 16) >> 16 ;
+ Z = (Z << 16) >> 16 ;
+
+ // Compute length and shift common to all components.
+ computeLengthShift(X, Y, Z) ;
+
+ // 0-length components are allowed only for normals.
+ if (length == 0)
+ length = 1 ;
+
+ // Add this element to the Huffman table associated with this stream.
+ huffmanTable.addPositionEntry(length, shift, absolute) ;
+
+ // Quantize any bundled color or normal.
+ if (color != null)
+ color.quantize(stream, huffmanTable) ;
+
+ if (normal != null)
+ normal.quantize(stream, huffmanTable) ;
+
+ // Push this vertex into the mesh buffer mirror, if necessary, so it
+ // can be retrieved for computing deltas when mesh buffer references
+ // are subsequently encountered during the quantization pass.
+ if (meshFlag == stream.MESH_PUSH)
+ stream.meshBuffer.push(this) ;
+ }
+
+ /**
+ * Output the final compressed bits to the compression command stream.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ @Override
+ void outputCommand(HuffmanTable huffmanTable, CommandStream outputBuffer) {
+
+ HuffmanNode t ;
+ int command = CommandStream.VERTEX ;
+
+ // Look up the Huffman token for this compression stream element. The
+ // values of length and shift found there will override the
+ // corresponding fields in this element, which represent best-case
+ // compression without regard to tag length.
+ t = huffmanTable.getPositionEntry(length, shift, absolute) ;
+
+ // Construct the position subcommand.
+ int componentLength = t.dataLength - t.shift ;
+ int subcommandLength = t.tagLength + (3 * componentLength) ;
+
+ X = (X >> t.shift) & (int)lengthMask[componentLength] ;
+ Y = (Y >> t.shift) & (int)lengthMask[componentLength] ;
+ Z = (Z >> t.shift) & (int)lengthMask[componentLength] ;
+
+ long positionSubcommand =
+ (((long)t.tag) << (3 * componentLength)) |
+ (((long)X) << (2 * componentLength)) |
+ (((long)Y) << (1 * componentLength)) |
+ (((long)Z) << (0 * componentLength)) ;
+
+ if (subcommandLength < 6) {
+ // The header will have some empty bits. The Huffman tag
+ // computation will prevent this if necessary.
+ command |= (int)(positionSubcommand << (6 - subcommandLength)) ;
+ subcommandLength = 0 ;
+ }
+ else {
+ // Move the 1st 6 bits of the subcommand into the header.
+ command |= (int)(positionSubcommand >>> (subcommandLength - 6)) ;
+ subcommandLength -= 6 ;
+ }
+
+ // Construct the vertex command body.
+ long body =
+ (((long)stripFlag) << (subcommandLength + 1)) |
+ (((long)meshFlag) << (subcommandLength + 0)) |
+ (positionSubcommand & lengthMask[subcommandLength]) ;
+
+ // Add the vertex command to the output buffer.
+ outputBuffer.addCommand(command, 8, body, subcommandLength + 3) ;
+
+ // Output any normal and color subcommands.
+ if (normal != null)
+ normal.outputSubcommand(huffmanTable, outputBuffer) ;
+
+ if (color != null)
+ color.outputSubcommand(huffmanTable, outputBuffer) ;
+ }
+
+ @Override
+ public String toString() {
+ String d = absolute? "" : "delta " ;
+ String c = (color == null? "": "\n\n " + color.toString()) ;
+ String n = (normal == null? "": "\n\n " + normal.toString()) ;
+
+ return
+ "position: " + floatX + " " + floatY + " " + floatZ + "\n" +
+ "fixed point " + d + + X + " " + Y + " " + Z + "\n" +
+ "length " + length + " shift " + shift +
+ (absolute? " absolute" : " relative") + "\n" +
+ "strip flag " + stripFlag + " mesh flag " + meshFlag +
+ c + n ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/compression/GeometryCompressor.java b/src/classes/share/org/jogamp/java3d/utils/compression/GeometryCompressor.java
new file mode 100644
index 0000000..39b83f7
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/compression/GeometryCompressor.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.compression;
+
+import java.io.IOException;
+
+import org.jogamp.java3d.CompressedGeometry;
+import org.jogamp.java3d.CompressedGeometryHeader;
+import org.jogamp.vecmath.Point3d;
+
+/**
+ * A GeometryCompressor takes a stream of geometric elements and
+ * quantization parameters (the CompressionStream object) and
+ * compresses it into a stream of commands as defined by appendix B
+ * of the Java 3D specification. The resulting data may be output
+ * in the form of a CompressedGeometry node component or appended
+ * to a CompressedGeometryFile.
+ *
+ * @see CompressionStream
+ * @see CompressedGeometry
+ * @see CompressedGeometryFile
+ *
+ * @deprecated As of Java 3D 1.5, replaced by
+ * org.jogamp.java3d.utils.geometry.compression.{@link org.jogamp.java3d.utils.geometry.compression.GeometryCompressor}.
+ */
+public class GeometryCompressor {
+ private static final boolean benchmark = false ;
+ private static final boolean printStream = false ;
+ private static final boolean printHuffman = false ;
+
+ private HuffmanTable huffmanTable ;
+ private CommandStream outputBuffer ;
+ private CompressedGeometryHeader cgHeader ;
+ private long startTime ;
+
+ public GeometryCompressor() {
+ // Create a compressed geometry header.
+ cgHeader = new CompressedGeometryHeader() ;
+
+ // v1.0.0 - pre-FCS
+ // v1.0.1 - fixed winding order, FCS version (J3D 1.1.2)
+ // v1.0.2 - normal component length maximum 6, LII hardware (J3D 1.2)
+ cgHeader.majorVersionNumber = 1 ;
+ cgHeader.minorVersionNumber = 0 ;
+ cgHeader.minorMinorVersionNumber = 2 ;
+ }
+
+ /**
+ * Compress a stream into a CompressedGeometry node component.
+ *
+ * @param stream CompressionStream containing the geometry to be compressed
+ * @return a CompressedGeometry node component
+ */
+ public CompressedGeometry compress(CompressionStream stream) {
+ CompressedGeometry cg ;
+
+ compressStream(stream) ;
+ cg = new CompressedGeometry(cgHeader, outputBuffer.getBytes()) ;
+
+ outputBuffer.clear() ;
+ return cg ;
+ }
+
+ /**
+ * Compress a stream and append the output to a CompressedGeometryFile.
+ * The resource remains open for subsequent updates; its close() method
+ * must be called to create a valid compressed geometry resource file.
+ *
+ * @param stream CompressionStream containing the geometry to be compressed
+ * @param f a currently open CompressedGeometryFile with write access
+ * @exception IOException if write fails
+ */
+ public void compress(CompressionStream stream, CompressedGeometryFile f)
+ throws IOException {
+
+ compressStream(stream) ;
+ f.write(cgHeader, outputBuffer.getBytes()) ;
+
+ outputBuffer.clear() ;
+ }
+
+ //
+ // Compress the stream and put the results in the output buffer.
+ // Set up the CompressedGeometryHeader object.
+ //
+ private void compressStream(CompressionStream stream) {
+ if (benchmark) startTime = System.currentTimeMillis() ;
+
+ // Create the Huffman table.
+ huffmanTable = new HuffmanTable() ;
+
+ // Quantize the stream, compute deltas between consecutive elements if
+ // possible, and histogram the data length distribution.
+ stream.quantize(huffmanTable) ;
+
+ // Compute tags for stream tokens.
+ huffmanTable.computeTags() ;
+
+ // Create the output buffer and assemble the compressed output.
+ outputBuffer = new CommandStream(stream.getByteCount() / 3) ;
+ stream.outputCommands(huffmanTable, outputBuffer) ;
+
+ // Print any desired info.
+ if (benchmark) printBench(stream) ;
+ if (printStream) stream.print() ;
+ if (printHuffman) huffmanTable.print() ;
+
+ // Set up the compressed geometry header object.
+ cgHeader.bufferType = stream.streamType ;
+ cgHeader.bufferDataPresent = 0 ;
+ cgHeader.lowerBound = new Point3d(stream.ncBounds[0]) ;
+ cgHeader.upperBound = new Point3d(stream.ncBounds[1]) ;
+
+ if (stream.vertexNormals)
+ cgHeader.bufferDataPresent |=
+ CompressedGeometryHeader.NORMAL_IN_BUFFER ;
+
+ if (stream.vertexColor3 || stream.vertexColor4)
+ cgHeader.bufferDataPresent |=
+ CompressedGeometryHeader.COLOR_IN_BUFFER ;
+
+ if (stream.vertexColor4)
+ cgHeader.bufferDataPresent |=
+ CompressedGeometryHeader.ALPHA_IN_BUFFER ;
+
+ cgHeader.start = 0 ;
+ cgHeader.size = outputBuffer.getByteCount() ;
+
+ // Clear the huffman table for next use.
+ huffmanTable.clear() ;
+ }
+
+ private void printBench(CompressionStream stream) {
+ long t = System.currentTimeMillis() - startTime ;
+ int vertexCount = stream.getVertexCount() ;
+ int meshReferenceCount = stream.getMeshReferenceCount() ;
+ int totalVertices = meshReferenceCount + vertexCount ;
+ float meshPercent = 100f * meshReferenceCount/(float)totalVertices ;
+
+ float compressionRatio =
+ stream.getByteCount() / ((float)outputBuffer.getByteCount()) ;
+
+ int vertexBytes =
+ 12 + (stream.vertexColor3 ? 12 : 0) +
+ (stream.vertexColor4 ? 16 : 0) + (stream.vertexNormals ? 12 : 0) ;
+
+ float compressedVertexBytes =
+ outputBuffer.getByteCount() / (float)totalVertices ;
+
+ System.out.println
+ ("\nGeometryCompressor:\n" + totalVertices + " total vertices\n" +
+ vertexCount + " streamed vertices\n" + meshReferenceCount +
+ " mesh buffer references (" + meshPercent + "%)\n" +
+ stream.getByteCount() + " bytes streamed geometry compressed to " +
+ outputBuffer.getByteCount() + " in " + (t/1000f) + " sec\n" +
+ (stream.getByteCount()/(float)t) + " kbytes/sec, " +
+ "stream compression ratio " + compressionRatio + "\n\n" +
+ vertexBytes + " original bytes per vertex, " +
+ compressedVertexBytes + " compressed bytes per vertex\n" +
+ "total vertex compression ratio " +
+ (vertexBytes / (float)compressedVertexBytes) + "\n\n" +
+ "lower bound " + stream.ncBounds[0].toString() +"\n" +
+ "upper bound " + stream.ncBounds[1].toString()) ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/compression/HuffmanNode.java b/src/classes/share/org/jogamp/java3d/utils/compression/HuffmanNode.java
new file mode 100644
index 0000000..00cf6ea
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/compression/HuffmanNode.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.compression;
+
+import java.util.Collection;
+import java.util.Comparator;
+
+/**
+ * Instances of this class are used as the nodes of binary trees representing
+ * mappings of tags to compression stream elements. Tags are descriptors
+ * inserted into the compression command stream that specify the encoding of
+ * immediately succeeding data elements.
+ *
+ * The tag assignments in such a tree are computed from the paths taken from
+ * the root to the leaf nodes. Each leaf node represents the particular way
+ * one or more compression stream elements wound up being encoded with respect
+ * to various combinations of data lengths, shifts, and absolute/relative
+ * status.
+ *
+ * Huffman's algorithm for constructing binary trees with minimal weighted
+ * path lengths can be used to optimize the bit lengths of the tags with
+ * respect to the frequency of occurrence of their associated data encodings
+ * in the compression stream. The weighted path length is the sum of the
+ * frequencies of all the leaf nodes times their path lengths to the root of
+ * the tree.
+ *
+ * The length of the longest tag determines the size of the table mapping tags
+ * to data representations. The geometry compression specification limits the
+ * size of the table to 64 entries, so tags cannot be longer than 6 bits. The
+ * depth of the tree is reduced through a process of increasing the data
+ * lengths of less frequently occuring nodes so they can be merged with other
+ * more frequent nodes.
+ */
+class HuffmanNode {
+ int tag, tagLength ;
+ int shift, dataLength ;
+ boolean absolute ;
+
+ private int frequency ;
+ private HuffmanNode child0, child1, mergeNode ;
+ private boolean merged, unmergeable, cleared ;
+
+ void clear() {
+ tag = -1 ;
+ tagLength = -1 ;
+
+ shift = -1 ;
+ dataLength = -1 ;
+ absolute = false ;
+
+ child0 = null ;
+ child1 = null ;
+ mergeNode = null ;
+
+ frequency = 0 ;
+ merged = false ;
+ unmergeable = false ;
+ cleared = true ;
+ }
+
+ HuffmanNode() {
+ clear() ;
+ }
+
+ HuffmanNode(int length, int shift, boolean absolute) {
+ this() ;
+ set(length, shift, absolute) ;
+ }
+
+ final void set(int length, int shift, boolean absolute) {
+ this.dataLength = length ;
+ this.shift = shift ;
+ this.absolute = absolute ;
+ this.cleared = false ;
+ }
+
+ final boolean cleared() {
+ return cleared ;
+ }
+
+ final void addCount() {
+ frequency++ ;
+ }
+
+ final boolean hasCount() {
+ return frequency > 0 ;
+ }
+
+ final boolean tokenEquals(HuffmanNode node) {
+ return
+ this.absolute == node.absolute &&
+ this.dataLength == node.dataLength &&
+ this.shift == node.shift ;
+ }
+
+ void addChildren(HuffmanNode child0, HuffmanNode child1) {
+ this.child0 = child0 ;
+ this.child1 = child1 ;
+ this.frequency = child0.frequency + child1.frequency ;
+ }
+
+ void collectLeaves(int tag, int tagLength, Collection collection) {
+ if (child0 == null) {
+ this.tag = tag ;
+ this.tagLength = tagLength ;
+ collection.add(this) ;
+ } else {
+ child0.collectLeaves((tag << 1) | 0, tagLength + 1, collection) ;
+ child1.collectLeaves((tag << 1) | 1, tagLength + 1, collection) ;
+ }
+ }
+
+ boolean mergeInto(HuffmanNode node) {
+ if (this.absolute == node.absolute) {
+ if (this.dataLength > node.dataLength)
+ node.dataLength = this.dataLength ;
+
+ if (this.shift < node.shift)
+ node.shift = this.shift ;
+
+ node.frequency += this.frequency ;
+ this.mergeNode = node ;
+ this.merged = true ;
+ return true ;
+
+ } else
+ return false ;
+ }
+
+ int incrementLength() {
+ if (shift > 0)
+ shift-- ;
+ else
+ dataLength++ ;
+
+ return dataLength - shift ;
+ }
+
+ final boolean merged() {
+ return merged ;
+ }
+
+ final HuffmanNode getMergeNode() {
+ return mergeNode ;
+ }
+
+ void setUnmergeable() {
+ unmergeable = true ;
+ }
+
+ final boolean unmergeable() {
+ return unmergeable ;
+ }
+
+ @Override
+ public String toString() {
+ return
+ "shift " + shift + " data length " + dataLength +
+ (absolute? " absolute " : " relative ") +
+ "\ntag 0x" + Integer.toHexString(tag) + " tag length " + tagLength +
+ "\nfrequency: " + frequency ;
+ }
+
+ /**
+ * Sorts nodes in ascending order by frequency.
+ */
+ static class FrequencyComparator implements Comparator {
+ @Override
+ public final int compare(Object o1, Object o2) {
+ return ((HuffmanNode)o1).frequency - ((HuffmanNode)o2).frequency ;
+ }
+ }
+
+ /**
+ * Sorts nodes in descending order by tag bit length.
+ */
+ static class TagLengthComparator implements Comparator {
+ @Override
+ public final int compare(Object o1, Object o2) {
+ return ((HuffmanNode)o2).tagLength - ((HuffmanNode)o1).tagLength ;
+ }
+ }
+
+ static FrequencyComparator frequencyComparator = new FrequencyComparator() ;
+ static TagLengthComparator tagLengthComparator = new TagLengthComparator() ;
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/compression/HuffmanTable.java b/src/classes/share/org/jogamp/java3d/utils/compression/HuffmanTable.java
new file mode 100644
index 0000000..a947f5e
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/compression/HuffmanTable.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.compression;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+/**
+ * This class maintains a map from compression stream elements (tokens) onto
+ * HuffmanNode objects. A HuffmanNode contains a tag describing the
+ * associated token's data length, right shift value, and absolute/relative
+ * status.
+ *
+ * The tags are computed using Huffman's algorithm to build a binary tree with
+ * a minimal total weighted path length. The frequency of each token is
+ * used as its node's weight when building the tree. The path length from the
+ * root to the token's node then indicates the bit length that should be used
+ * for that token's tag in order to minimize the total size of the compressed
+ * stream.
+ */
+class HuffmanTable {
+ private static final int MAX_TAG_LENGTH = 6 ;
+
+ private HuffmanNode positions[] ;
+ private HuffmanNode normals[] ;
+ private HuffmanNode colors[] ;
+
+ /**
+ * Create a new HuffmanTable with entries for all possible position,
+ * normal, and color tokens.
+ */
+ HuffmanTable() {
+ //
+ // Position and color components can have data lengths up to 16
+ // bits, with right shifts up to 15 bits. The position and color
+ // lookup tables are therefore 2*17*16=544 entries in length to
+ // account for all possible combinations of data lengths, shifts,
+ // and relative or absolute status.
+ //
+ colors = new HuffmanNode[544] ;
+ positions = new HuffmanNode[544] ;
+
+ //
+ // Delta normals can have uv components up to 7 bits in length with
+ // right shifts up to 6 bits. Absolute normals can have uv components
+ // up to 6 bits in length with right shifts up to 5 bits. The normal
+ // lookup table is therefore 2*8*7=112 entries in length.
+ //
+ normals = new HuffmanNode[112] ;
+ }
+
+ private final int getPositionIndex(int len, int shift, boolean absolute) {
+ return (absolute? 1:0)*272 + len*16 + shift ;
+ }
+
+ private final int getNormalIndex(int length, int shift, boolean absolute) {
+ return (absolute? 1:0)*56 + length*7 + shift ;
+ }
+
+ private final int getColorIndex(int length, int shift, boolean absolute) {
+ return getPositionIndex(length, shift, absolute) ;
+ }
+
+
+ /**
+ * Add a position entry with the given length, shift, and absolute
+ * status.
+ *
+ * @param length number of bits in each X, Y, and Z component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous vertex in the compression stream
+ */
+ void addPositionEntry(int length, int shift, boolean absolute) {
+ addEntry(positions, getPositionIndex(length, shift, absolute),
+ length, shift, absolute) ;
+ }
+
+ /**
+ * Get the position entry associated with the specified length, shift, and
+ * absolute status. This will contain a tag indicating the actual
+ * encoding to be used in the compression command stream, not necessarily
+ * the same as the original length and shift with which the the entry was
+ * created.
+ *
+ * @param length number of bits in each X, Y, and Z component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous vertex in the compression stream
+ * @return HuffmanNode mapped to the specified parameters
+ */
+ HuffmanNode getPositionEntry(int length, int shift, boolean absolute) {
+ return getEntry(positions, getPositionIndex(length, shift, absolute)) ;
+ }
+
+ /**
+ * Add a color entry with the given length, shift, and absolute
+ * status.
+ *
+ * @param length number of bits in each R, G, B, and A component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous color in the compression stream
+ */
+ void addColorEntry(int length, int shift, boolean absolute) {
+ addEntry(colors, getColorIndex(length, shift, absolute),
+ length, shift, absolute) ;
+ }
+
+ /**
+ * Get the color entry associated with the specified length, shift, and
+ * absolute status. This will contain a tag indicating the actual
+ * encoding to be used in the compression command stream, not necessarily
+ * the same as the original length and shift with which the the entry was
+ * created.
+ *
+ * @param length number of bits in each R, G, B, and A component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous color in the compression stream
+ * @return HuffmanNode mapped to the specified parameters
+ */
+ HuffmanNode getColorEntry(int length, int shift, boolean absolute) {
+ return getEntry(colors, getColorIndex(length, shift, absolute)) ;
+ }
+
+ /**
+ * Add a normal entry with the given length, shift, and absolute
+ * status.
+ *
+ * @param length number of bits in each U and V component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous normal in the compression stream
+ */
+ void addNormalEntry(int length, int shift, boolean absolute) {
+ addEntry(normals, getNormalIndex(length, shift, absolute),
+ length, shift, absolute) ;
+ }
+
+ /**
+ * Get the normal entry associated with the specified length, shift, and
+ * absolute status. This will contain a tag indicating the actual
+ * encoding to be used in the compression command stream, not necessarily
+ * the same as the original length and shift with which the the entry was
+ * created.
+ *
+ * @param length number of bits in each U and V component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous normal in the compression stream
+ * @return HuffmanNode mapped to the specified parameters
+ */
+ HuffmanNode getNormalEntry(int length, int shift, boolean absolute) {
+ return getEntry(normals, getNormalIndex(length, shift, absolute)) ;
+ }
+
+
+ private void addEntry(HuffmanNode table[], int index,
+ int length, int shift, boolean absolute) {
+
+ if (table[index] == null)
+ table[index] = new HuffmanNode(length, shift, absolute) ;
+
+ else if (table[index].cleared())
+ table[index].set(length, shift, absolute) ;
+
+ table[index].addCount() ;
+ }
+
+ private HuffmanNode getEntry(HuffmanNode table[], int index) {
+ HuffmanNode t = table[index] ;
+
+ while (t.merged())
+ t = t.getMergeNode() ;
+
+ return t ;
+ }
+
+ private void getEntries(HuffmanNode table[], Collection c) {
+ for (int i = 0 ; i < table.length ; i++)
+ if (table[i] != null && !table[i].cleared() &&
+ table[i].hasCount() && !table[i].merged())
+ c.add(table[i]) ;
+ }
+
+
+ /**
+ * Clear this HuffmanTable instance.
+ */
+ void clear() {
+ for (int i = 0 ; i < positions.length ; i++)
+ if (positions[i] != null)
+ positions[i].clear() ;
+
+ for (int i = 0 ; i < colors.length ; i++)
+ if (colors[i] != null)
+ colors[i].clear() ;
+
+ for (int i = 0 ; i < normals.length ; i++)
+ if (normals[i] != null)
+ normals[i].clear() ;
+ }
+
+ /**
+ * Compute optimized tags for each position, color, and normal entry.
+ */
+ void computeTags() {
+ LinkedList nodeList = new LinkedList() ;
+ getEntries(positions, nodeList) ;
+ computeTags(nodeList, 3) ;
+
+ nodeList.clear() ;
+ getEntries(colors, nodeList) ;
+ computeTags(nodeList, 3) ;
+
+ nodeList.clear() ;
+ getEntries(normals, nodeList) ;
+ computeTags(nodeList, 2) ;
+ }
+
+ //
+ // Compute tags for a list of Huffman tokens.
+ //
+ private void computeTags(LinkedList nodes, int minComponentCount) {
+ HuffmanNode node0, node1, node2 ;
+
+ // Return if there's nothing to do.
+ if (nodes.isEmpty())
+ return ;
+
+ while (true) {
+ // Sort the nodes in ascending order by frequency.
+ Collections.sort(nodes, HuffmanNode.frequencyComparator) ;
+
+ // Apply Huffman's algorithm to construct a binary tree with a
+ // minimum total weighted path length.
+ node0 = (HuffmanNode)nodes.removeFirst() ;
+ while (nodes.size() > 0) {
+ node1 = (HuffmanNode)nodes.removeFirst() ;
+ node2 = new HuffmanNode() ;
+
+ node2.addChildren(node0, node1) ;
+ addNodeInOrder(nodes, node2, HuffmanNode.frequencyComparator) ;
+
+ node0 = (HuffmanNode)nodes.removeFirst() ;
+ }
+
+ // node0 is the root of the resulting binary tree. Traverse it
+ // assigning tags and lengths to the leaf nodes. The leaves are
+ // collected into the now empty node list.
+ node0.collectLeaves(0, 0, nodes) ;
+
+ // Sort the nodes in descending order by tag length.
+ Collections.sort(nodes, HuffmanNode.tagLengthComparator) ;
+
+ // Check for tag length overrun.
+ if (((HuffmanNode)nodes.getFirst()).tagLength > MAX_TAG_LENGTH) {
+ // Tokens need to be merged and the tree rebuilt with the new
+ // combined frequencies.
+ merge(nodes) ;
+
+ } else {
+ // Increase tag length + data length if they're too small.
+ expand(nodes, minComponentCount) ;
+ break ;
+ }
+ }
+ }
+
+ //
+ // Merge a token with a long tag into some other token. The merged token
+ // will be removed from the list along with any duplicate node the merge
+ // created, reducing the size of the list by 1 or 2 elements until only
+ // unmergeable tokens are left.
+ //
+ private void merge(LinkedList nodes) {
+ ListIterator i = nodes.listIterator(0) ;
+ HuffmanNode node0, node1, node2 ;
+ int index = 0 ;
+
+ while (i.hasNext()) {
+ // Get the node with the longest possibly mergeable tag.
+ node0 = (HuffmanNode)i.next() ;
+ if (node0.unmergeable()) continue ;
+
+ // Try to find a node that can be merged with node0. This is any
+ // node that matches its absolute/relative status.
+ i.remove() ;
+ while (i.hasNext()) {
+ node1 = (HuffmanNode)i.next() ;
+ if (node0.mergeInto(node1)) {
+ // Search for a duplicate of the possibly modified node1
+ // and merge into it so that node weights remain valid.
+ // If a duplicate exists it must be further in the list,
+ // otherwise node0 would have merged into it.
+ i.remove() ;
+ while (i.hasNext()) {
+ node2 = (HuffmanNode)i.next() ;
+ if (node1.tokenEquals(node2)) {
+ node1.mergeInto(node2) ;
+ return ;
+ }
+ }
+ // node1 has no duplicate, so return it to the list.
+ i.add(node1) ;
+ return ;
+ }
+ }
+
+ // node0 can't be merged with any other node; it must be the only
+ // relative or absolute node in the list. Mark it as unmergeable
+ // to avoid unnecessary searches on subsequent calls to merge()
+ // and return it to the list.
+ node0.setUnmergeable() ;
+ i.add(node0) ;
+
+ // Restart the iteration.
+ i = nodes.listIterator(0) ;
+ }
+ }
+
+ //
+ // Empty bits within a compression command header are not allowed. If
+ // the tag length plus the total data length is less than 6 bits then
+ // the token's length must be increased.
+ //
+ private void expand(LinkedList nodes, int minComponentCount) {
+ Iterator i = nodes.iterator() ;
+
+ while (i.hasNext()) {
+ HuffmanNode n = (HuffmanNode)i.next() ;
+
+ while (n.tagLength +
+ (minComponentCount * (n.dataLength - n.shift)) < 6) {
+
+ n.incrementLength() ;
+ }
+ }
+ }
+
+ //
+ // Insert a node into the correct place in a sorted list of nodes.
+ //
+ private void addNodeInOrder(LinkedList l, HuffmanNode node, Comparator c) {
+ ListIterator i = l.listIterator(0) ;
+
+ while (i.hasNext()) {
+ HuffmanNode n = (HuffmanNode)i.next() ;
+ if (c.compare(n, node) > 0) {
+ n = (HuffmanNode)i.previous() ;
+ break ;
+ }
+ }
+ i.add(node) ;
+ }
+
+ /**
+ * Create compression stream commands for decompressors to use to set up
+ * their decompression tables.
+ *
+ * @param output CommandStream which receives the compression commands
+ */
+ void outputCommands(CommandStream output) {
+ LinkedList nodeList = new LinkedList() ;
+ getEntries(positions, nodeList) ;
+ outputCommands(nodeList, output, CommandStream.POSITION_TABLE) ;
+
+ nodeList.clear() ;
+ getEntries(colors, nodeList) ;
+ outputCommands(nodeList, output, CommandStream.COLOR_TABLE) ;
+
+ nodeList.clear() ;
+ getEntries(normals, nodeList) ;
+ outputCommands(nodeList, output, CommandStream.NORMAL_TABLE) ;
+ }
+
+ //
+ // Output a setTable command for each unique token.
+ //
+ private void outputCommands(Collection nodes,
+ CommandStream output, int tableId) {
+
+ Iterator i = nodes.iterator() ;
+ while (i.hasNext()) {
+ HuffmanNode n = (HuffmanNode)i.next() ;
+ int addressRange = (1 << n.tagLength) | n.tag ;
+ int dataLength = (n.dataLength == 16? 0 : n.dataLength) ;
+
+ int command =
+ CommandStream.SET_TABLE | (tableId << 1) | (addressRange >> 6) ;
+
+ long body =
+ ((addressRange & 0x3f) << 9) | (dataLength << 5) |
+ (n.absolute? 0x10 : 0) | n.shift ;
+
+ output.addCommand(command, 8, body, 15) ;
+ }
+ }
+
+ /**
+ * Print a collection of HuffmanNode objects to standard out.
+ *
+ * @param header descriptive string
+ * @param nodes Collection of HuffmanNode objects to print
+ */
+ void print(String header, Collection nodes) {
+ System.out.println(header + "\nentries: " + nodes.size() + "\n") ;
+
+ Iterator i = nodes.iterator() ;
+ while(i.hasNext()) {
+ HuffmanNode n = (HuffmanNode)i.next() ;
+ System.out.println(n.toString() + "\n") ;
+ }
+ }
+
+ /**
+ * Print the contents of this instance to standard out.
+ */
+ void print() {
+ LinkedList nodeList = new LinkedList() ;
+
+ getEntries(positions, nodeList) ;
+ Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
+ print("\nposition tokens and tags", nodeList) ;
+
+ nodeList.clear() ;
+ getEntries(colors, nodeList) ;
+ Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
+ print("\ncolor tokens and tags", nodeList) ;
+
+ nodeList.clear() ;
+ getEntries(normals, nodeList) ;
+ Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
+ print("\nnormal tokens and tags", nodeList) ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/compression/MeshBuffer.java b/src/classes/share/org/jogamp/java3d/utils/compression/MeshBuffer.java
new file mode 100644
index 0000000..130cb34
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/compression/MeshBuffer.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.compression;
+
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * This class mirrors the vertex mesh buffer stack supported by the geometry
+ * compression semantics.
+ */
+class MeshBuffer {
+ //
+ // The fixed-length mesh buffer stack is represented by circular buffers.
+ // Three stack representations are provided: vertices, positions, and
+ // indices.
+ //
+ // The vertex representation stores references to CompressionStreamVertex
+ // objects. The position representation stores references to Point3f,
+ // Vector3f, Color3f, and Color4f objects, while the index representation
+ // stores indices into externally maintained arrays of those objects. All
+ // these representations may be used independently and all provide access
+ // to the stored references via a mesh buffer index.
+ //
+ // In addition, the position and index representations provide lookup
+ // mechanisms to check if positions or indices exist in the mesh buffer
+ // and return their mesh buffer indices if they do. This is used to
+ // implement a limited meshing algorithm which reduces the number of
+ // vertices when non-stripped abutting facets are added to a compression
+ // stream.
+ //
+ static final int NOT_FOUND = -1 ;
+
+ private static final int SIZE = 16 ;
+ private static final int NAN_HASH =
+ new Point3f(Float.NaN, Float.NaN, Float.NaN).hashCode() ;
+
+ private int topIndex = SIZE - 1 ;
+ private int positionIndices[] = new int[SIZE] ;
+ private int normalIndices[] = new int[SIZE] ;
+ private int colorIndices[] = new int[SIZE] ;
+
+ private int topPosition = SIZE - 1 ;
+ private int positionHashCodes[] = new int[SIZE] ;
+ private Point3f positions[] = new Point3f[SIZE] ;
+ private Vector3f normals[] = new Vector3f[SIZE] ;
+ private Color3f colors3[] = new Color3f[SIZE] ;
+ private Color4f colors4[] = new Color4f[SIZE] ;
+
+ private int topVertex = SIZE - 1 ;
+ private CompressionStreamVertex vertices[] =
+ new CompressionStreamVertex[SIZE] ;
+
+ MeshBuffer() {
+ for (int i = 0 ; i < SIZE ; i++) {
+ positionHashCodes[i] = NAN_HASH ;
+
+ positionIndices[i] = NOT_FOUND ;
+ normalIndices[i] = NOT_FOUND ;
+ colorIndices[i] = NOT_FOUND ;
+ }
+ }
+
+ private static int nextTop(int top) {
+ // The stack top references an element in the fixed-length backing
+ // array in which the stack is stored. Stack elements below it have
+ // decreasing indices into the backing array until element 0, at which
+ // point the indices wrap to the end of the backing array and back to
+ // the top.
+ //
+ // A push is accomplished by incrementing the stack top in a circular
+ // buffer and storing the data into the new stack element it
+ // references. The bottom of the stack is the element with the next
+ // higher index from the top in the backing array, and is overwritten
+ // with each new push.
+ return (top + 1) % SIZE ;
+ }
+
+ private static int flipOffset(int top, int offset) {
+ // Flips an offset relative to the beginning of the backing array to
+ // an offset from the top of the stack. Also works in reverse, from
+ // an offset from the top of the stack to an offset from the beginning
+ // of the backing array.
+ if (offset > top) offset -= SIZE ;
+ return top - offset ;
+ }
+
+ //
+ // Mesh buffer vertex stack. This is currently only used for vertex
+ // lookup during the quantization pass in order to compute delta values;
+ // no mesh reference lookup is necessary.
+ //
+ void push(CompressionStreamVertex v) {
+ topVertex = nextTop(topVertex) ;
+ vertices[topVertex] = v ;
+ }
+
+ CompressionStreamVertex getVertex(int meshReference) {
+ return vertices[flipOffset(topVertex, meshReference)] ;
+ }
+
+
+ //
+ // Mesh buffer index stack and index reference lookup support.
+ //
+ void push(int positionIndex, int normalIndex) {
+ topIndex = nextTop(topIndex) ;
+
+ positionIndices[topIndex] = positionIndex ;
+ normalIndices[topIndex] = normalIndex ;
+ }
+
+ void push(int positionIndex, int colorIndex, int normalIndex) {
+ push(positionIndex, normalIndex) ;
+ colorIndices[topIndex] = colorIndex ;
+ }
+
+ int getMeshReference(int positionIndex) {
+ int index ;
+ for (index = 0 ; index < SIZE ; index++)
+ if (positionIndices[index] == positionIndex)
+ break ;
+
+ if (index == SIZE) return NOT_FOUND ;
+ return flipOffset(topIndex, index) ;
+ }
+
+ int getPositionIndex(int meshReference) {
+ return positionIndices[flipOffset(topIndex, meshReference)] ;
+ }
+
+ int getColorIndex(int meshReference) {
+ return colorIndices[flipOffset(topIndex, meshReference)] ;
+ }
+
+ int getNormalIndex(int meshReference) {
+ return normalIndices[flipOffset(topIndex, meshReference)] ;
+ }
+
+
+ //
+ // Mesh buffer position stack and position reference lookup support.
+ //
+ void push(Point3f position, Vector3f normal) {
+ topPosition = nextTop(topPosition) ;
+
+ positionHashCodes[topPosition] = position.hashCode() ;
+ positions[topPosition] = position ;
+ normals[topPosition] = normal ;
+ }
+
+ void push(Point3f position, Color3f color, Vector3f normal) {
+ push(position, normal) ;
+ colors3[topPosition] = color ;
+ }
+
+ void push(Point3f position, Color4f color, Vector3f normal) {
+ push(position, normal) ;
+ colors4[topPosition] = color ;
+ }
+
+ void push(Point3f position, Object color, Vector3f normal) {
+ push(position, normal) ;
+ if (color instanceof Color3f)
+ colors3[topPosition] = (Color3f)color ;
+ else
+ colors4[topPosition] = (Color4f)color ;
+ }
+
+ int getMeshReference(Point3f position) {
+ int index ;
+ int hashCode = position.hashCode() ;
+
+ for (index = 0 ; index < SIZE ; index++)
+ if (positionHashCodes[index] == hashCode)
+ if (positions[index].equals(position))
+ break ;
+
+ if (index == SIZE) return NOT_FOUND ;
+ return flipOffset(topPosition, index) ;
+ }
+
+ Point3f getPosition(int meshReference) {
+ return positions[flipOffset(topPosition, meshReference)] ;
+ }
+
+ Color3f getColor3(int meshReference) {
+ return colors3[flipOffset(topPosition, meshReference)] ;
+ }
+
+ Color4f getColor4(int meshReference) {
+ return colors4[flipOffset(topPosition, meshReference)] ;
+ }
+
+ Vector3f getNormal(int meshReference) {
+ return normals[flipOffset(topPosition, meshReference)] ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/compression/package.html b/src/classes/share/org/jogamp/java3d/utils/compression/package.html
new file mode 100644
index 0000000..639ad1a
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/compression/package.html
@@ -0,0 +1,13 @@
+
+
+ Deprecated: Use
+ * By default all primitives with the same parameters share their
+ * geometry (e.g., you can have 50 shperes in your scene, but the
+ * geometry is stored only once). A change to one primitive will
+ * effect all shared nodes. Another implication of this
+ * implementation is that the capabilities of the geometry are shared,
+ * and once one of the shared nodes is live, the capabilities cannot
+ * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to
+ * share geometry among primitives with the same parameters.
+ */
+
+public class Box extends Primitive {
+
+ /**
+ * Used to designate the front side of the box when using
+ * getShape().
+ *
+ * @see Box#getShape
+ */
+ public static final int FRONT = 0;
+
+ /**
+ * Used to designate the back side of the box when using
+ * getShape().
+ *
+ * @see Box#getShape
+ */
+ public static final int BACK = 1;
+
+ /**
+ * Used to designate the right side of the box when using
+ * getShape().
+ *
+ * @see Box#getShape
+ */
+ public static final int RIGHT = 2;
+
+ /**
+ * Used to designate the left side of the box when using
+ * getShape().
+ *
+ * @see Box#getShape
+ */
+ public static final int LEFT = 3;
+
+ /**
+ * Used to designate the top side of the box when using
+ * getShape().
+ *
+ * @see Box#getShape
+ */
+ public static final int TOP = 4;
+
+ /**
+ * Used to designate the bottom side of the box when using
+ * getShape().
+ *
+ * @see Box#getShape
+ */
+ public static final int BOTTOM = 5;
+
+ float xDim, yDim, zDim;
+
+ int numTexUnit = 1;
+
+ /**
+ * Constructs a default box of 1.0 in all dimensions.
+ * Normals are generated by default, texture coordinates are not.
+ */
+
+ public Box()
+ {
+ this(1.0f, 1.0f, 1.0f, GENERATE_NORMALS, null);
+ }
+
+ /**
+ * Constructs a box of a given dimension and appearance.
+ * Normals are generated by default, texture coordinates are not.
+ *
+ * @param xdim X-dimension size.
+ * @param ydim Y-dimension size.
+ * @param zdim Z-dimension size.
+ * @param ap Appearance
+ */
+
+ public Box(float xdim, float ydim, float zdim, Appearance ap)
+ {
+ this(xdim, ydim, zdim, GENERATE_NORMALS, ap);
+ }
+
+ /**
+ * Constructs a box of a given dimension, flags, and appearance.
+ *
+ * @param xdim X-dimension size.
+ * @param ydim Y-dimension size.
+ * @param zdim Z-dimension size.
+ * @param primflags primitive flags.
+ * @param ap Appearance
+ */
+
+ public Box(float xdim, float ydim, float zdim, int primflags,
+ Appearance ap, int numTexUnit) {
+ int i;
+ double sign;
+
+ xDim = xdim;
+ yDim = ydim;
+ zDim = zdim;
+ flags = primflags;
+ this.numTexUnit = numTexUnit;
+ boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0;
+
+ //Depending on whether normal inward bit is set.
+ if ((flags & GENERATE_NORMALS_INWARD) != 0)
+ sign = -1.0;
+ else sign = 1.0;
+
+
+// TransformGroup objTrans = new TransformGroup();
+// objTrans.setCapability(ALLOW_CHILDREN_READ);
+// this.addChild(objTrans);
+
+ Shape3D shape[] = new Shape3D[6];
+
+ GeomBuffer cache = null;
+
+ for (i = FRONT; i <= BOTTOM; i++){
+
+ cache = getCachedGeometry(Primitive.BOX, xdim, ydim, zdim, i, i,
+ primflags);
+ if (cache != null) {
+// System.out.println("using cached geometry i = " + i);
+ shape[i] = new Shape3D(cache.getComputedGeometry());
+ numVerts += cache.getNumVerts();
+ numTris += cache.getNumTris();
+ }
+ else {
+
+ GeomBuffer gbuf = new GeomBuffer(4, numTexUnit);
+
+ gbuf.begin(GeomBuffer.QUAD_STRIP);
+ for (int j = 0; j < 2; j++){
+ gbuf.normal3d( (double) normals[i].x*sign,
+ (double) normals[i].y*sign,
+ (double) normals[i].z*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(tcoords[i*8 + j*2], 1.0 - tcoords[i*8 + j*2 + 1]);
+ }
+ else {
+ gbuf.texCoord2d(tcoords[i*8 + j*2], tcoords[i*8 + j*2 + 1]);
+ }
+
+ gbuf.vertex3d( (double) verts[i*12 + j*3]*xdim,
+ (double) verts[i*12+ j*3 + 1]*ydim,
+ (double) verts[i*12+ j*3 + 2]*zdim );
+ }
+ for (int j = 3; j > 1; j--){
+ gbuf.normal3d( (double) normals[i].x*sign,
+ (double) normals[i].y*sign,
+ (double) normals[i].z*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(tcoords[i*8 + j*2], 1.0 - tcoords[i*8 + j*2 + 1]);
+ }
+ else {
+ gbuf.texCoord2d(tcoords[i*8 + j*2], tcoords[i*8 + j*2 + 1]);
+ }
+ gbuf.vertex3d( (double) verts[i*12 + j*3]*xdim,
+ (double) verts[i*12+ j*3 + 1]*ydim,
+ (double) verts[i*12+ j*3 + 2]*zdim );
+ }
+ gbuf.end();
+ shape[i] = new Shape3D(gbuf.getGeom(flags));
+ numVerts = gbuf.getNumVerts();
+ numTris = gbuf.getNumTris();
+
+ if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
+ cacheGeometry(Primitive.BOX, xdim, ydim, zdim, i, i,
+ primflags, gbuf);
+ }
+ }
+
+ if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
+ (shape[i]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
+ (shape[i]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
+ }
+
+ if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
+ (shape[i]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
+ }
+
+// objTrans.addChild(shape[i]);
+ this.addChild(shape[i]);
+ }
+
+ if (ap == null){
+ setAppearance();
+ }
+ else setAppearance(ap);
+ }
+
+ public Box(float xdim, float ydim, float zdim, int primflags,
+ Appearance ap) {
+ this(xdim, ydim, zdim, primflags, ap, 1);
+ }
+
+ /**
+ * Gets one of the faces (Shape3D) from the box that contains the
+ * geometry and appearance. This allows users to modify the
+ * appearance or geometry of individual parts.
+ * @param partId The part to return.
+ * @return The Shape3D object associated with the partID. If an
+ * invalid partId is passed in, null is returned.
+ */
+
+ @Override
+ public Shape3D getShape(int partId) {
+ if ((partId >= FRONT) && (partId <= BOTTOM))
+// return (Shape3D)(((Group)getChild(0)).getChild(partId));
+ return (Shape3D)getChild(partId);
+ return null;
+ }
+
+ /**
+ * Sets appearance of the box. This will set each face of the
+ * box to the same appearance. To set each face's appearance
+ * separately, use getShape(partId) to get the
+ * individual shape and call shape.setAppearance(ap).
+ */
+
+ @Override
+ public void setAppearance(Appearance ap){
+// ((Shape3D)((Group)getChild(0)).getChild(TOP)).setAppearance(ap);
+// ((Shape3D)((Group)getChild(0)).getChild(LEFT)).setAppearance(ap);
+// ((Shape3D)((Group)getChild(0)).getChild(RIGHT)).setAppearance(ap);
+// ((Shape3D)((Group)getChild(0)).getChild(FRONT)).setAppearance(ap);
+// ((Shape3D)((Group)getChild(0)).getChild(BACK)).setAppearance(ap);
+// ((Shape3D)((Group)getChild(0)).getChild(BOTTOM)).setAppearance(ap);
+ ((Shape3D)getChild(TOP)).setAppearance(ap);
+ ((Shape3D)getChild(LEFT)).setAppearance(ap);
+ ((Shape3D)getChild(RIGHT)).setAppearance(ap);
+ ((Shape3D)getChild(FRONT)).setAppearance(ap);
+ ((Shape3D)getChild(BACK)).setAppearance(ap);
+ ((Shape3D)getChild(BOTTOM)).setAppearance(ap);
+ }
+
+ /**
+ * Gets the appearance of the specified part of the box.
+ *
+ * @param partId identifier for a given subpart of the box
+ *
+ * @return The appearance object associated with the partID. If an
+ * invalid partId is passed in, null is returned.
+ *
+ * @since Java 3D 1.2.1
+ */
+ @Override
+ public Appearance getAppearance(int partId) {
+ if (partId > BOTTOM || partId < FRONT) return null;
+ return getShape(partId).getAppearance();
+ }
+
+
+ private static final float[] verts = {
+ // front face
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+-1.0f, 1.0f, 1.0f,
+-1.0f, -1.0f, 1.0f,
+ // back face
+-1.0f, -1.0f, -1.0f,
+-1.0f, 1.0f, -1.0f,
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ // right face
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f,
+ // left face
+-1.0f, -1.0f, 1.0f,
+-1.0f, 1.0f, 1.0f,
+-1.0f, 1.0f, -1.0f,
+-1.0f, -1.0f, -1.0f,
+ // top face
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+-1.0f, 1.0f, -1.0f,
+-1.0f, 1.0f, 1.0f,
+ // bottom face
+-1.0f, -1.0f, 1.0f,
+-1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ };
+
+ private static final double[] tcoords = {
+ // front
+ 1.0, 0.0,
+ 1.0, 1.0,
+ 0.0, 1.0,
+ 0.0, 0.0,
+ // back
+ 1.0, 0.0,
+ 1.0, 1.0,
+ 0.0, 1.0,
+ 0.0, 0.0,
+ //right
+ 1.0, 0.0,
+ 1.0, 1.0,
+ 0.0, 1.0,
+ 0.0, 0.0,
+ // left
+ 1.0, 0.0,
+ 1.0, 1.0,
+ 0.0, 1.0,
+ 0.0, 0.0,
+ // top
+ 1.0, 0.0,
+ 1.0, 1.0,
+ 0.0, 1.0,
+ 0.0, 0.0,
+ // bottom
+ 0.0, 1.0,
+ 0.0, 0.0,
+ 1.0, 0.0,
+ 1.0, 1.0
+ };
+
+
+ private static final Vector3f[] normals = {
+ new Vector3f( 0.0f, 0.0f, 1.0f), // front face
+ new Vector3f( 0.0f, 0.0f, -1.0f), // back face
+ new Vector3f( 1.0f, 0.0f, 0.0f), // right face
+ new Vector3f(-1.0f, 0.0f, 0.0f), // left face
+ new Vector3f( 0.0f, 1.0f, 0.0f), // top face
+ new Vector3f( 0.0f, -1.0f, 0.0f), // bottom face
+ };
+
+
+ /**
+ * Used to create a new instance of the node. This routine is called
+ * by
+ * For any NodeComponent objects
+ * contained by the object being duplicated, each NodeComponent
+ * object's
+ * If the GENERATE_TEXTURE_COORDS flag is set, the texture coordinates
+ * are generated such that the texture gets mapped onto the cone similarly
+ * to how it gets mapped onto a cylinder, the difference being the top
+ * cap is nonexistent.
+ *
+ * By default all primitives with the same parameters share their
+ * geometry (e.g., you can have 50 shperes in your scene, but the
+ * geometry is stored only once). A change to one primitive will
+ * effect all shared nodes. Another implication of this
+ * implementation is that the capabilities of the geometry are shared,
+ * and once one of the shared nodes is live, the capabilities cannot
+ * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to
+ * share geometry among primitives with the same parameters.
+ */
+public class Cone extends Primitive {
+ float radius, height;
+ int xdivisions, ydivisions;
+ static final int MID_REZ_DIV_X = 15;
+ static final int MID_REZ_DIV_Y = 1;
+
+ /**
+ * Designates the body of the cone. Used by
+ * If appearance is null, the default white appearance will be used.
+ * @param radius Radius
+ * @param height Height
+ * @param xdivision Number of divisions along X direction.
+ * @param ydivision Number of divisions along the height of cone.
+ * @param primflags flags
+ * @param ap Appearance
+ */
+
+ public Cone(float radius, float height, int primflags,
+ int xdivision, int ydivision,
+ Appearance ap)
+ {
+ super();
+
+ Shape3D shape[] = new Shape3D[2];
+ this.radius = radius;
+ this.height = height;
+ xdivisions = xdivision;
+ ydivisions = ydivision;
+ flags = primflags;
+ boolean outside = (flags & GENERATE_NORMALS_INWARD) == 0;
+ boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0;
+ Quadrics q = new Quadrics();
+ GeomBuffer gbuf = null;
+
+ GeomBuffer cache = getCachedGeometry(Primitive.CONE,
+ radius, 0.0f, height,
+ xdivision, ydivision, primflags);
+ if (cache != null){
+// System.out.println("using cached geometry");
+ shape[BODY] = new Shape3D(cache.getComputedGeometry());
+ numVerts += cache.getNumVerts();
+ numTris += cache.getNumTris();
+ }
+ else {
+ // the body of the cone consists of the top of the cone and if
+ // ydivisions is greater than 1, the body of the cone.
+ gbuf = q.coneTop((double)(height/2.0 - height/ydivisions),
+ (double)(radius/ydivisions), height/ydivisions,
+ xdivisions, 1.0-1.0/(double)ydivisions,
+ outside, texCoordYUp);
+ shape[BODY] = new Shape3D(gbuf.getGeom(flags));
+ numVerts += gbuf.getNumVerts();
+ numTris += gbuf.getNumTris();
+ if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
+ cacheGeometry(Primitive.CONE,
+ radius, 0.0f, height,
+ xdivision, ydivision, primflags, gbuf);
+ }
+ }
+
+ // only need to add a body if the ydivisions is greater than 1
+ if (ydivisions > 1) {
+ cache = getCachedGeometry(Primitive.CONE_DIVISIONS, radius, 0.0f,
+ height, xdivision, ydivision, primflags);
+ if (cache != null) {
+// System.out.println("using cached divisions");
+ shape[BODY].addGeometry(cache.getComputedGeometry());
+ numVerts += cache.getNumVerts();
+ numTris += cache.getNumTris();
+ }
+ else {
+ gbuf = q.coneBody(-(double)(height/2.0),
+ (double)(height/2.0-height/ydivisions),
+ (double)radius, (double)(radius/ydivisions),
+ xdivisions, ydivisions-1, 1.0/(double)ydivisions,
+ outside, texCoordYUp);
+ shape[BODY].addGeometry(gbuf.getGeom(flags));
+ numVerts += gbuf.getNumVerts();
+ numTris += gbuf.getNumTris();
+ if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
+ cacheGeometry(Primitive.CONE_DIVISIONS, radius, 0.0f, height,
+ xdivision, ydivision, primflags, gbuf);
+ }
+ }
+ }
+
+ if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
+ (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
+ (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
+ }
+
+ if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
+ (shape[BODY]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
+ }
+
+ this.addChild(shape[BODY]);
+
+ // Create bottom cap.
+ cache = getCachedGeometry(Primitive.BOTTOM_DISK, radius,
+ radius, -height/2.0f, xdivision, xdivision,
+ primflags);
+ if (cache != null) {
+// System.out.println("using cached bottom");
+ shape[CAP] = new Shape3D(cache.getComputedGeometry());
+ numVerts += cache.getNumVerts();
+ numTris += cache.getNumTris();
+ }
+ else {
+ gbuf = q.disk((double)radius, xdivision, -(double)height/2.0,
+ !outside, texCoordYUp);
+ shape[CAP] = new Shape3D(gbuf.getGeom(flags));
+ numVerts += gbuf.getNumVerts();
+ numTris += gbuf.getNumTris();
+ if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
+ cacheGeometry(Primitive.BOTTOM_DISK, radius, radius, -height/2.0f,
+ xdivision, xdivision, primflags, gbuf);
+ }
+ }
+
+ if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
+ (shape[CAP]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
+ (shape[CAP]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
+ }
+
+ if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
+ (shape[CAP]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
+ }
+
+// Transform3D t2 = new Transform3D();
+
+ // Flip it to match up the texture coords.
+/* This causes the bottom not to match up for odd xdivision values
+ objectMat = new Matrix4d();
+ objectMat.setIdentity();
+ rotMat = new Matrix4d();
+ rotMat.setIdentity();
+ rotMat.rotZ(Math.PI);
+ objectMat.mul(objectMat, rotMat);
+ t2.set(objectMat);
+*/
+
+ this.addChild(shape[CAP]);
+
+ if (ap == null){
+ setAppearance();
+ }
+ else setAppearance(ap);
+ }
+
+ /**
+ * Used to create a new instance of the node. This routine is called
+ * by
+ * For any NodeComponent objects
+ * contained by the object being duplicated, each NodeComponent
+ * object's
+ * When a texture is applied to a cylinder, the texture is applied to the
+ * caps and the body different. A texture is mapped CCW from the back of the
+ * body. The top and bottom caps are mapped such that the texture appears
+ * front facing when the caps are rotated 90 degrees toward the viewer.
+ *
+ * By default all primitives with the same parameters share their
+ * geometry (e.g., you can have 50 shperes in your scene, but the
+ * geometry is stored only once). A change to one primitive will
+ * effect all shared nodes. Another implication of this
+ * implementation is that the capabilities of the geometry are shared,
+ * and once one of the shared nodes is live, the capabilities cannot
+ * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to
+ * share geometry among primitives with the same parameters.
+ */
+
+public class Cylinder extends Primitive{
+ float radius, height;
+ int xdivisions, ydivisions;
+
+ static final int MID_REZ_DIV_X = 15;
+ static final int MID_REZ_DIV_Y = 1;
+
+ /**
+ * Designates the body of the cylinder. Used by
+ * For any NodeComponent objects
+ * contained by the object being duplicated, each NodeComponent
+ * object's
+ * Here is a sample code that use this utility to create some quads.
+ *
+ * Currently, you are limited to one primitive type per geom buffer. Future
+ * versions will add support for mixed primitive types.
+ *
+ **/
+
+class GeomBuffer extends Object{
+
+ //Supported Primitives
+ static final int QUAD_STRIP = 0x01;
+ static final int TRIANGLES = 0x02;
+ static final int QUADS = 0x04;
+ static final int TRIANGLE_FAN = 0x10;
+ static final int TRIANGLE_STRIP = 0x20;
+
+ private int flags;
+
+ Point3f[] pts = null;
+ Vector3f[] normals = null;
+ TexCoord2f[] tcoords = null;
+ int currVertCnt;
+ int currPrimCnt;
+ int[] currPrimType = null,
+ currPrimStartVertex = null,
+ currPrimEndVertex = null;
+ GeometryArray geometry;
+ int numVerts = 0;
+ int numTris = 0;
+ int numTexUnit = 1;
+ int texCoordSetMap[] = null;
+
+
+ static final int debug = 0;
+
+ /** Creates a geometry buffer of given number of vertices
+ * @param numVerts total number of vertices to allocate by this buffer.
+ * This is an upper bound estimate.
+ */
+ GeomBuffer(int numVerts, int numTexUnit)
+ {
+ this.numTexUnit = numTexUnit;
+ pts = new Point3f[numVerts];
+ normals = new Vector3f[numVerts];
+ tcoords = new TexCoord2f[numVerts];
+ // max primitives is numV/3
+ currPrimType = new int[numVerts/3];
+ currPrimStartVertex = new int[numVerts/3];
+ currPrimEndVertex = new int[numVerts/3];
+ currVertCnt = 0;
+ currPrimCnt = 0;
+
+ texCoordSetMap = new int[numTexUnit];
+ for (int i = 0; i < numTexUnit; i++)
+ texCoordSetMap[i] = 0;
+
+ }
+
+ GeomBuffer(int numVerts)
+ {
+ this(numVerts, 1);
+ }
+
+ /*
+ * Returns a Java 3D geometry array from the geometry buffer. You need to
+ * call begin, vertex3d, end, etc. before calling this, of course.
+ *
+ * @param format vertex format.
+ */
+
+ GeometryArray getGeom(int format)
+ {
+ GeometryArray obj = null;
+ flags = format;
+
+ numTris = 0;
+
+ //Switch based on first primitive.
+ switch (currPrimType[0]){
+ case TRIANGLES:
+ obj = processTriangles();
+ break;
+ case QUADS:
+ obj = processQuads();
+ break;
+ case QUAD_STRIP:
+ case TRIANGLE_STRIP:
+ obj = processQuadStrips();
+ break;
+ case TRIANGLE_FAN:
+ obj = processTriangleFan();
+ break;
+ }
+ if ((obj != null) && ((flags & Primitive.ENABLE_GEOMETRY_PICKING) != 0)) {
+ obj.setCapability(Geometry.ALLOW_INTERSECT);
+ obj.setCapability(GeometryArray.ALLOW_FORMAT_READ);
+ obj.setCapability(GeometryArray.ALLOW_COUNT_READ);
+ obj.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
+ }
+ return obj;
+ }
+
+
+ /**
+ * Begins a new primitive given the primitive type.
+ *
+ * @param prim the primitive type (listed above).
+ *
+ **/
+
+ void begin(int prim)
+ {
+ if (debug >= 1) System.out.println("quad");
+ currPrimType[currPrimCnt] = prim;
+ currPrimStartVertex[currPrimCnt] = currVertCnt;
+ }
+
+
+ /**
+ * End of primitive.
+ *
+ *
+ **/
+ void end()
+ {
+ if (debug >= 1) System.out.println("end");
+ currPrimEndVertex[currPrimCnt] = currVertCnt;
+ currPrimCnt++;
+ }
+
+ void vertex3d(double x, double y, double z)
+ {
+
+ if (debug >= 2) System.out.println("v " + x + " " +
+ y + " " +
+ z);
+ pts[currVertCnt] = new Point3f((float)x, (float)y, (float)z);
+ currVertCnt++;
+ }
+
+ void normal3d(double x, double y, double z)
+ {
+ if (debug >= 2) System.out.println("n " + x + " " +
+ y + " " + z);
+ double sum = x*x+y*y+z*z;
+ if (Math.abs(sum - 1.0) > 0.001){
+ if (debug >= 2) System.out.println("normalizing");
+ double root = Math.sqrt(sum);
+ if (root > 0.000001) {
+ x /= root;
+ y /= root;
+ z /= root;
+ } else {
+ y = z = 0.0; x = 1.0;
+ }
+ }
+ normals[currVertCnt] = new Vector3f((float)x, (float)y, (float)z);
+ }
+
+ void texCoord2d(double s, double t)
+ {
+ if (debug >= 2) System.out.println("t " +
+ s + " " +
+ t);
+ tcoords[currVertCnt] = new TexCoord2f((float)s, (float)t);
+ }
+
+ // Return a reference to the texture coordinates of this geom buffer.
+ TexCoord2f[] getTexCoords() {
+ return tcoords;
+ }
+
+ /**
+ * Returns the Java 3D geometry gotten from calling getGeom.
+ *
+ **/
+
+ GeometryArray getComputedGeometry()
+ {
+ return geometry;
+ }
+
+ int getNumTris()
+ {
+ return numTris;
+ }
+
+ int getNumVerts()
+ {
+ return numVerts;
+ }
+
+
+ private GeometryArray processQuadStrips()
+ {
+ GeometryArray obj = null;
+ int i;
+ int totalVerts = 0;
+
+ // Calculate how many vertices needed to hold all of the individual quads
+ int stripCounts[] = new int[currPrimCnt];
+ for (i = 0; i < currPrimCnt; i++){
+ stripCounts[i] = currPrimEndVertex[i] - currPrimStartVertex[i];
+ totalVerts += stripCounts[i];
+ }
+
+ if (debug >= 1) System.out.println("totalVerts " + totalVerts);
+
+ int tsaFlags = TriangleStripArray.COORDINATES;
+ if ((flags & Primitive.GENERATE_NORMALS) != 0)
+ tsaFlags |= TriangleStripArray.NORMALS;
+ if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
+ tsaFlags |= TriangleStripArray.TEXTURE_COORDINATE_2;
+
+ // Create GeometryArray to pass back
+ obj = new TriangleStripArray(totalVerts, tsaFlags,
+ 1, texCoordSetMap, stripCounts);
+
+ // Allocate space to store new vertex info
+ Point3f[] newpts = new Point3f[totalVerts];
+ Vector3f[] newnormals = new Vector3f[totalVerts];
+ TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
+ int currVert = 0;
+
+ // Repeat for each Quad Strip
+ for (i = 0; i < currPrimCnt; i++){
+ // Output order for these quad arrays same as java 3d triangle strips
+ for (int j = currPrimStartVertex[i] ; j < currPrimEndVertex[i] ; j++){
+ outVertex(newpts, newnormals, newtcoords, currVert++,
+ pts, normals, tcoords, j);
+ }
+
+ }
+
+ numVerts = currVert;
+ numTris += totalVerts - currPrimCnt * 2;
+
+ obj.setCoordinates(0, newpts);
+ if ((flags & Primitive.GENERATE_NORMALS) != 0)
+ obj.setNormals(0, newnormals);
+ if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
+ obj.setTextureCoordinates(0, 0, newtcoords);
+
+ geometry = obj;
+ return obj;
+ }
+
+ private GeometryArray processQuads()
+ {
+ GeometryArray obj = null;
+ int i;
+ int totalVerts = 0;
+
+ for (i = 0; i < currPrimCnt; i++){
+ totalVerts += currPrimEndVertex[i] - currPrimStartVertex[i];
+ }
+
+ if (debug >= 1) System.out.println("totalVerts " + totalVerts);
+
+ if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
+ ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
+ obj = new QuadArray(totalVerts,
+ QuadArray.COORDINATES |
+ QuadArray.NORMALS |
+ QuadArray.TEXTURE_COORDINATE_2,
+ 1, texCoordSetMap);
+ }
+ else
+ if (((flags & Primitive.GENERATE_NORMALS) == 0) &&
+ ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
+ obj = new QuadArray(totalVerts,
+ QuadArray.COORDINATES |
+ QuadArray.TEXTURE_COORDINATE_2,
+ 1, texCoordSetMap);
+ }
+ else
+ if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
+ ((flags & Primitive.GENERATE_TEXTURE_COORDS) == 0)){
+ obj = new QuadArray(totalVerts,
+ QuadArray.COORDINATES |
+ QuadArray.NORMALS);
+ }
+ else {
+ obj = new QuadArray(totalVerts,
+ QuadArray.COORDINATES);
+ }
+
+ Point3f[] newpts = new Point3f[totalVerts];
+ Vector3f[] newnormals = new Vector3f[totalVerts];
+ TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
+ int currVert = 0;
+
+ if (debug > 1) System.out.println("total prims " + currPrimCnt);
+
+ for (i = 0; i < currPrimCnt; i++){
+ if (debug > 1) System.out.println("start " + currPrimStartVertex[i] +
+ " end " + currPrimEndVertex[i]);
+ for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i] - 3;j+=4){
+ outVertex(newpts, newnormals, newtcoords, currVert++,
+ pts, normals, tcoords, j);
+ outVertex(newpts, newnormals, newtcoords, currVert++,
+ pts, normals, tcoords, j + 1);
+ outVertex(newpts, newnormals, newtcoords, currVert++,
+ pts, normals, tcoords, j + 2);
+ outVertex(newpts, newnormals, newtcoords, currVert++,
+ pts, normals, tcoords, j + 3);
+ numTris += 2;
+ }
+ }
+ numVerts = currVert;
+
+ obj.setCoordinates(0, newpts);
+ if ((flags & Primitive.GENERATE_NORMALS) != 0)
+ obj.setNormals(0, newnormals);
+ if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
+ obj.setTextureCoordinates(0, 0, newtcoords);
+
+ geometry = obj;
+ return obj;
+ }
+
+ private GeometryArray processTriangles()
+ {
+ GeometryArray obj = null;
+ int i;
+ int totalVerts = 0;
+
+ for (i = 0; i < currPrimCnt; i++){
+ totalVerts += currPrimEndVertex[i] - currPrimStartVertex[i];
+ }
+
+ if (debug >= 1) System.out.println("totalVerts " + totalVerts);
+
+ if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
+ ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
+ obj = new TriangleArray(totalVerts,
+ TriangleArray.COORDINATES |
+ TriangleArray.NORMALS |
+ TriangleArray.TEXTURE_COORDINATE_2,
+ 1, texCoordSetMap);
+ }
+ else
+ if (((flags & Primitive.GENERATE_NORMALS) == 0) &&
+ ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)){
+ obj = new TriangleArray(totalVerts,
+ TriangleArray.COORDINATES |
+ TriangleArray.TEXTURE_COORDINATE_2,
+ 1, texCoordSetMap);
+ }
+ else
+ if (((flags & Primitive.GENERATE_NORMALS) != 0) &&
+ ((flags & Primitive.GENERATE_TEXTURE_COORDS) == 0)){
+ obj = new TriangleArray(totalVerts,
+ TriangleArray.COORDINATES |
+ TriangleArray.NORMALS);
+ }
+ else {
+ obj = new TriangleArray(totalVerts,
+ TriangleArray.COORDINATES);
+ }
+
+ Point3f[] newpts = new Point3f[totalVerts];
+ Vector3f[] newnormals = new Vector3f[totalVerts];
+ TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
+ int currVert = 0;
+
+ for (i = 0; i < currPrimCnt; i++){
+ for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i] - 2;j+=3){
+ outVertex(newpts, newnormals, newtcoords, currVert++,
+ pts, normals, tcoords, j);
+ outVertex(newpts, newnormals, newtcoords, currVert++,
+ pts, normals, tcoords, j + 1);
+ outVertex(newpts, newnormals, newtcoords, currVert++,
+ pts, normals, tcoords, j + 2);
+ numTris += 1;
+ }
+ }
+ numVerts = currVert;
+
+ obj.setCoordinates(0, newpts);
+ if ((flags & Primitive.GENERATE_NORMALS) != 0)
+ obj.setNormals(0, newnormals);
+ if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0)
+ obj.setTextureCoordinates(0, 0, newtcoords);
+
+ geometry = obj;
+ return obj;
+ }
+
+
+ private GeometryArray processTriangleFan() {
+ if (debug > 0) System.out.println("processTriangleFan");
+
+ GeometryArray obj = null;
+ int i;
+ int totalVerts = 0;
+
+ int stripCounts[] = new int[currPrimCnt];
+
+ // figure out how many vertices we need to hold the individual fans
+ for (i = 0; i < currPrimCnt; i++) {
+ stripCounts[i] = currPrimEndVertex[i] - currPrimStartVertex[i];
+ totalVerts += stripCounts[i];
+ }
+
+ // figure out what flags we need
+ int tfFlags = TriangleFanArray.COORDINATES;
+ if ((flags & Primitive.GENERATE_NORMALS) != 0) {
+ tfFlags |= TriangleFanArray.NORMALS;
+ }
+ if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) {
+ tfFlags |= TriangleFanArray.TEXTURE_COORDINATE_2;
+ }
+
+ // create the TriangleFanArray
+ obj = new TriangleFanArray(totalVerts, tfFlags, 1, texCoordSetMap,
+ stripCounts);
+
+ // allocate space for vertex info
+ Point3f[] newpts = new Point3f[totalVerts];
+ Vector3f[] newnormals = new Vector3f[totalVerts];
+ TexCoord2f[] newtcoords = new TexCoord2f[totalVerts];
+
+ int currVert = 0;
+
+ // repeat for each fan
+ for (i = 0; i < currPrimCnt; i++) {
+ for (int j = currPrimStartVertex[i]; j < currPrimEndVertex[i]; j++) {
+ outVertex(newpts, newnormals, newtcoords, currVert++, pts,
+ normals, tcoords, j);
+ }
+ }
+
+ for (i = 0; i < newpts.length; i++) {
+ if (debug > 1) System.out.println("i = " + i + " " + newpts[i]);
+ }
+
+ numVerts = currVert;
+ numTris = totalVerts - currPrimCnt * 2;
+
+ // set the coordinates on the GeometryArray
+ obj.setCoordinates(0, newpts);
+
+ // set the normals and tex coords if necessary
+ if ((flags & Primitive.GENERATE_NORMALS) != 0) {
+ obj.setNormals(0, newnormals);
+ }
+ if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0) {
+ obj.setTextureCoordinates(0, 0, newtcoords);
+ }
+ geometry = obj;
+ return obj;
+ }
+
+
+
+ void outVertex(Point3f[] dpts, Vector3f[] dnormals, TexCoord2f[] dtcoords,
+ int dloc,
+ Point3f[] spts, Vector3f[] snormals, TexCoord2f[] stcoords,
+ int sloc)
+ {
+ if (debug >= 1) System.out.println("v " + spts[sloc].x + " " +
+ spts[sloc].y + " " +
+ spts[sloc].z);
+
+ // PSP: Do we really need new points here?
+
+ dpts[dloc] = new Point3f(spts[sloc]);
+
+ if ((flags & Primitive.GENERATE_NORMALS) != 0){
+ dnormals[dloc] = new Vector3f(snormals[sloc]);
+ }
+ if ((flags & Primitive.GENERATE_TEXTURE_COORDS) != 0){
+ if (debug >= 2) System.out.println("final out tcoord");
+ dtcoords[dloc] = new TexCoord2f(stcoords[sloc]);
+ }
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/GeometryInfo.java b/src/classes/share/org/jogamp/java3d/utils/geometry/GeometryInfo.java
new file mode 100644
index 0000000..4bff8e9
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/GeometryInfo.java
@@ -0,0 +1,2838 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.HashMap;
+
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.IndexedGeometryArray;
+import org.jogamp.java3d.IndexedQuadArray;
+import org.jogamp.java3d.IndexedTriangleArray;
+import org.jogamp.java3d.IndexedTriangleFanArray;
+import org.jogamp.java3d.IndexedTriangleStripArray;
+import org.jogamp.java3d.J3DBuffer;
+import org.jogamp.java3d.QuadArray;
+import org.jogamp.java3d.TriangleArray;
+import org.jogamp.java3d.TriangleFanArray;
+import org.jogamp.java3d.TriangleStripArray;
+import org.jogamp.vecmath.Color3b;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4b;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point2f;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.TexCoord2f;
+import org.jogamp.vecmath.TexCoord3f;
+import org.jogamp.vecmath.TexCoord4f;
+import org.jogamp.vecmath.Tuple2f;
+import org.jogamp.vecmath.Tuple3f;
+import org.jogamp.vecmath.Tuple4f;
+import org.jogamp.vecmath.Vector3f;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+/**
+ * The GeometryInfo object holds data for processing by the Java3D geometry
+ * utility tools.
+ *
+ * The Stripifier combines adjacent triangles into triangle strips for
+ * more efficent rendering.
+ * Geometry is loaded into a GeometryInfo in a manner similar to the
+ *
+ * GeometryArray methods. The constructor for the GeometryInfo takes a flag
+ * that specifies the kind of data being loaded. The vertex data is
+ * specified using methods that are similar to the GeometryArray methods, but
+ * with fewer variations.
+ * The major difference between GeometryInfo and GeometryArray is
+ * that the number of vertices, vertex format, and other data are specified
+ * implictly, rather than as part of the constructor. The number of verticies
+ * comes from the number of coordinates passed to the setCoordinates()
+ * method. The format comes from the set of data components that are
+ * specified. For example, calling the setCoordinates(), setColors3() and
+ * setTextureCoordinatesParames(1, 2) methods implies a
+ * format of COORDINATES | COLOR_3
+ * | TEXTURE_COORDINATE_2. Indexed representation is specified by calling
+ * the methods that specify the indices, for example
+ * setCoordinateIndices().
+ * Stripped primitives are loaded using the TRIANGLE_FAN_ARRAY or
+ * TRIANGLE_STRIP_ARRAY flags to the constructor. The setStripCounts()
+ * method specifies the length of each strip.
+ * A set of complex polygons is loaded using the POLYGON_ARRAY
+ * flag to the constructor. The setStripCounts() method specifies the length
+ * of each contour of the polygons. The setContourCounts() method specifies
+ * the number of countours in each polygon. For example, a triangle with a
+ * triangular hole would have strip counts [3, 3] (indicating two contours of
+ * three points) and contour counts [2] (indicating a single polygon with two
+ * contours).
+ * GeometryInfo itelf contains some simple utilities, such as
+ * calculating indices for non-indexed data ("indexifying") and getting rid
+ * of unused data in your indexed geometry ("compacting").
+ * The geometry utility tools modify the contents of the
+ * GeometryInfo. After processing, the resulting geometry can be extracted
+ * from the GeometryInfo by calling getGeometryArray(). If multiple tools
+ * are used, the order of processing should be: generate normals, then
+ * stripify. For example, to convert a general mesh of polygons without
+ * normals into an optimized mesh call:
+ *
+ * If the GeometryArray uses the Note: If the texCoordSetMap is not set, multi-texturing is
+ * turned off. Only the texture coordinate set at index 0 (if set) will be
+ * used. Any other sets specified by the GeometryInfo.setTextureCoordinate*
+ * methods will be ignored.
+ */
+ public void setTexCoordSetMap(int map[]) {
+ texCoordSetMap = map;
+ }
+
+
+
+ /**
+ * Returns a reference to the texture coordinate set map.
+ * See the
+ *
+ * GeometryArray constructor for further details.
+ */
+ public int[] getTexCoordSetMap() {
+ return texCoordSetMap;
+ }
+
+
+
+ /**
+ * Sets the 2D texture coordinates for the specified set.
+ * No data copying is done - a reference to user data is used.
+ * @param texCoordSet The texture coordinate set for which these
+ * coordinates are being specified.
+ * @param texCoords Array of 2D texture coordinates.
+ * @throws IllegalArgumentException if setRotationCenter()
method.
+ *
+ * @since Java 3D 1.2.1
+ */
+public class OrbitBehavior extends ViewPlatformAWTBehavior {
+
+ private Transform3D longditudeTransform = new Transform3D();
+ private Transform3D latitudeTransform = new Transform3D();
+ private Transform3D rotateTransform = new Transform3D();
+
+ // needed for integrateTransforms but don't want to new every time
+ private Transform3D temp1 = new Transform3D();
+ private Transform3D temp2 = new Transform3D();
+ private Transform3D translation = new Transform3D();
+ private Vector3d transVector = new Vector3d();
+ private Vector3d distanceVector = new Vector3d();
+ private Vector3d centerVector = new Vector3d();
+ private Vector3d invertCenterVector = new Vector3d();
+
+ private double longditude = 0.0;
+ private double latitude = 0.0;
+ private double startDistanceFromCenter = 20.0;
+ private double distanceFromCenter = 20.0;
+ private Point3d rotationCenter = new Point3d();
+ private Matrix3d rotMatrix = new Matrix3d();
+ private Transform3D currentXfm = new Transform3D();
+
+ private int mouseX = 0;
+ private int mouseY = 0;
+
+ private double rotXFactor = 1.0;
+ private double rotYFactor = 1.0;
+ private double transXFactor = 1.0;
+ private double transYFactor = 1.0;
+ private double zoomFactor = 1.0;
+
+ private double xtrans = 0.0;
+ private double ytrans = 0.0;
+ private double ztrans = 0.0;
+
+ private boolean zoomEnabled = true;
+ private boolean rotateEnabled = true;
+ private boolean translateEnabled = true;
+ private boolean reverseRotate = false;
+ private boolean reverseTrans = false;
+ private boolean reverseZoom = false;
+ private boolean stopZoom = false;
+ private boolean proportionalZoom = false;
+ private double minRadius = 0.0;
+ private int leftButton = ROTATE;
+ private int rightButton = TRANSLATE;
+ private int middleButton = ZOOM;
+
+ // the factor to be applied to wheel zooming so that it does not
+ // look much different with mouse movement zooming.
+ // This is a totally subjective factor.
+ private float wheelZoomFactor = 50.0f;
+
+ /**
+ * Constructor flag to reverse the rotate behavior
+ */
+ public static final int REVERSE_ROTATE = 0x010;
+
+ /**
+ * Constructor flag to reverse the translate behavior
+ */
+ public static final int REVERSE_TRANSLATE = 0x020;
+
+ /**
+ * Constructor flag to reverse the zoom behavior
+ */
+ public static final int REVERSE_ZOOM = 0x040;
+
+ /**
+ * Constructor flag to reverse all the behaviors
+ */
+ public static final int REVERSE_ALL = (REVERSE_ROTATE | REVERSE_TRANSLATE |
+ REVERSE_ZOOM);
+
+ /**
+ * Constructor flag that indicates zoom should stop when it reaches
+ * the minimum orbit radius set by setMinRadius(). The minimus
+ * radius default is 0.0.
+ */
+ public static final int STOP_ZOOM = 0x100;
+
+ /**
+ * Constructor flag to disable rotate
+ */
+ public static final int DISABLE_ROTATE = 0x200;
+
+ /**
+ * Constructor flag to disable translate
+ */
+ public static final int DISABLE_TRANSLATE = 0x400;
+
+ /**
+ * Constructor flag to disable zoom
+ */
+ public static final int DISABLE_ZOOM = 0x800;
+
+ /**
+ * Constructor flag to use proportional zoom, which determines
+ * how much you zoom based on view's distance from the center of
+ * rotation. The percentage of distance that the viewer zooms
+ * is determined by the zoom factor.
+ */
+ public static final int PROPORTIONAL_ZOOM = 0x1000;
+
+ /**
+ * Used to set the fuction for a mouse button to Rotate
+ */
+ private static final int ROTATE = 0;
+
+ /**
+ * Used to set the function for a mouse button to Translate
+ */
+ private static final int TRANSLATE = 1;
+
+ /**
+ * Used to set the function for a mouse button to Zoom
+ */
+ private static final int ZOOM = 2;
+
+ private static final double NOMINAL_ZOOM_FACTOR = .01;
+ private static final double NOMINAL_PZOOM_FACTOR = 1.0;
+ private static final double NOMINAL_ROT_FACTOR = .01;
+ private static final double NOMINAL_TRANS_FACTOR = .01;
+
+ private double rotXMul = NOMINAL_ROT_FACTOR * rotXFactor;
+ private double rotYMul = NOMINAL_ROT_FACTOR * rotYFactor;
+ private double transXMul = NOMINAL_TRANS_FACTOR * transXFactor;
+ private double transYMul = NOMINAL_TRANS_FACTOR * transYFactor;
+ private double zoomMul = NOMINAL_ZOOM_FACTOR * zoomFactor;
+
+ /**
+ * Parameterless constructor for this behavior. This is intended for use
+ * by ConfiguredUniverse, which requires such a constructor for
+ * configurable behaviors. The Canvas3D used to listen for mouse and
+ * mouse motion events is obtained from the superclass
+ * setViewingPlatform() method.
+ * @since Java 3D 1.3
+ */
+ public OrbitBehavior() {
+ super(MOUSE_LISTENER | MOUSE_MOTION_LISTENER | MOUSE_WHEEL_LISTENER);
+ }
+
+ /**
+ * Creates a new OrbitBehavior
+ *
+ * @param c The Canvas3D to add the behavior to
+ */
+ public OrbitBehavior(Canvas3D c) {
+ this(c, 0 );
+ }
+
+ /**
+ * Creates a new OrbitBehavior
+ *
+ * @param c The Canvas3D to add the behavior to
+ * @param flags The option flags
+ */
+ public OrbitBehavior(Canvas3D c, int flags) {
+ super(c, MOUSE_LISTENER | MOUSE_MOTION_LISTENER | MOUSE_WHEEL_LISTENER | flags );
+
+ if ((flags & DISABLE_ROTATE) != 0) rotateEnabled = false;
+ if ((flags & DISABLE_ZOOM) != 0) zoomEnabled = false;
+ if ((flags & DISABLE_TRANSLATE) != 0) translateEnabled = false;
+ if ((flags & REVERSE_TRANSLATE) != 0) reverseTrans = true;
+ if ((flags & REVERSE_ROTATE) != 0) reverseRotate = true;
+ if ((flags & REVERSE_ZOOM) != 0) reverseZoom = true;
+ if ((flags & STOP_ZOOM) != 0) stopZoom = true;
+ if ((flags & PROPORTIONAL_ZOOM) !=0) {
+ proportionalZoom = true;
+ zoomMul = NOMINAL_PZOOM_FACTOR * zoomFactor;
+ }
+ }
+
+ @Override
+ protected synchronized void processAWTEvents( final AWTEvent[] events ) {
+ motion = false;
+ for(int i=0; imotion
variable will be true when the method
+ * is called. If it is true when the method returns integrateTransforms
+ * will be called immediately.
+ *
+ * The AWTEvents are presented in the array in the order in which they
+ * arrived from AWT.
+ */
+ protected abstract void processAWTEvents( final java.awt.AWTEvent[] events );
+
+ /**
+ * Called once per frame (if the view is moving) to calculate the new
+ * view platform transform
+ */
+ protected abstract void integrateTransforms();
+
+ /**
+ * Queue AWTEvents in a thread safe manner.
+ *
+ * If subclasses override this method they must call
+ * super.queueAWTEvent(e)
+ */
+ protected void queueAWTEvent( AWTEvent e ) {
+ // add new event to the queue
+ // must be MT safe
+ synchronized (eventQueue) {
+ eventQueue.add(e);
+ // Only need to post if this is the only event in the queue.
+ // There have been reports that the first event after
+ // setViewingPlatform() is sometimes missed, so check the
+ // firstEvent flag as well.
+ if (firstEvent || eventQueue.size() == 1) {
+ firstEvent = false;
+ postId( POST_ID );
+ }
+ }
+ }
+
+ @Override
+ public void mouseClicked(final MouseEvent e) {
+ queueAWTEvent( e );
+ }
+
+ @Override
+ public void mouseEntered(final MouseEvent e) {
+ queueAWTEvent( e );
+ }
+
+ @Override
+ public void mouseExited(final MouseEvent e) {
+ queueAWTEvent( e );
+ }
+
+ @Override
+ public void mousePressed(final MouseEvent e) {
+ queueAWTEvent( e );
+ }
+
+ @Override
+ public void mouseReleased(final MouseEvent e) {
+ queueAWTEvent( e );
+ }
+
+ @Override
+ public void mouseDragged(final MouseEvent e) {
+ queueAWTEvent( e );
+ }
+
+ @Override
+ public void mouseMoved(final MouseEvent e) {
+ queueAWTEvent( e );
+ }
+
+ @Override
+ public void keyReleased(final java.awt.event.KeyEvent e) {
+ queueAWTEvent( e );
+ }
+
+ @Override
+ public void keyPressed(final java.awt.event.KeyEvent e) {
+ queueAWTEvent( e );
+ }
+
+ @Override
+ public void keyTyped(final java.awt.event.KeyEvent e) {
+ queueAWTEvent( e );
+ }
+
+ @Override
+ public void mouseWheelMoved( final java.awt.event.MouseWheelEvent e) {
+ queueAWTEvent( e );
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/ViewPlatformBehavior.java b/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/ViewPlatformBehavior.java
new file mode 100644
index 0000000..ea9bfc1
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/ViewPlatformBehavior.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.behaviors.vp;
+
+import org.jogamp.java3d.Behavior;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+
+import org.jogamp.java3d.utils.universe.ViewingPlatform;
+
+/**
+ * Abstract class for ViewPlatformBehaviors. A ViewPlatformBehavior must
+ * be added to the ViewingPlatform with the
+ * ViewingPlatform.addViewPlatformBehavior() method. The ViewPlatformBehavior
+ * will operate on the ViewPlatform transform (the TransformGroup return by
+ * ViewingPlatform.getViewPlatformTransform()).
+ * @since Java 3D 1.2.1
+ */
+abstract public class ViewPlatformBehavior extends Behavior {
+
+ /**
+ * The ViewingPlatform for this behavior.
+ */
+ protected ViewingPlatform vp;
+
+ /**
+ * The target TransformGroup for this behavior.
+ */
+ protected TransformGroup targetTG;
+
+ /**
+ * The "home" transform for this behavior. This is a transform used to
+ * position and orient the ViewingPlatform to a known point of interest.
+ *
+ * @since Java 3D 1.3
+ */
+ protected Transform3D homeTransform = null;
+
+ /**
+ * Sets the ViewingPlatform for this behavior. This method is called by
+ * the ViewingPlatform. If a sub-calls overrides this method, it must
+ * call super.setViewingPlatform(vp).SensorEventAgent
directly.
+ * ConfiguredUniverse
and fully configured using the
+ * ViewPlatformBehaviorProperties
command to set the properties
+ * described below, but neither ConfiguredUniverse
nor
+ * SimpleUniverse
are required by this behavior. Conventional
+ * set
and get
accessors are provided for
+ * configuring this behavior directly; these methods have the same names as
+ * the properties but are prefixed with get
and set
.
+ * Property values are spelled with mixed case strings while the corresponding
+ * constant field names for the conventional accessors are spelled with upper
+ * case strings and underscores.
+ * setHotSpot
method of the Sensor
class.
+ *
+ *
+ * GrabView
- Directly manipulates the view platform by moving
+ * it in inverse response to the sensor's position and orientation,
+ * producing the effect of attaching the virtual world to the sensor's
+ * movements. If a button is available then this action is bound to button 0
+ * by default.
+ * TranslateForward
- Translates the view platform forward along
+ * the direction the sensor is pointing; the virtual world appears to move
+ * towards the sensor. The default is button 1 if two buttons are available.
+ * Related properties are {@link #TranslationSpeed TranslationSpeed}, {@link
+ * #AccelerationTime AccelerationTime}, {@link #ConstantSpeedTime
+ * ConstantSpeedTime}, and {@link #FastSpeedFactor FastSpeedFactor}.
+ * TranslateBackward
- Translates the view platform backwards
+ * along the direction the sensor is pointing; the virtual world appears to
+ * move away from the sensor. The default is button 2 if three buttons are
+ * available.
+ * RotateCCW
- Rotates the view platform counter-clockwise about
+ * a Y axis; the virtual world appears to rotate clockwise. This action is
+ * not assigned by default. Related properties are {@link #RotationSpeed
+ * RotationSpeed}, {@link #RotationCoords RotationCoords}, {@link
+ * #TransformCenterSource TransformCenterSource}, {@link #TransformCenter
+ * TransformCenter}, and AccelerationTime
.
+ * RotateCW
- Rotates the view platform clockwise about a Y axis;
+ * the virtual world appears to rotate counter-clockwise. This action is not
+ * assigned by default.
+ * ScaleUp
- Scales the view platform larger so that the virtual
+ * world appears to grow smaller. This action is not assigned by default.
+ * Related properties are {@link #ScaleSpeed ScaleSpeed},
+ * TransformCenterSource
, TransformCenter
, and
+ * AccelerationTime
.
+ * ScaleDown
- Scales the view platform smaller so that the
+ * virtual world appears to grow larger. This action is not assigned by
+ * default.
+ *
+ *
+ * Rotation
- Rotates the view platform. This is the default 2D
+ * valuator action set by this behavior. Related properties are
+ * RotationSpeed
, RotationCoords
,
+ * TransformCenterSource
, and TransformCenter
.
+ * Translation
- Translates the view platform. The translation
+ * occurs relative to the X and Z basis vectors of either the 6DOF sensor or
+ * the view platform if one is not available. The maximum speed is equal to
+ * the product of the TranslationSpeed
and
+ * FastSpeedFactor
property values.
+ * Scale
- Scales the view platform smaller with positive Y
+ * values and larger with negative Y values. The effect is to increase the
+ * apparent size of the virtual world when pushing the valuator forwards and
+ * to decrease it when pushing backwards. Related properties are
+ * ScaleSpeed
, TransformCenterSource
, and
+ * TransformCenter
.
+ * ReadAction2D
. No actions are bound by default to the 2D
+ * valuator buttons.
+ * None
can in general be assigned to any
+ * button or read action to prevent any defaults from being bound to it.
+ *
+ * @see ConfiguredUniverse
+ * @see SensorEventAgent
+ * @since Java 3D 1.3
+ */
+public class WandViewBehavior extends ViewPlatformBehavior {
+ /**
+ * Indicates a null configuration choice.
+ */
+ public static final int NONE = 0 ;
+
+ /**
+ * Indicates that a 6DOF sensor button action should be bound
+ * to grabbing the view. The default is button 0.
+ */
+ public static final int GRAB_VIEW = 1 ;
+
+ /**
+ * Indicates that a 6DOF sensor button action should be bound
+ * to translating the view forward. The default is button 1.
+ */
+ public static final int TRANSLATE_FORWARD = 2 ;
+
+ /**
+ * Indicates that a 6DOF sensor button action should be bound
+ * to translating the view backward. The default is button 2.
+ */
+ public static final int TRANSLATE_BACKWARD = 3 ;
+
+ /**
+ * Indicates that a 6DOF sensor button action should be bound
+ * to rotate the view plaform counter-clockwise about a Y axis.
+ */
+ public static final int ROTATE_CCW = 4 ;
+
+ /**
+ * Indicates that a 6DOF sensor button action should be bound
+ * to rotate the view platform clockwise about a Y axis.
+ */
+ public static final int ROTATE_CW = 5 ;
+
+ /**
+ * Indicates that a 6DOF sensor button action should be bound
+ * to scaling the view platform larger.
+ */
+ public static final int SCALE_UP = 6 ;
+
+ /**
+ * Indicates that a 6DOF sensor button action should be bound
+ * to scaling the view platform smaller.
+ */
+ public static final int SCALE_DOWN = 7 ;
+
+ /**
+ * Indicates that a 2D sensor button or read action should be bound
+ * to translation.
+ */
+ public static final int TRANSLATION = 8 ;
+
+ /**
+ * Indicates that a 2D sensor button or read action should be bound
+ * to scaling.
+ */
+ public static final int SCALE = 9 ;
+
+ /**
+ * Indicates that a 2D sensor button or read action should be bound
+ * to rotation. The default is to bind rotation to the 2D sensor reads.
+ */
+ public static final int ROTATION = 10 ;
+
+ /**
+ * Indicates that translation, rotation, or scaling speeds are
+ * per frame.
+ */
+ public static final int PER_FRAME = 11 ;
+
+ /**
+ * Use to indicate that translation, rotation, or scaling speeds are per
+ * second. This is the default.
+ */
+ public static final int PER_SECOND = 12 ;
+
+ /**
+ * Indicates that translation speed is in virtual world units.
+ */
+ public static final int VIRTUAL_UNITS = 13 ;
+
+ /**
+ * Indicates that translation speed is in physical world units
+ * (meters per second or per frame). This is the default.
+ */
+ public static final int PHYSICAL_METERS = 14 ;
+
+ /**
+ * Indicates that rotation speed should be in radians.
+ */
+ public static final int RADIANS = 15 ;
+
+ /**
+ * Indicates that rotation speed should be in degrees. This is the
+ * default.
+ */
+ public static final int DEGREES = 16 ;
+
+ /**
+ * Indicates that rotation should occur in view platform
+ * coordinates.
+ */
+ public static final int VIEW_PLATFORM = 17 ;
+
+ /**
+ * Indicates that rotation should occur in head coordinates.
+ */
+ public static final int HEAD = 18 ;
+
+ /**
+ * Indicates that rotation should occur in sensor coordinates.
+ * This is the default.
+ */
+ public static final int SENSOR = 19 ;
+
+ /**
+ * Indicates that rotation or scale should be about a fixed point
+ * in virtual world coordinates.
+ */
+ public static final int VWORLD_FIXED = 20 ;
+
+ /**
+ * Indicates that rotation or scale should be about a 6DOF sensor
+ * hotspot. This is the default.
+ */
+ public static final int HOTSPOT = 21 ;
+
+ /**
+ * Indicates that the 6DOF sensor read action should be bound to
+ * displaying the sensor's echo in the virtual world. This is the
+ * default.
+ */
+ public static final int ECHO = 22 ;
+
+ /**
+ * Indicates that the echo type is a gnomon displaying the
+ * directions of the sensor's local coordinate system axes at the location
+ * of the sensor's hotspot.
+ */
+ public static final int GNOMON = 23 ;
+
+ /**
+ * Indicates that the echo type is a beam extending from the
+ * origin of the sensor's local coordinate system to its hotspot.
+ */
+ public static final int BEAM = 24 ;
+
+ /**
+ * Indicates that a button listener or read listener has not been
+ * set for a particular target. This allows this behavior to use that
+ * target for a default listener.
+ */
+ private static final int UNSET = -1 ;
+
+ private View view = null ;
+ private SensorEventAgent eventAgent = null ;
+ private String sensor6DName = null ;
+ private String sensor2DName = null ;
+ private Shape3D echoGeometry = null ;
+ private BranchGroup echoBranchGroup = null ;
+ private TransformGroup echoTransformGroup = null ;
+ private SensorReadListener echoReadListener6D = null ;
+ private boolean echoBranchGroupAttached = false ;
+ private WakeupCondition wakeupConditions = new WakeupOnElapsedFrames(0) ;
+ private boolean configured = false ;
+
+ // The rest of these private fields are all configurable through
+ // ConfiguredUniverse.
+ private Sensor sensor6D = null ;
+ private Sensor sensor2D = null ;
+ private int x2D = 3 ;
+ private int y2D = 7 ;
+ private double threshold2D = 0.0 ;
+
+ private int readAction6D = UNSET ;
+ private int readAction2D = UNSET ;
+
+ private ArrayList buttonActions6D = new ArrayList() ;
+ private ArrayList buttonActions2D = new ArrayList() ;
+
+ private double translationSpeed = 0.1 ;
+ private int translationUnits = PHYSICAL_METERS ;
+ private int translationTimeBase = PER_SECOND ;
+ private double accelerationTime = 1.0 ;
+ private double constantSpeedTime = 8.0 ;
+ private double fastSpeedFactor = 10.0 ;
+
+ private double rotationSpeed = 180.0 ;
+ private int rotationUnits = DEGREES ;
+ private int rotationTimeBase = PER_SECOND ;
+ private int rotationCoords = SENSOR ;
+
+ private double scaleSpeed = 2.0 ;
+ private int scaleTimeBase = PER_SECOND ;
+
+ private int transformCenterSource = HOTSPOT ;
+ private Point3d transformCenter = new Point3d(0.0, 0.0, 0.0) ;
+
+ private int resetViewButtonCount6D = 3 ;
+ private int resetViewButtonCount2D = NONE ;
+
+ private int echoType = GNOMON ;
+ private double echoSize = 0.01 ;
+ private Color3f echoColor = null ;
+ private float echoTransparency = 0.0f ;
+ private Transform3D nominalSensorRotation = null ;
+
+ /**
+ * Parameterless constructor for this behavior. This is called when this
+ * behavior is instantiated from a configuration file.
+ *
(NewViewPlatformBehavior <name>
+ * org.jogamp.java3d.utils.behaviors.vp.WandViewBehavior)
+ */
+ public WandViewBehavior() {
+ // Create an event agent.
+ eventAgent = new SensorEventAgent(this) ;
+
+ // Set a default SchedulingBounds.
+ setSchedulingBounds(new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
+ Double.POSITIVE_INFINITY)) ;
+ }
+
+ /**
+ * Creates a new instance with the specified sensors and echo parameters.
+ * At least one sensor must be non-null
.
+ * SimpleUniverse
or ConfiguredUniverse
is used
+ * to set up the view side of the scene graph, or if it is otherwise to be
+ * attached to a ViewingPlatform
. If this behavior is not
+ * instantiated from a configuration file then it must then be explicitly
+ * attached to a ViewingPlatform
instance with the
+ * ViewingPlatform.setViewPlatformBehavior
method.
+ *
+ * @param sensor6D a six degree of freedom sensor which generates reads
+ * relative to the tracker base in physical units; may be
+ * null
+ * @param sensor2D 2D valuator which generates X and Y reads ranging from
+ * [-1.0 .. +1.0]; may be null
+ * @param echoType either GNOMON
, BEAM
, or
+ * NONE
for the 6DOF sensor echo
+ * @param echoSize the width of the 6DOF sensor echo in physical meters;
+ * ignored if echoType is NONE
+ */
+ public WandViewBehavior(Sensor sensor6D, Sensor sensor2D,
+ int echoType, double echoSize) {
+ this() ;
+ this.sensor6D = sensor6D ;
+ this.sensor2D = sensor2D ;
+ this.echoType = echoType ;
+ this.echoSize = echoSize ;
+ }
+
+ /**
+ * Creates a new instance with the specified sensors and a 6DOF sensor
+ * echo parented by the specified TransformGroup
. At least
+ * one sensor must be non-null
.
+ * SimpleUniverse
or ConfiguredUniverse
is used
+ * to set up the view side of the scene graph, or if it is otherwise to be
+ * attached to a ViewingPlatform
. If this behavior is not
+ * instantiated from a configuration file then it must then be explicitly
+ * attached to a ViewingPlatform
instance with the
+ * ViewingPlatform.setViewPlatformBehavior
method.
+ * TransformGroup
is non-null
, it
+ * will be added to a new BranchGroup
and attached to the
+ * ViewingPlatform
, where its transform will be updated in
+ * response to the sensor reads. Capabilities to allow writing its
+ * transform and to read, write, and extend its children will be set. The
+ * echo geometry is assumed to incorporate the position and orientation of
+ * the 6DOF sensor hotspot.
+ *
+ * @param sensor6D a six degree of freedom sensor which generates reads
+ * relative to the tracker base in physical units; may be
+ * null
+ * @param sensor2D 2D valuator which generates X and Y reads ranging from
+ * [-1.0 .. +1.0]; may be null
+ * @param echo a TransformGroup
containing the visible echo
+ * which will track the 6DOF sensor's position and orientation, or
+ * null
for no echo
+ */
+ public WandViewBehavior(Sensor sensor6D, Sensor sensor2D,
+ TransformGroup echo) {
+ this() ;
+ this.sensor6D = sensor6D ;
+ this.sensor2D = sensor2D ;
+ if (echo != null) {
+ echo.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE) ;
+ echo.setCapability(Group.ALLOW_CHILDREN_READ) ;
+ echo.setCapability(Group.ALLOW_CHILDREN_WRITE) ;
+ echo.setCapability(Group.ALLOW_CHILDREN_EXTEND) ;
+ }
+ this.echoTransformGroup = echo ;
+ }
+
+ /**
+ * Creates a new instance with the specified sensors and a 6DOF sensor
+ * echo parented by the specified TransformGroup
. At least
+ * one sensor must be non-null
.
+ * SimpleUniverse
or
+ * ConfiguredUniverse
is not used to set up the view
+ * side of the scene graph. The application must set up the view side
+ * itself and supply references to the View
and the
+ * TransformGroup
containing the view platform transform.
+ * ViewingPlatform.setViewPlatformBehavior
must not
+ * be called, and this behavior must be explicitly added to the virtual
+ * universe by the application.
+ * TransformGroup
is non-null
, it
+ * will only be used to update its associated transform with the position
+ * and orientation of a 6DOF sensor (if supplied). The application is
+ * responsible for adding the echo to the virtual universe. The echo
+ * geometry is assumed to incorporate the position and orientation of the
+ * 6DOF sensor hotspot.
+ *
+ * @param sensor6D a six degree of freedom sensor which generates reads
+ * relative to the tracker base in physical units; may be
+ * null
+ * @param sensor2D 2D valuator which generates X and Y reads ranging from
+ * [-1.0 .. +1.0]; may be null
+ * @param view a reference to the View
attached to the
+ * ViewPlatform
to be manipulated by this behavior
+ * @param viewTransform a TransformGroup
containing the view
+ * platform transform; appropriate capabilities to update the transform
+ * must be set
+ * @param homeTransform a Transform3D
containing the
+ * view transform to be used when the view is reset; may be
+ * null
for identity
+ * @param echo a TransformGroup
containing the visible echo
+ * which will track the 6DOF sensor's position and orientation, or
+ * null
for no echo; appropriate capabilities to update the
+ * transform must be set
+ */
+ public WandViewBehavior(Sensor sensor6D, Sensor sensor2D,
+ View view, TransformGroup viewTransform,
+ Transform3D homeTransform, TransformGroup echo) {
+ this() ;
+ this.sensor6D = sensor6D ;
+ this.sensor2D = sensor2D ;
+ this.view = view ;
+ this.targetTG = viewTransform ;
+ this.echoTransformGroup = echo ;
+
+ if (homeTransform == null)
+ setHomeTransform(new Transform3D()) ;
+ else
+ setHomeTransform(homeTransform) ;
+ }
+
+ /**
+ * Initializes and configures this behavior.
+ * NOTE: Applications should not call this method. It is called by
+ * the Java 3D behavior scheduler.
+ */
+ @Override
+ public void initialize() {
+ // Don't configure the sensors and echo after the first time.
+ if (!configured) {
+ configureSensorActions() ;
+
+ // Configure an echo only if a ViewingPlatform is in use.
+ if (vp != null) {
+ if (echoTransformGroup == null &&
+ sensor6D != null && readAction6D == ECHO) {
+ configureEcho() ;
+ }
+ if (echoTransformGroup != null) {
+ echoBranchGroup = new BranchGroup() ;
+ echoBranchGroup.setCapability
+ (BranchGroup.ALLOW_DETACH) ;
+ echoBranchGroup.setCapability
+ (BranchGroup.ALLOW_CHILDREN_READ) ;
+ echoBranchGroup.setCapability
+ (BranchGroup.ALLOW_CHILDREN_WRITE) ;
+
+ echoBranchGroup.addChild(echoTransformGroup) ;
+ echoBranchGroup.compile() ;
+ }
+ attachEcho() ;
+ }
+ configured = true ;
+ }
+ wakeupOn(wakeupConditions) ;
+ }
+
+ /**
+ * Processes a stimulus meant for this behavior.
+ * NOTE: Applications should not call this method. It is called by
+ * the Java 3D behavior scheduler.
+ */
+ @Override
+ public void processStimulus(Enumeration criteria) {
+ // Invoke the sensor event dispatcher.
+ eventAgent.dispatchEvents() ;
+
+ // Wake up on the next frame.
+ wakeupOn(wakeupConditions) ;
+ }
+
+ /**
+ * Enables or disables this behavior. The default state is enabled.
+ * @param enable true or false to enable or disable this behavior
+ */
+ @Override
+ public void setEnable(boolean enable) {
+ if (enable == getEnable()) {
+ return ;
+ }
+ else if (enable) {
+ attachEcho() ;
+ }
+ else {
+ detachEcho() ;
+ }
+ super.setEnable(enable) ;
+ }
+
+ /**
+ * Sets the ViewingPlatform
for this behavior. If a subclass
+ * overrides this method, it must call
+ * super.setViewingPlatform(vp)
. NOTE: Applications should
+ * not call this method. It is called by the
+ * ViewingPlatform
.
+ */
+ @Override
+ public void setViewingPlatform(ViewingPlatform vp) {
+ super.setViewingPlatform(vp) ;
+ if (vp == null) {
+ detachEcho() ;
+ return ;
+ }
+
+ Viewer[] viewers = vp.getViewers() ;
+ if (viewers != null) {
+ // Get the View from the first Viewer attached to the
+ // ViewingPlatform. Multiple Viewers are not supported.
+ if (viewers.length != 0 && viewers[0] != null)
+ view = viewers[0].getView() ;
+
+ if (viewers.length > 1)
+ throw new RuntimeException("multiple Viewers not supported") ;
+ }
+ if (view == null) {
+ // Fallback to the first View attached to a live ViewPlatform.
+ view = getView() ;
+ }
+ if (view == null) {
+ // This behavior requires a view. Bail.
+ throw new RuntimeException("a view is not available") ;
+ }
+
+ // Get the top-most TransformGroup in the ViewingPlatform.
+ // ViewPlatformBehavior retrieves the bottom-most which won't work
+ // if there are multiple TransformGroups.
+ targetTG = vp.getMultiTransformGroup().getTransformGroup(0) ;
+
+ // Should be an API for checking if homeTransform is null.
+ if (homeTransform == null)
+ setHomeTransform(new Transform3D()) ;
+
+ attachEcho() ;
+ }
+
+ /**
+ * Attaches the echo BranchGroup to the ViewingPlatform if appropriate.
+ */
+ private void attachEcho() {
+ if (vp != null &&
+ echoBranchGroup != null && !echoBranchGroupAttached) {
+ vp.addChild(echoBranchGroup) ;
+ echoBranchGroupAttached = true ;
+ }
+ }
+
+ /**
+ * Detaches the echo BranchGroup from the ViewingPlatform if appropriate.
+ */
+ private void detachEcho() {
+ if (echoBranchGroup != null && echoBranchGroupAttached) {
+ echoBranchGroup.detach() ;
+ echoBranchGroupAttached = false ;
+ }
+ }
+
+ /**
+ * Creates the sensor listeners for a 6DOF sensor and/or a 2D valuator
+ * sensor using the predefined button and read listeners and the
+ * configured action bindings.
+ * initialize
is called. This
+ * method can be overridden by subclasses to modify the configured
+ * bindings or introduce other configuration parameters.
+ */
+ protected void configureSensorActions() {
+ SensorButtonListener[] sbls ;
+ int buttonCount, buttonActionCount ;
+
+ SimpleUniverse universe = null ;
+ if (vp != null) universe = vp.getUniverse() ;
+ if (universe != null && universe instanceof ConfiguredUniverse) {
+ // Check if sensors were instantiated from a config file.
+ Map sensorMap = ((ConfiguredUniverse)universe).getNamedSensors() ;
+
+ if (sensor2D == null && sensor2DName != null) {
+ sensor2D = (Sensor)sensorMap.get(sensor2DName) ;
+ if (sensor2D == null)
+ throw new IllegalArgumentException
+ ("\nsensor " + sensor2DName + " not found") ;
+ }
+
+ if (sensor6D == null && sensor6DName != null) {
+ sensor6D = (Sensor)sensorMap.get(sensor6DName) ;
+ if (sensor6D == null)
+ throw new IllegalArgumentException
+ ("\nsensor " + sensor6DName + " not found") ;
+ }
+ }
+
+ if (sensor6D != null) {
+ // Assign default read action.
+ if (readAction6D == UNSET)
+ readAction6D = ECHO ;
+
+ // Register the read listener.
+ if (readAction6D == ECHO) {
+ echoReadListener6D = new EchoReadListener6D() ;
+ eventAgent.addSensorReadListener
+ (sensor6D, echoReadListener6D) ;
+ }
+
+ // Check for button range.
+ buttonCount = sensor6D.getSensorButtonCount() ;
+ buttonActionCount = buttonActions6D.size() ;
+ if (buttonActionCount > buttonCount)
+ throw new IllegalArgumentException
+ ("\nbutton index " + (buttonActionCount-1) +
+ " >= number of buttons (" + buttonCount +")") ;
+
+ // Assign default button actions.
+ if (buttonCount > 2 &&
+ (buttonActionCount < 3 || buttonActions6D.get(2) == null))
+ setButtonAction6D(2, TRANSLATE_BACKWARD) ;
+ if (buttonCount > 1 &&
+ (buttonActionCount < 2 || buttonActions6D.get(1) == null))
+ setButtonAction6D(1, TRANSLATE_FORWARD) ;
+ if (buttonCount > 0 &&
+ (buttonActionCount < 1 || buttonActions6D.get(0) == null))
+ setButtonAction6D(0, GRAB_VIEW) ;
+
+ buttonActionCount = buttonActions6D.size() ;
+ if (buttonActionCount > 0) {
+ // Set up the button listener array.
+ sbls = new SensorButtonListener[buttonCount] ;
+ for (int i = 0 ; i < buttonActionCount ; i++) {
+ Integer button = (Integer)buttonActions6D.get(i) ;
+ if (button != null) {
+ int action = button.intValue() ;
+ if (action == NONE)
+ sbls[i] = null ;
+ else if (action == GRAB_VIEW)
+ sbls[i] = new GrabViewListener6D() ;
+ else if (action == TRANSLATE_FORWARD)
+ sbls[i] = new TranslationListener6D(false) ;
+ else if (action == TRANSLATE_BACKWARD)
+ sbls[i] = new TranslationListener6D(true) ;
+ else if (action == ROTATE_CCW)
+ sbls[i] = new RotationListener6D(false) ;
+ else if (action == ROTATE_CW)
+ sbls[i] = new RotationListener6D(true) ;
+ else if (action == SCALE_UP)
+ sbls[i] = new ScaleListener6D(false) ;
+ else if (action == SCALE_DOWN)
+ sbls[i] = new ScaleListener6D(true) ;
+ }
+ }
+ // Register the button listeners.
+ eventAgent.addSensorButtonListeners(sensor6D, sbls) ;
+ }
+
+ // Check for reset view action.
+ if (resetViewButtonCount6D != NONE) {
+ SensorInputAdaptor r =
+ new ResetViewListener(sensor6D, resetViewButtonCount6D) ;
+ eventAgent.addSensorButtonListener(sensor6D, r) ;
+ eventAgent.addSensorReadListener(sensor6D, r) ;
+ }
+ }
+
+ if (sensor2D != null) {
+ // Assign default read action
+ if (readAction2D == UNSET)
+ readAction2D = ROTATION ;
+
+ // Register the read listener.
+ if (readAction2D == ROTATION) {
+ SensorReadListener r =
+ new RotationListener2D(sensor2D, sensor6D) ;
+ eventAgent.addSensorReadListener(sensor2D, r) ;
+ }
+ else if (readAction2D == TRANSLATION) {
+ SensorReadListener r =
+ new TranslationListener2D(sensor2D, sensor6D) ;
+ eventAgent.addSensorReadListener(sensor2D, r) ;
+ }
+ else if (readAction2D == SCALE) {
+ SensorReadListener r =
+ new ScaleListener2D(sensor2D, sensor6D) ;
+ eventAgent.addSensorReadListener(sensor2D, r) ;
+ }
+
+ // Check for button range.
+ buttonCount = sensor2D.getSensorButtonCount() ;
+ buttonActionCount = buttonActions2D.size() ;
+ if (buttonActionCount > buttonCount)
+ throw new IllegalArgumentException
+ ("\nbutton index " + (buttonActionCount-1) +
+ " >= number of buttons (" + buttonCount +")") ;
+
+ // No default button actions are defined for the 2D sensor.
+ if (buttonActionCount > 0) {
+ // Set up the button listener array.
+ sbls = new SensorButtonListener[buttonCount] ;
+ for (int i = 0 ; i < buttonActionCount ; i++) {
+ Integer button = (Integer)buttonActions2D.get(i) ;
+ if (button != null) {
+ int action = button.intValue() ;
+ if (action == NONE)
+ sbls[i] = null ;
+ else if (action == ROTATION)
+ sbls[i] = new RotationListener2D
+ (sensor2D, sensor6D) ;
+ else if (action == TRANSLATION)
+ sbls[i] = new TranslationListener2D
+ (sensor2D, sensor6D) ;
+ else if (action == SCALE)
+ sbls[i] = new ScaleListener2D
+ (sensor2D, sensor6D) ;
+ }
+ }
+ // Register the button listeners.
+ eventAgent.addSensorButtonListeners(sensor2D, sbls) ;
+ }
+
+ // Check for reset view action.
+ if (resetViewButtonCount2D != NONE) {
+ SensorInputAdaptor r =
+ new ResetViewListener(sensor2D, resetViewButtonCount2D) ;
+ eventAgent.addSensorButtonListener(sensor2D, r) ;
+ eventAgent.addSensorReadListener(sensor2D, r) ;
+ }
+ }
+ }
+
+ /**
+ * Creates a 6DOF sensor echo according to configuration parameters. This
+ * is done only if a 6DOF sensor has been specified, the 6DOF sensor read
+ * action has been set to echo the sensor position, the echo transform
+ * group has not already been set, and a ViewingPlatform is in use. This
+ * is invoked the first time initialize
is called to set this
+ * behavior live, but before the echo transform group is added to a
+ * BranchGroup
and made live. This method can be overridden
+ * to support other echo geometry.
+ */
+ protected void configureEcho() {
+ Point3d hotspot = new Point3d() ;
+ sensor6D.getHotspot(hotspot) ;
+
+ if (echoType == GNOMON) {
+ Transform3D gnomonTransform = new Transform3D() ;
+ if (nominalSensorRotation != null) {
+ gnomonTransform.set(nominalSensorRotation) ;
+ gnomonTransform.invert() ;
+ }
+ gnomonTransform.setTranslation(new Vector3d(hotspot)) ;
+ echoGeometry = new SensorGnomonEcho
+ (gnomonTransform, 0.1 * echoSize, 0.5 * echoSize, true) ;
+ }
+ else if (echoType == BEAM) {
+ echoGeometry = new SensorBeamEcho(hotspot, echoSize, true) ;
+ }
+
+ if (echoGeometry != null) {
+ Appearance a = echoGeometry.getAppearance() ;
+ if (echoColor != null) {
+ Material m = a.getMaterial() ;
+ m.setDiffuseColor(echoColor) ;
+ }
+ if (echoTransparency != 0.0f) {
+ TransparencyAttributes ta = a.getTransparencyAttributes() ;
+ ta.setTransparencyMode(TransparencyAttributes.BLENDED) ;
+ ta.setTransparency(echoTransparency) ;
+ // Use order independent additive blend for gnomon.
+ if (echoGeometry instanceof SensorGnomonEcho)
+ ta.setDstBlendFunction(TransparencyAttributes.BLEND_ONE) ;
+ }
+ echoTransformGroup = new TransformGroup() ;
+ echoTransformGroup.setCapability
+ (TransformGroup.ALLOW_TRANSFORM_WRITE) ;
+ echoTransformGroup.setCapability(Group.ALLOW_CHILDREN_READ) ;
+ echoTransformGroup.setCapability(Group.ALLOW_CHILDREN_WRITE) ;
+ echoTransformGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND) ;
+ echoTransformGroup.addChild(echoGeometry) ;
+ }
+ }
+
+ /**
+ * A base class for implementing some of this behavior's listeners.
+ */
+ public class ListenerBase extends SensorInputAdaptor {
+ /**
+ * The initial transform from view platform coordinates to virtual
+ * world coordinates, set by initAction
.
+ */
+ protected Transform3D viewPlatformToVworld = new Transform3D() ;
+
+ /**
+ * The initial transform from tracker base coordinates to virtual
+ * world coordinates, set by initAction
.
+ */
+ protected Transform3D trackerToVworld = new Transform3D() ;
+
+ /**
+ * The initial transform from sensor coordinates to virtual
+ * world coordinates, set by initAction
.
+ */
+ protected Transform3D sensorToVworld = new Transform3D() ;
+
+ /**
+ * The initial transform from sensor coordinates to tracker base
+ * coordinates, set by initAction
.
+ */
+ protected Transform3D sensorToTracker = new Transform3D() ;
+
+ // Private fields.
+ private Transform3D trackerToSensor = new Transform3D() ;
+ private boolean active = false ;
+
+ // Misc. temporary objects.
+ private double[] s3Tmp = new double[3] ;
+ private double[] m16Tmp = new double[16] ;
+ private Vector3d v3dTmp = new Vector3d() ;
+ private Transform3D t3dTmp = new Transform3D() ;
+
+ /**
+ * Initializes the listener action. Subclasses must call this before
+ * starting the action, either from pressed
or when a 2D
+ * valuator exits the deadzone threshold.
+ *
+ * @param s reference to a 6DOF sensor if used by the listener; may
+ * be null
+ */
+ protected void initAction(Sensor s) {
+ targetTG.getTransform(viewPlatformToVworld) ;
+ active = true ;
+ if (s == null) return ;
+
+ // Kludge to get the static trackerToVworld for this
+ // frame. This is computed from the two separate sensor reads
+ // below, which are close enough to identical to work. The
+ // Java 3D View class needs a getTrackerBaseToVworld() method
+ // (see Java 3D RFE 4676808).
+ s.getRead(sensorToTracker) ;
+ view.getSensorToVworld(s, sensorToVworld) ;
+
+ trackerToSensor.invert(sensorToTracker) ;
+ trackerToVworld.mul(sensorToVworld, trackerToSensor) ;
+ }
+
+ /**
+ * Ends the action. Subclasses must be call this from
+ * released
or when a 2D valuator enters the deadzone
+ * threshold.
+ *
+ * @param s reference to a 6DOF sensor if used by the listener; may
+ * be null
+ */
+ protected void endAction(Sensor s) {
+ active = false ;
+ }
+
+ /**
+ * Returns true if the listener is currently active; that is, if
+ * initAction
has been called but not yet
+ * endAction
.
+ *
+ * @return true if the listener is active, false otherwise
+ */
+ protected boolean isActive() {
+ return active ;
+ }
+
+ @Override
+ public void pressed(SensorEvent e) {
+ initAction(e.getSensor()) ;
+ }
+
+ @Override
+ public void released(SensorEvent e) {
+ endAction(e.getSensor()) ;
+ }
+
+ /**
+ * Gets the physical to virtual scale.
+ */
+ protected double getPhysicalToVirtualScale() {
+ view.getCanvas3D(0).getImagePlateToVworld(t3dTmp) ;
+ t3dTmp.get(m16Tmp) ;
+ return Math.sqrt(m16Tmp[0]*m16Tmp[0] +
+ m16Tmp[1]*m16Tmp[1] +
+ m16Tmp[2]*m16Tmp[2]) ;
+ }
+
+ /**
+ * Gets the scale from physical units to view platform units.
+ */
+ protected double getPhysicalToViewPlatformScale() {
+ double vpToVirtualScale ;
+
+ targetTG.getTransform(t3dTmp) ;
+ t3dTmp.get(m16Tmp) ;
+ vpToVirtualScale = Math.sqrt(m16Tmp[0]*m16Tmp[0] +
+ m16Tmp[1]*m16Tmp[1] +
+ m16Tmp[2]*m16Tmp[2]) ;
+
+ return getPhysicalToVirtualScale() / vpToVirtualScale ;
+ }
+
+ /**
+ * Translates a coordinate system.
+ *
+ * @param transform the coordinate system to be translated
+ * @param translation the vector by which to translate
+ */
+ protected void translateTransform(Transform3D transform,
+ Vector3d translation) {
+ transform.get(v3dTmp) ;
+ v3dTmp.add(translation) ;
+ transform.setTranslation(v3dTmp) ;
+ }
+
+ /**
+ * Transforms the target coordinate system about a center point.
+ * This can be used for rotation and scaling.
+ *
+ * @param target the coordinate system to transform
+ * @param center the center point about which to transform
+ * @param transform the transform to apply
+ */
+ protected void transformAboutCenter
+ (Transform3D target, Point3d center, Transform3D transform) {
+
+ // Translate to the center.
+ target.get(v3dTmp) ;
+ v3dTmp.sub(center) ;
+ target.setTranslation(v3dTmp) ;
+
+ // Apply the transform.
+ target.mul(transform, target) ;
+
+ // Translate back.
+ target.get(v3dTmp) ;
+ v3dTmp.add(center) ;
+ target.setTranslation(v3dTmp) ;
+ }
+
+ /**
+ * Equalizes the scale factors in the view tranform, which must be
+ * congruent. If successful, the ViewingPlatform
+ * TransformGroup
is updated; otherwise, its transform is reset
+ * to the home transform. This should be called if multiple
+ * incremental scale factors are applied to the view transform.
+ *
+ * @param viewPlatformToVworld the view transform
+ */
+ protected void conditionViewScale(Transform3D viewPlatformToVworld) {
+ viewPlatformToVworld.normalize() ;
+ viewPlatformToVworld.get(m16Tmp) ;
+
+ s3Tmp[0] = m16Tmp[0]*m16Tmp[0] +
+ m16Tmp[4]*m16Tmp[4] + m16Tmp[8]*m16Tmp[8] ;
+ s3Tmp[1] = m16Tmp[1]*m16Tmp[1] +
+ m16Tmp[5]*m16Tmp[5] + m16Tmp[9]*m16Tmp[9] ;
+ s3Tmp[2] = m16Tmp[2]*m16Tmp[2] +
+ m16Tmp[6]*m16Tmp[6] + m16Tmp[10]*m16Tmp[10] ;
+
+ if (s3Tmp[0] == s3Tmp[1] && s3Tmp[0] == s3Tmp[2])
+ return ;
+
+ s3Tmp[0] = Math.sqrt(s3Tmp[0]) ;
+ s3Tmp[1] = Math.sqrt(s3Tmp[1]) ;
+ s3Tmp[2] = Math.sqrt(s3Tmp[2]) ;
+
+ int closestToOne = 0 ;
+ if (Math.abs(s3Tmp[1] - 1.0) < Math.abs(s3Tmp[0] - 1.0))
+ closestToOne = 1 ;
+ if (Math.abs(s3Tmp[2] - 1.0) < Math.abs(s3Tmp[closestToOne] - 1.0))
+ closestToOne = 2 ;
+
+ double scale ;
+ for (int i = 0 ; i < 3 ; i++) {
+ if (i == closestToOne) continue ;
+ scale = s3Tmp[closestToOne] / s3Tmp[i] ;
+ m16Tmp[i+0] *= scale ;
+ m16Tmp[i+4] *= scale ;
+ m16Tmp[i+8] *= scale ;
+ }
+
+ // Set the view transform and bail out if unsuccessful.
+ viewPlatformToVworld.set(m16Tmp) ;
+ if ((viewPlatformToVworld.getType() & Transform3D.CONGRUENT) == 0)
+ goHome() ;
+ else
+ targetTG.setTransform(viewPlatformToVworld) ;
+ }
+ }
+
+ /**
+ * Implements a 6DOF sensor button listener to directly manipulate the
+ * view platform transform. The view platform moves in inverse response
+ * to the sensor's position and orientation to give the effect of
+ * attaching the virtual world to the sensor's echo.
+ * @see #setButtonAction6D
+ */
+ public class GrabViewListener6D extends ListenerBase {
+ private Transform3D t3d = new Transform3D() ;
+ private Transform3D initialVworldToSensor = new Transform3D() ;
+
+ @Override
+ public void pressed(SensorEvent e) {
+ initAction(e.getSensor()) ;
+
+ // Save the inverse of the initial sensorToVworld.
+ initialVworldToSensor.invert(sensorToVworld) ;
+ }
+
+ @Override
+ public void dragged(SensorEvent e) {
+ // Get sensor read relative to the static view at the time of the
+ // button-down.
+ Sensor s = e.getSensor() ;
+ s.getRead(sensorToTracker) ;
+ sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
+
+ // Solve for T, where T x initialSensorToVworld = sensorToVworld
+ t3d.mul(sensorToVworld, initialVworldToSensor) ;
+
+ // Move T to the view side by inverting it, and then applying it
+ // to the static view transform.
+ t3d.invert() ;
+ t3d.mul(viewPlatformToVworld) ;
+ targetTG.setTransform(t3d) ;
+ }
+ }
+
+ /**
+ * Implements a 6DOF sensor button listener that translates the view
+ * platform along the direction the sensor is pointing.
+ * @see #setButtonAction6D
+ * @see #setTranslationSpeed
+ * @see #setAccelerationTime
+ * @see #setConstantSpeedTime
+ * @see #setFastSpeedFactor
+ */
+ public class TranslationListener6D extends ListenerBase {
+ private long buttonDownTime ;
+ private double speedScaled ;
+ private double interval0 ;
+ private double interval1 ;
+ private double interval2 ;
+ private Vector3d v3d = new Vector3d() ;
+
+ /**
+ * Construct a new translation button listener for a 6DOF sensor.
+ *
+ * @param reverse if true, translate the view platform backwards;
+ * otherwise, translate the view platform forwards
+ */
+ public TranslationListener6D(boolean reverse) {
+ // Compute translation speed intervals.
+ interval0 = accelerationTime ;
+ interval1 = interval0 + constantSpeedTime ;
+ interval2 = interval1 + accelerationTime ;
+
+ // Apply virtual to physical scale if needed.
+ if (translationUnits == VIRTUAL_UNITS)
+ speedScaled = translationSpeed / getPhysicalToVirtualScale() ;
+ else
+ speedScaled = translationSpeed ;
+
+ if (reverse) {
+ speedScaled = -speedScaled ;
+ }
+ }
+
+ @Override
+ public void pressed(SensorEvent e) {
+ initAction(e.getSensor()) ;
+ buttonDownTime = e.getTime() ;
+ }
+
+ @Override
+ public void dragged(SensorEvent e) {
+ long time = e.getTime() ;
+ long lastTime = e.getLastTime() ;
+ double currSpeed, transTime ;
+ double frameTime = 1.0 ;
+ if (translationTimeBase == PER_SECOND)
+ frameTime = (time - lastTime) / 1e9 ;
+
+ // Compute speed based on acceleration intervals.
+ transTime = (time - buttonDownTime) / 1e9 ;
+ if (transTime <= interval0) {
+ currSpeed = (transTime / accelerationTime) * speedScaled ;
+ }
+ else if (transTime > interval1 && transTime < interval2) {
+ currSpeed = ((((transTime-interval1) / accelerationTime) *
+ (fastSpeedFactor-1.0)) + 1.0) * speedScaled ;
+ }
+ else if (transTime >= interval2) {
+ currSpeed = fastSpeedFactor * speedScaled ;
+ }
+ else {
+ currSpeed = speedScaled ;
+ }
+
+ // Transform the translation direction (0, 0, -1).
+ v3d.set(0.0, 0.0, -1.0) ;
+ if (nominalSensorRotation != null)
+ nominalSensorRotation.transform(v3d) ;
+
+ // To avoid echo frame lag, compute sensorToVworld based on
+ // computed trackerToVworld. getSensorToVworld() isn't
+ // current for this frame.
+ Sensor s = e.getSensor() ;
+ s.getRead(sensorToTracker) ;
+ sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
+ sensorToVworld.transform(v3d) ;
+
+ // Translate the view platform.
+ v3d.scale(frameTime * currSpeed) ;
+ translateTransform(viewPlatformToVworld, v3d) ;
+ targetTG.setTransform(viewPlatformToVworld) ;
+
+ // Translate trackerToVworld.
+ translateTransform(trackerToVworld, v3d) ;
+
+ if (readAction6D == ECHO) {
+ // Translate sensor echo to compensate for the new view
+ // platform movement.
+ translateTransform(sensorToVworld, v3d) ;
+ updateEcho(s, sensorToVworld) ;
+ }
+ }
+ }
+
+ /**
+ * Implements a 6DOF sensor button listener that rotates the view platform
+ * about a Y axis. This axis can be relative to the sensor, user head, or
+ * view platform. The rotation center can be the sensor hotspot or a
+ * fixed point in virtual world coordinates.
+ *
+ * @see #setButtonAction6D
+ * @see #setRotationCoords
+ * @see #setTransformCenterSource
+ * @see #setTransformCenter
+ * @see #setRotationSpeed
+ * @see #setAccelerationTime
+ */
+ public class RotationListener6D extends ListenerBase {
+ private boolean reverse ;
+ private long buttonDownTime ;
+ private Vector3d axis = new Vector3d() ;
+ private Point3d center = new Point3d() ;
+ private Transform3D t3d = new Transform3D() ;
+ private AxisAngle4d aa4d = new AxisAngle4d() ;
+ private Transform3D headToVworld = new Transform3D() ;
+ private double speedScaled ;
+
+ @Override
+ protected void initAction(Sensor s) {
+ super.initAction(s) ;
+ if (rotationCoords == HEAD) {
+ view.setUserHeadToVworldEnable(true) ;
+ }
+ }
+
+ @Override
+ protected void endAction(Sensor s) {
+ super.endAction(s) ;
+ viewPlatformToVworld.normalize() ;
+ targetTG.setTransform(viewPlatformToVworld) ;
+ if (rotationCoords == HEAD) {
+ view.setUserHeadToVworldEnable(false) ;
+ }
+ }
+
+ /**
+ * Construct a new rotation button listener for a 6DOF sensor.
+ *
+ * @param reverse if true, rotate clockwise; otherwise, rotate
+ * counter-clockwise
+ */
+ public RotationListener6D(boolean reverse) {
+ this.reverse = reverse ;
+ if (rotationUnits == DEGREES)
+ speedScaled = rotationSpeed * Math.PI / 180.0 ;
+ else
+ speedScaled = rotationSpeed ;
+ }
+
+ @Override
+ public void pressed(SensorEvent e) {
+ initAction(e.getSensor()) ;
+ buttonDownTime = e.getTime() ;
+ }
+
+ @Override
+ public void dragged(SensorEvent e) {
+ long time = e.getTime() ;
+ long lastTime = e.getLastTime() ;
+ double currSpeed, transTime ;
+ double frameTime = 1.0 ;
+ if (rotationTimeBase == PER_SECOND)
+ frameTime = (time - lastTime) / 1e9 ;
+
+ // Compute speed based on acceleration interval.
+ transTime = (time - buttonDownTime) / 1e9 ;
+ if (transTime <= accelerationTime) {
+ currSpeed = (transTime / accelerationTime) * speedScaled ;
+ }
+ else {
+ currSpeed = speedScaled ;
+ }
+
+ // Set the rotation axis.
+ if (reverse)
+ axis.set(0.0, -1.0, 0.0) ;
+ else
+ axis.set(0.0, 1.0, 0.0) ;
+
+ // To avoid echo frame lag, compute sensorToVworld based on
+ // computed trackerToVworld. getSensorToVworld() isn't current
+ // for this frame.
+ Sensor s = e.getSensor() ;
+ s.getRead(sensorToTracker) ;
+ sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
+
+ // Transform rotation axis into target coordinate system.
+ if (rotationCoords == SENSOR) {
+ if (nominalSensorRotation != null)
+ nominalSensorRotation.transform(axis) ;
+
+ sensorToVworld.transform(axis) ;
+ }
+ else if (rotationCoords == HEAD) {
+ view.getUserHeadToVworld(headToVworld) ;
+ headToVworld.transform(axis) ;
+ }
+ else {
+ viewPlatformToVworld.transform(axis) ;
+ }
+
+ // Get the rotation center.
+ if (transformCenterSource == HOTSPOT) {
+ s.getHotspot(center) ;
+ sensorToVworld.transform(center) ;
+ }
+ else {
+ center.set(transformCenter) ;
+ }
+
+ // Construct origin-based rotation about axis.
+ aa4d.set(axis, currSpeed * frameTime) ;
+ t3d.set(aa4d) ;
+
+ // Apply the rotation to the view platform.
+ transformAboutCenter(viewPlatformToVworld, center, t3d) ;
+ targetTG.setTransform(viewPlatformToVworld) ;
+
+ // Apply the rotation to trackerToVworld.
+ transformAboutCenter(trackerToVworld, center, t3d) ;
+
+ if (readAction6D == ECHO) {
+ // Transform sensor echo to compensate for the new view
+ // platform movement.
+ transformAboutCenter(sensorToVworld, center, t3d) ;
+ updateEcho(s, sensorToVworld) ;
+ }
+ }
+ }
+
+ /**
+ * Implements a 6DOF sensor button listener that scales the view platform.
+ * The center of scaling can be the sensor hotspot or a fixed location in
+ * virtual world coordinates.
+ *
+ * @see #setButtonAction6D
+ * @see #setTransformCenterSource
+ * @see #setTransformCenter
+ * @see #setScaleSpeed
+ * @see #setAccelerationTime
+ */
+ public class ScaleListener6D extends ListenerBase {
+ private double direction ;
+ private long buttonDownTime ;
+ private Point3d center = new Point3d() ;
+ private Transform3D t3d = new Transform3D() ;
+
+ @Override
+ protected void endAction(Sensor s) {
+ super.endAction(s) ;
+ conditionViewScale(viewPlatformToVworld) ;
+ }
+
+ /**
+ * Construct a new scale button listener for a 6DOF sensor.
+ *
+ * @param reverse if true, scale the view platform smaller; otherwise,
+ * scale the view platform larger
+ */
+ public ScaleListener6D(boolean reverse) {
+ if (reverse)
+ direction = -1.0 ;
+ else
+ direction = 1.0 ;
+ }
+
+ @Override
+ public void pressed(SensorEvent e) {
+ initAction(e.getSensor()) ;
+ buttonDownTime = e.getTime() ;
+ }
+
+ @Override
+ public void dragged(SensorEvent e) {
+ long time = e.getTime() ;
+ long lastTime = e.getLastTime() ;
+ double scale, exp, transTime ;
+ double frameTime = 1.0 ;
+ if (scaleTimeBase == PER_SECOND)
+ frameTime = (time - lastTime) / 1e9 ;
+
+ // Compute speed based on acceleration interval.
+ transTime = (time - buttonDownTime) / 1e9 ;
+ if (transTime <= accelerationTime) {
+ exp = (transTime / accelerationTime) * frameTime * direction ;
+ }
+ else {
+ exp = frameTime * direction ;
+ }
+ scale = Math.pow(scaleSpeed, exp) ;
+
+ // To avoid echo frame lag, compute sensorToVworld based on
+ // computed trackerToVworld. getSensorToVworld() isn't current
+ // for this frame.
+ Sensor s = e.getSensor() ;
+ s.getRead(sensorToTracker) ;
+ sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
+
+ // Get the scale center.
+ if (transformCenterSource == HOTSPOT) {
+ s.getHotspot(center) ;
+ sensorToVworld.transform(center) ;
+ }
+ else {
+ center.set(transformCenter) ;
+ }
+
+ // Apply the scale to the view platform.
+ t3d.set(scale) ;
+ transformAboutCenter(viewPlatformToVworld, center, t3d) ;
+
+ // Incremental scaling at the extremes can lead to numerical
+ // instability, so catch BadTransformException to prevent the
+ // behavior thread from being killed. Using a cumulative scale
+ // matrix avoids this problem to a better extent, but causes the
+ // 6DOF sensor hotspot center to jitter excessively.
+ try {
+ targetTG.setTransform(viewPlatformToVworld) ;
+ }
+ catch (BadTransformException bt) {
+ conditionViewScale(viewPlatformToVworld) ;
+ }
+
+ // Apply the scale to trackerToVworld.
+ transformAboutCenter(trackerToVworld, center, t3d) ;
+
+ if (readAction6D == ECHO) {
+ // Scale sensor echo to compensate for the new view
+ // platform scale.
+ transformAboutCenter(sensorToVworld, center, t3d) ;
+ updateEcho(s, sensorToVworld) ;
+ }
+ }
+ }
+
+ /**
+ * Implements a 6DOF sensor read listener that updates the orientation and
+ * position of the sensor's echo in the virtual world.
+ *
+ * @see #setEchoType
+ * @see #setEchoSize
+ * @see #setReadAction6D
+ * @see SensorGnomonEcho
+ * @see SensorBeamEcho
+ */
+ public class EchoReadListener6D implements SensorReadListener {
+ private Transform3D sensorToVworld = new Transform3D() ;
+
+ @Override
+ public void read(SensorEvent e) {
+ Sensor s = e.getSensor() ;
+ view.getSensorToVworld(s, sensorToVworld) ;
+ updateEcho(s, sensorToVworld) ;
+ }
+ }
+
+ /**
+ * Implements a 2D valuator listener that rotates the view platform. The
+ * X and Y values from the valuator should have a continuous range from
+ * -1.0 to +1.0, although the rotation speed can be scaled to compensate
+ * for a different range. The X and Y values are found in the sensor's
+ * read matrix at the indices specified by
+ * setMatrixIndices2D
, with defaults of 3 and 7 respectively.
+ * setRotationCoords
has been called with the value
+ * SENSOR
, then the rotation is applied in the 6DOF sensor's
+ * coordinate system; otherwise the rotation is applied either in head
+ * coordinates or in view platform coordinates. If a 6DOF sensor is
+ * provided and setTransformCenterSource
has been called with
+ * the value HOTSPOT
, then rotation is about the 6DOF
+ * sensor's hotspot; otherwise, the rotation center is the value set by
+ * setTransformCenter
.
+ *
+ * @see #setReadAction2D
+ * @see #setButtonAction2D
+ * @see #setRotationCoords
+ * @see #setTransformCenterSource
+ * @see #setTransformCenter
+ * @see #setRotationSpeed
+ * @see #setThreshold2D
+ * @see #setMatrixIndices2D
+ */
+ public class RotationListener2D extends ListenerBase {
+ private Sensor sensor2D, sensor6D ;
+ private double[] m = new double[16] ;
+ private Vector3d axis = new Vector3d() ;
+ private Point3d center = new Point3d() ;
+ private Transform3D t3d = new Transform3D() ;
+ private AxisAngle4d aa4d = new AxisAngle4d() ;
+ private Transform3D sensor2DRead = new Transform3D() ;
+ private Transform3D headToVworld = new Transform3D() ;
+ private double speedScaled ;
+
+ @Override
+ protected void initAction(Sensor s) {
+ super.initAction(s) ;
+ if (rotationCoords == HEAD) {
+ view.setUserHeadToVworldEnable(true) ;
+ }
+ if (s != null && readAction6D == ECHO) {
+ // Disable the 6DOF echo. It will be updated in this action.
+ eventAgent.removeSensorReadListener(s, echoReadListener6D) ;
+ }
+ }
+
+ @Override
+ protected void endAction(Sensor s) {
+ super.endAction(s) ;
+ viewPlatformToVworld.normalize() ;
+ targetTG.setTransform(viewPlatformToVworld) ;
+ if (rotationCoords == HEAD) {
+ view.setUserHeadToVworldEnable(false) ;
+ }
+ if (s != null && readAction6D == ECHO) {
+ eventAgent.addSensorReadListener(s, echoReadListener6D) ;
+ }
+ }
+
+ /**
+ * Construct an instance of this class with the specified sensors.
+ *
+ * @param sensor2D the 2D valuator whose X and Y values drive the
+ * rotation
+ * @param sensor6D the 6DOF sensor to use if the rotation coordinate
+ * system is set to SENSOR
or the rotation center source
+ * is HOTSPOT
; may be null
+ */
+ public RotationListener2D(Sensor sensor2D, Sensor sensor6D) {
+ this.sensor2D = sensor2D ;
+ this.sensor6D = sensor6D ;
+
+ if (rotationUnits == DEGREES)
+ speedScaled = rotationSpeed * Math.PI / 180.0 ;
+ else
+ speedScaled = rotationSpeed ;
+ }
+
+ @Override
+ public void read(SensorEvent e) {
+ sensor2D.getRead(sensor2DRead) ;
+ sensor2DRead.get(m) ;
+
+ if (m[x2D] > threshold2D || m[x2D] < -threshold2D ||
+ m[y2D] > threshold2D || m[y2D] < -threshold2D) {
+ // Initialize action on threshold crossing.
+ if (!isActive()) initAction(sensor6D) ;
+
+ // m[x2D] is the X valuator value and m[y2D] is the Y valuator
+ // value. Use these to construct the rotation axis.
+ double length = Math.sqrt(m[x2D]*m[x2D] + m[y2D]*m[y2D]) ;
+ double iLength = 1.0/length ;
+ axis.set(m[y2D]*iLength, -m[x2D]*iLength, 0.0) ;
+
+ if (sensor6D != null) {
+ // To avoid echo frame lag, compute sensorToVworld based
+ // on computed trackerToVworld. getSensorToVworld() isn't
+ // current for this frame.
+ sensor6D.getRead(sensorToTracker) ;
+ sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
+ }
+
+ // Transform rotation axis into target coordinate system.
+ if (sensor6D != null && rotationCoords == SENSOR) {
+ if (nominalSensorRotation != null)
+ nominalSensorRotation.transform(axis) ;
+
+ sensorToVworld.transform(axis) ;
+ }
+ else if (rotationCoords == HEAD) {
+ view.getUserHeadToVworld(headToVworld) ;
+ headToVworld.transform(axis) ;
+ }
+ else {
+ viewPlatformToVworld.transform(axis) ;
+ }
+
+ // Get the rotation center.
+ if (transformCenterSource == HOTSPOT && sensor6D != null) {
+ sensor6D.getHotspot(center) ;
+ sensorToVworld.transform(center) ;
+ }
+ else {
+ center.set(transformCenter) ;
+ }
+
+ double frameTime = 1.0 ;
+ if (rotationTimeBase == PER_SECOND)
+ frameTime = (e.getTime() - e.getLastTime()) / 1e9 ;
+
+ // Construct origin-based rotation about axis.
+ aa4d.set(axis, speedScaled * frameTime * length) ;
+ t3d.set(aa4d) ;
+
+ // Apply the rotation to the view platform.
+ transformAboutCenter(viewPlatformToVworld, center, t3d) ;
+ targetTG.setTransform(viewPlatformToVworld) ;
+
+ if (sensor6D != null) {
+ // Apply the rotation to trackerToVworld.
+ transformAboutCenter(trackerToVworld, center, t3d) ;
+ }
+
+ if (sensor6D != null && readAction6D == ECHO) {
+ // Transform sensor echo to compensate for the new view
+ // platform movement.
+ transformAboutCenter(sensorToVworld, center, t3d) ;
+ updateEcho(sensor6D, sensorToVworld) ;
+ }
+ }
+ else {
+ // Initialize action on next threshold crossing.
+ if (isActive()) endAction(sensor6D) ;
+ }
+ }
+
+ @Override
+ public void pressed(SensorEvent e) {
+ initAction(sensor6D) ;
+ }
+
+ @Override
+ public void released(SensorEvent e) {
+ if (isActive()) endAction(sensor6D) ;
+ }
+
+ @Override
+ public void dragged(SensorEvent e) {
+ read(e) ;
+ }
+ }
+
+ /**
+ * Implements a 2D valuator listener that translates the view platform.
+ * The X and Y values from the valuator should have a continuous range
+ * from -1.0 to +1.0, although the translation speed can be scaled to
+ * compensate for a different range. The X and Y values are found in the
+ * sensor's read matrix at the indices specified by
+ * setMatrixIndices2D
, with defaults of 3 and 7 respectively.
+ * null
+ */
+ public TranslationListener2D(Sensor sensor2D, Sensor sensor6D) {
+ this.sensor2D = sensor2D ;
+ this.sensor6D = sensor6D ;
+
+ // Apply virtual to physical scale if needed.
+ if (translationUnits == VIRTUAL_UNITS)
+ speedScaled = translationSpeed *
+ fastSpeedFactor / getPhysicalToVirtualScale() ;
+ else
+ speedScaled = translationSpeed * fastSpeedFactor ;
+
+ // Apply physical to view platform scale if needed.
+ if (sensor6D == null)
+ speedScaled *= getPhysicalToViewPlatformScale() ;
+ }
+
+ @Override
+ public void read(SensorEvent e) {
+ sensor2D.getRead(sensor2DRead) ;
+ sensor2DRead.get(m) ;
+
+ if (m[x2D] > threshold2D || m[x2D] < -threshold2D ||
+ m[y2D] > threshold2D || m[y2D] < -threshold2D) {
+ // Initialize action on threshold crossing.
+ if (!isActive()) initAction(sensor6D) ;
+
+ // m[x2D] is the X valuator value and m[y2D] is the Y valuator
+ // value. Use these to construct the translation vector.
+ double length = Math.sqrt(m[x2D]*m[x2D] + m[y2D]*m[y2D]) ;
+ double iLength = 1.0/length ;
+ v3d.set(m[x2D]*iLength, 0.0, -m[y2D]*iLength) ;
+
+ // Transform translation vector into target coordinate system.
+ if (sensor6D != null) {
+ if (nominalSensorRotation != null)
+ nominalSensorRotation.transform(v3d) ;
+
+ // To avoid echo frame lag, compute sensorToVworld based
+ // on computed trackerToVworld. getSensorToVworld() isn't
+ // current for this frame.
+ sensor6D.getRead(sensorToTracker) ;
+ sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
+ sensorToVworld.transform(v3d) ;
+ }
+ else {
+ viewPlatformToVworld.transform(v3d) ;
+ }
+
+ double frameTime = 1.0 ;
+ if (translationTimeBase == PER_SECOND)
+ frameTime = (e.getTime() - e.getLastTime()) / 1e9 ;
+
+ v3d.scale(frameTime * speedScaled * length) ;
+
+ // Translate the view platform.
+ translateTransform(viewPlatformToVworld, v3d) ;
+ targetTG.setTransform(viewPlatformToVworld) ;
+
+ if (sensor6D != null) {
+ // Apply the translation to trackerToVworld.
+ translateTransform(trackerToVworld, v3d) ;
+ }
+
+ if (sensor6D != null && readAction6D == ECHO) {
+ // Translate sensor echo to compensate for the new view
+ // platform movement.
+ translateTransform(sensorToVworld, v3d) ;
+ updateEcho(sensor6D, sensorToVworld) ;
+ }
+ }
+ else {
+ // Initialize action on next threshold crossing.
+ if (isActive()) endAction(sensor6D) ;
+ }
+ }
+
+ @Override
+ public void pressed(SensorEvent e) {
+ initAction(sensor6D) ;
+ }
+
+ @Override
+ public void released(SensorEvent e) {
+ if (isActive()) endAction(sensor6D) ;
+ }
+
+ @Override
+ public void dragged(SensorEvent e) {
+ read(e) ;
+ }
+ }
+
+ /**
+ * Implements a 2D valuator listener that scales the view platform.
+ * Pushing the valuator forwards gives the appearance of the virtual world
+ * increasing in size, while pushing the valuator backwards makes the
+ * virtual world appear to shrink. The X and Y values from the valuator
+ * should have a continuous range from -1.0 to +1.0, although the scale
+ * speed can be adjusted to compensate for a different range.
+ * setTransformCenterSource
has been
+ * called with the value HOTSPOT
, then scaling is about the
+ * 6DOF sensor's hotspot; otherwise, the scaling center is the value set
+ * by setTransformCenter
.
+ *
+ * @see #setReadAction2D
+ * @see #setButtonAction2D
+ * @see #setScaleSpeed
+ * @see #setTransformCenter
+ * @see #setThreshold2D
+ * @see #setMatrixIndices2D
+ */
+ public class ScaleListener2D extends ListenerBase {
+ private Sensor sensor2D, sensor6D ;
+ private double[] m = new double[16] ;
+ private Point3d center = new Point3d() ;
+ private Transform3D t3d = new Transform3D() ;
+ private Transform3D sensor2DRead = new Transform3D() ;
+
+ @Override
+ protected void initAction(Sensor s) {
+ super.initAction(s) ;
+ if (s != null && readAction6D == ECHO) {
+ // Disable the 6DOF echo. It will be updated in this action.
+ eventAgent.removeSensorReadListener(s, echoReadListener6D) ;
+ }
+ }
+
+ @Override
+ protected void endAction(Sensor s) {
+ super.endAction(s) ;
+ conditionViewScale(viewPlatformToVworld) ;
+ if (s != null && readAction6D == ECHO) {
+ // Enable the 6DOF sensor echo.
+ eventAgent.addSensorReadListener(s, echoReadListener6D) ;
+ }
+ }
+
+ /**
+ * Construct an instance of this class with the specified sensors.
+ *
+ * @param sensor2D the 2D valuator whose Y value drive the scaling
+ * @param sensor6D the 6DOF sensor to use if the rotation/scale center
+ * source is HOTSPOT
; may be null
+ */
+ public ScaleListener2D(Sensor sensor2D, Sensor sensor6D) {
+ this.sensor2D = sensor2D ;
+ this.sensor6D = sensor6D ;
+ }
+
+ @Override
+ public void read(SensorEvent e) {
+ sensor2D.getRead(sensor2DRead) ;
+ sensor2DRead.get(m) ;
+
+ if (m[y2D] > threshold2D || m[y2D] < -threshold2D) {
+ // Initialize action on threshold crossing.
+ if (!isActive()) initAction(sensor6D) ;
+
+ if (sensor6D != null) {
+ // To avoid echo frame lag, compute sensorToVworld based
+ // on computed trackerToVworld. getSensorToVworld() isn't
+ // current for this frame.
+ sensor6D.getRead(sensorToTracker) ;
+ sensorToVworld.mul(trackerToVworld, sensorToTracker) ;
+ }
+
+ // Get the scale center.
+ if (sensor6D != null && transformCenterSource == HOTSPOT) {
+ sensor6D.getHotspot(center) ;
+ sensorToVworld.transform(center) ;
+ }
+ else {
+ center.set(transformCenter) ;
+ }
+
+ // Compute incremental scale for this frame.
+ double frameTime = 1.0 ;
+ if (scaleTimeBase == PER_SECOND)
+ frameTime = (e.getTime() - e.getLastTime()) / 1e9 ;
+
+ // Map range: [-1.0 .. 0 .. 1.0] to:
+ // [scaleSpeed**frameTime .. 1 .. 1.0/(scaleSpeed**frameTime)]
+ double scale = Math.pow(scaleSpeed, (-m[y2D]*frameTime)) ;
+
+ // Apply the scale to the view platform.
+ t3d.set(scale) ;
+ transformAboutCenter(viewPlatformToVworld, center, t3d) ;
+
+ // Incremental scaling at the extremes can lead to numerical
+ // instability, so catch BadTransformException to prevent the
+ // behavior thread from being killed. Using a cumulative
+ // scale matrix avoids this problem to a better extent, but
+ // causes the 6DOF sensor hotspot center to jitter
+ // excessively.
+ try {
+ targetTG.setTransform(viewPlatformToVworld) ;
+ }
+ catch (BadTransformException bt) {
+ conditionViewScale(viewPlatformToVworld) ;
+ }
+
+ if (sensor6D != null) {
+ // Apply the scale to trackerToVworld.
+ transformAboutCenter(trackerToVworld, center, t3d) ;
+ }
+
+ if (sensor6D != null && readAction6D == ECHO) {
+ // Scale sensor echo to compensate for the new view
+ // platform scale.
+ transformAboutCenter(sensorToVworld, center, t3d) ;
+ updateEcho(sensor6D, sensorToVworld) ;
+ }
+ }
+ else {
+ // Initialize action on next threshold crossing.
+ if (isActive()) endAction(sensor6D) ;
+ }
+ }
+
+ @Override
+ public void pressed(SensorEvent e) {
+ initAction(sensor6D) ;
+ }
+
+ @Override
+ public void released(SensorEvent e) {
+ if (isActive()) endAction(sensor6D) ;
+ }
+
+ @Override
+ public void dragged(SensorEvent e) {
+ read(e) ;
+ }
+ }
+
+ /**
+ * Resets the view back to the home transform when a specified number of
+ * buttons are down simultaneously.
+ *
+ * @see #setResetViewButtonCount6D
+ * @see ViewPlatformBehavior#setHomeTransform
+ * ViewPlatformBehavior.setHomeTransform
+ */
+ public class ResetViewListener extends SensorInputAdaptor {
+ private int resetCount ;
+ private int[] buttonState = null ;
+ private boolean goHomeNextRead = false ;
+
+ /**
+ * Creates a sensor listener that resets the view when the specified
+ * number of buttons are down simultaneously.
+ *
+ * @param s the sensor to listen to
+ * @param count the number of buttons that must be down simultaneously
+ */
+ public ResetViewListener(Sensor s, int count) {
+ resetCount = count ;
+ buttonState = new int[s.getSensorButtonCount()] ;
+ }
+
+ @Override
+ public void pressed(SensorEvent e) {
+ int count = 0 ;
+ e.getButtonState(buttonState) ;
+ for (int i = 0 ; i < buttonState.length ; i++)
+ if (buttonState[i] == 1) count++ ;
+
+ if (count >= resetCount)
+ // Ineffectual to reset immediately while other listeners may
+ // be setting the view transform.
+ goHomeNextRead = true ;
+ }
+
+ @Override
+ public void read(SensorEvent e) {
+ if (goHomeNextRead) {
+ goHome() ;
+ goHomeNextRead = false ;
+ }
+ }
+ }
+
+ /**
+ * Updates the echo position and orientation. The echo is placed at the
+ * sensor hotspot position if applicable. This implementation assumes the
+ * hotspot position and orientation have been incorporated into the echo
+ * geometry.
+ *
+ * @param sensor the sensor to be echoed
+ * @param sensorToVworld transform from sensor coordinates to virtual
+ * world coordinates
+ * @see #setEchoType
+ * @see #setEchoSize
+ * @see #setReadAction6D
+ * @see SensorGnomonEcho
+ * @see SensorBeamEcho
+ */
+ protected void updateEcho(Sensor sensor, Transform3D sensorToVworld) {
+ echoTransformGroup.setTransform(sensorToVworld) ;
+ }
+
+ /**
+ * Property which sets a 6DOF sensor for manipulating the view platform.
+ * This sensor must generate 6 degree of freedom orientation and position
+ * data in physical meters relative to the sensor's tracker base.
+ * ViewingPlatform
is being used and that the
+ * sensor name can be looked up from a ConfiguredUniverse
+ * reference retrieved from ViewingPlatform.getUniverse
. The
+ * second form is preferred and accepts the Sensor reference directly.
+ *
(ViewPlatformBehaviorProperty <name>
+ * Sensor6D <sensorName>)
+ *
(ViewPlatformBehaviorProperty
+ * <name> Sensor6D (Sensor <sensorName>))
+ *
+ * @param sensor array of length 1 containing a String
or
+ * a Sensor
+ */
+ public void Sensor6D(Object[] sensor) {
+ if (sensor.length != 1)
+ throw new IllegalArgumentException
+ ("Sensor6D requires a single name or Sensor instance") ;
+
+ if (sensor[0] instanceof String)
+ sensor6DName = (String)sensor[0] ;
+ else if (sensor[0] instanceof Sensor)
+ sensor6D = (Sensor)sensor[0] ;
+ else
+ throw new IllegalArgumentException
+ ("Sensor6D must be a name or a Sensor instance") ;
+ }
+
+ /**
+ * Returns a reference to the 6DOF sensor used for manipulating the view
+ * platform.
+ *
+ * @return the 6DOF sensor
+ */
+ public Sensor getSensor6D() {
+ return sensor6D ;
+ }
+
+ /**
+ * Property which sets a 2D sensor for manipulating the view platform.
+ * This is intended to support devices which incorporate a separate 2D
+ * valuator along with the 6DOF sensor. The X and Y values from the
+ * valuator should have a continuous range from -1.0 to +1.0, although
+ * rotation, translation, and scaling speeds can be scaled to compensate
+ * for a different range. The X and Y values are found in the sensor's
+ * read matrix at the indices specified by the
+ * MatrixIndices2D
property, with defaults of 3 and 7
+ * (the X and Y translation components) respectively.
+ * ViewingPlatform
is being used and that the
+ * sensor name can be looked up from a ConfiguredUniverse
+ * reference retrieved from ViewingPlatform.getUniverse
. The
+ * second form is preferred and accepts the Sensor reference directly.
+ *
(ViewPlatformBehaviorProperty <name>
+ * Sensor2D <sensorName>)
+ *
(ViewPlatformBehaviorProperty
+ * <name> Sensor2D (Sensor <sensorName>))
+ *
+ * @param sensor array of length 1 containing a String
or
+ * a Sensor
+ */
+ public void Sensor2D(Object[] sensor) {
+ if (sensor.length != 1)
+ throw new IllegalArgumentException
+ ("Sensor2D requires a single name or Sensor instance") ;
+
+ if (sensor[0] instanceof String)
+ sensor2DName = (String)sensor[0] ;
+ else if (sensor[0] instanceof Sensor)
+ sensor2D = (Sensor)sensor[0] ;
+ else
+ throw new IllegalArgumentException
+ ("Sensor2D must be a name or a Sensor instance") ;
+ }
+
+ /**
+ * Returns a reference to the 2D valuator used for manipulating the view
+ * platform.
+ *
+ * @return the 2D valuator
+ */
+ public Sensor getSensor2D() {
+ return sensor2D ;
+ }
+
+ /**
+ * Property which sets a button action for the 6DOF sensor. The choices
+ * are TranslateForward
, TranslateBackward
,
+ * GrabView
, RotateCCW
, RotateCW
,
+ * ScaleUp
, ScaleDown
, or None
. By
+ * default, button 0 is bound to GrabView
, button 1 is bound
+ * to TranslateForward
, and button 2 is bound to
+ * TranslateBackward
. If there are fewer than three buttons
+ * available, then the default button actions with the lower button
+ * indices have precedence. A value of None
indicates that
+ * no default action is to be associated with the specified button.
+ * TranslateForward
moves the view platform forward along the
+ * direction the sensor is pointing. TranslateBackward
does
+ * the same, in the opposite direction. GrabView
directly
+ * manipulates the view by moving it in inverse response to the sensor's
+ * position and orientation. RotateCCW
and
+ * RotateCW
rotate about a Y axis, while ScaleUp
+ * and ScaleDown
scale the view platform larger and smaller.
+ * ArrayOutOfBoundsException
+ * when the behavior is initialized or attached to a
+ * ViewingPlatform
.
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * ButtonAction6D <button index>
+ * [GrabView | TranslateForward | TranslateBackward | RotateCCW |
+ * RotateCW | ScaleUp | ScaleDown | None])
+ *
+ * @param action array of length 2 containing a Double
and a
+ * String
.
+ * @see #setButtonAction6D
+ * @see #Sensor6D Sensor6D
+ * @see #TranslationSpeed TranslationSpeed
+ * @see #AccelerationTime AccelerationTime
+ * @see #ConstantSpeedTime ConstantSpeedTime
+ * @see #FastSpeedFactor FastSpeedFactor
+ * @see #RotationSpeed RotationSpeed
+ * @see #RotationCoords RotationCoords
+ * @see #ScaleSpeed ScaleSpeed
+ * @see #TransformCenterSource TransformCenterSource
+ * @see #TransformCenter TransformCenter
+ * @see GrabViewListener6D
+ * @see TranslationListener6D
+ * @see RotationListener6D
+ * @see ScaleListener6D
+ */
+ public void ButtonAction6D(Object[] action) {
+ if (! (action.length == 2 &&
+ action[0] instanceof Double && action[1] instanceof String))
+ throw new IllegalArgumentException
+ ("\nButtonAction6D must be a number and a string") ;
+
+ int button = ((Double)action[0]).intValue() ;
+ String actionString = (String)action[1] ;
+
+ if (actionString.equals("GrabView"))
+ setButtonAction6D(button, GRAB_VIEW) ;
+ else if (actionString.equals("TranslateForward"))
+ setButtonAction6D(button, TRANSLATE_FORWARD) ;
+ else if (actionString.equals("TranslateBackward"))
+ setButtonAction6D(button, TRANSLATE_BACKWARD) ;
+ else if (actionString.equals("RotateCCW"))
+ setButtonAction6D(button, ROTATE_CCW) ;
+ else if (actionString.equals("RotateCW"))
+ setButtonAction6D(button, ROTATE_CW) ;
+ else if (actionString.equals("ScaleUp"))
+ setButtonAction6D(button, SCALE_UP) ;
+ else if (actionString.equals("ScaleDown"))
+ setButtonAction6D(button, SCALE_DOWN) ;
+ else if (actionString.equals("None"))
+ setButtonAction6D(button, NONE) ;
+ else
+ throw new IllegalArgumentException
+ ("\nButtonAction6D must be GrabView, TranslateForward, " +
+ "TranslateBackward, RotateCCW, RotateCW, ScaleUp, " +
+ "ScaleDown, or None") ;
+ }
+
+ /**
+ * Sets a button action for the 6DOF sensor. The choices are
+ * TRANSLATE_FORWARD
, TRANSLATE_BACKWARD
,
+ * GRAB_VIEW
, ROTATE_CCW
,
+ * ROTATE_CW
, SCALE_UP
, SCALE_DOWN
,
+ * or NONE
. By default, button 0 is bound to
+ * GRAB_VIEW
, button 1 is bound to
+ * TRANSLATE_FORWARD
, and button 2 is bound to
+ * TRANSLATE_BACKWARD
. If there are fewer than three buttons
+ * available, then the default button actions with the lower button
+ * indices have precedence. A value of NONE
indicates that
+ * no default action is to be associated with the specified button.
+ * TRANSLATE_FORWARD
moves the view platform forward along
+ * the direction the sensor is pointing. TRANSLATE_BACKWARD
+ * does the same, in the opposite direction. GRAB_VIEW
+ * directly manipulates the view by moving it in inverse response to the
+ * sensor's position and orientation. ROTATE_CCW
and
+ * ROTATE_CW
rotate about a Y axis, while
+ * SCALE_UP
and SCALE_DOWN
scale the view
+ * platform larger and smaller.
+ * ArrayOutOfBoundsException
+ * when the behavior is initialized or attached to a
+ * ViewingPlatform
.
+ * SensorEventAgent
used by this behavior directly.
+ *
+ * @param button index of the button to bind
+ * @param action either TRANSLATE_FORWARD
,
+ * TRANSLATE_BACKWARD
, GRAB_VIEW
,
+ * ROTATE_CCW
, ROTATE_CW
,
+ * ,
SCALE_UPSCALE_DOWN
, or NONE
+ * @see #setTranslationSpeed
+ * @see #setAccelerationTime
+ * @see #setConstantSpeedTime
+ * @see #setFastSpeedFactor
+ * @see #setRotationSpeed
+ * @see #setRotationCoords
+ * @see #setScaleSpeed
+ * @see #setTransformCenterSource
+ * @see #setTransformCenter
+ * @see #getSensorEventAgent
+ * @see GrabViewListener6D
+ * @see TranslationListener6D
+ * @see RotationListener6D
+ * @see ScaleListener6D
+ */
+ public synchronized void setButtonAction6D(int button, int action) {
+ if (! (action == TRANSLATE_FORWARD || action == TRANSLATE_BACKWARD ||
+ action == GRAB_VIEW || action == ROTATE_CCW ||
+ action == ROTATE_CW || action == SCALE_UP ||
+ action == SCALE_DOWN || action == NONE))
+ throw new IllegalArgumentException
+ ("\naction must be TRANSLATE_FORWARD, TRANSLATE_BACKWARD, " +
+ "GRAB_VIEW, ROTATE_CCW, ROTATE_CW, SCALE_UP, SCALE_DOWN, " +
+ "or NONE") ;
+
+ while (button >= buttonActions6D.size()) {
+ buttonActions6D.add(null) ;
+ }
+ buttonActions6D.set(button, new Integer(action)) ;
+ }
+
+
+ /**
+ * Gets the action associated with the specified button on the 6DOF sensor.
+ *
+ * @return the action associated with the button
+ */
+ public int getButtonAction6D(int button) {
+ if (button >= buttonActions6D.size())
+ return NONE ;
+
+ Integer i = (Integer)buttonActions6D.get(button) ;
+ if (i == null)
+ return NONE ;
+ else
+ return i.intValue() ;
+ }
+
+ /**
+ * Property which sets the action to be bound to 2D valuator reads. This
+ * action will be performed on each frame whenever no button actions have
+ * been invoked and the valuator read value is greater than the threshold
+ * range specified by the Threshold2D
property.
+ * MatrixIndices2D
, with
+ * defaults of 3 and 7 respectively.
+ * Rotation
rotates the view
+ * platform in the direction the valuator is pushed. The rotation
+ * coordinate system is set by the RotationCoords
property,
+ * with a default of Sensor
. The rotation occurs about a
+ * point in the virtual world set by the
+ * TransformCenterSource
and TransformCenter
+ * properties, with the default set to rotate about the hotspot of a 6DOF
+ * sensor, if one is available, or about the origin of the virtual world
+ * if not. The rotation speed is scaled by the valuator read value up to
+ * the maximum speed set with the RotationSpeed
property; the
+ * default is 180 degrees per second.
+ * Translation
moves the view platform in
+ * the direction the valuator is pushed. The translation occurs along the
+ * X and Z basis vectors of either a 6DOF sensor or the view platform if a
+ * 6DOF sensor is not specified. The translation speed is scaled by the
+ * valuator read value up to a maximum set by the product of the
+ * TranslationSpeed
and FastSpeedFactor
property
+ * values.
+ * Scale
, then the view platform
+ * is scaled smaller or larger when the valuator is pushed forward or
+ * backward. The scaling occurs about a point in the virtual world set by
+ * the TransformCenterSource
and TransformCenter
+ * properties. The scaling speed is set with the ScaleSpeed
+ * property, with a default scale factor of 2.0 per second at the extreme
+ * negative range of -1.0, and a factor of 0.5 per second at the extreme
+ * positive range of +1.0.
+ * None
prevents Rotation
from being
+ * bound to the 2D valuator reads.
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * ReadAction2D [Rotation | Translation | Scale | None])
+ *
+ * @param action array of length 1 containing a String
+ * @see #setReadAction2D
+ * @see #RotationCoords RotationCoords
+ * @see #RotationSpeed RotationSpeed
+ * @see #TransformCenterSource TransformCenterSource
+ * @see #TransformCenter TransformCenter
+ * @see #TranslationSpeed TranslationSpeed
+ * @see #FastSpeedFactor FastSpeedFactor
+ * @see #ScaleSpeed ScaleSpeed
+ * @see #MatrixIndices2D MatrixIndices2D
+ * @see RotationListener2D
+ * @see TranslationListener2D
+ * @see ScaleListener2D
+ */
+ public void ReadAction2D(Object[] action) {
+ if (! (action.length == 1 && action[0] instanceof String))
+ throw new IllegalArgumentException
+ ("\nReadAction2D must be a String") ;
+
+ String actionString = (String)action[0] ;
+
+ if (actionString.equals("Rotation"))
+ setReadAction2D(ROTATION) ;
+ else if (actionString.equals("Translation"))
+ setReadAction2D(TRANSLATION) ;
+ else if (actionString.equals("Scale"))
+ setReadAction2D(SCALE) ;
+ else if (actionString.equals("None"))
+ setReadAction2D(NONE) ;
+ else
+ throw new IllegalArgumentException
+ ("\nReadAction2D must be Rotation, Translation, Scale, " +
+ "or None") ;
+ }
+
+ /**
+ * Sets the action to be bound to 2D valuator reads. This action will be
+ * performed on each frame whenever no button actions have been invoked
+ * and the valuator read value is greater than the threshold range
+ * specified by setThreshold2D
.
+ * setMatrixIndices2D
+ * method, with defaults of 3 and 7 respectively.
+ * ROTATION
rotates the view platform
+ * in the direction the valuator is pushed. The rotation coordinate
+ * system is set by setRotationCoords
, with a default of
+ * SENSOR
. The rotation occurs about a point in the virtual
+ * world set by setTransformCenterSource
and
+ * setTransformCenter
, with the default set to rotate about
+ * the hotspot of a 6DOF sensor, if one is available, or about the origin
+ * of the virtual world if not. The rotation speed is scaled by the
+ * valuator read value up to the maximum speed set with
+ * setRotationSpeed
; the default is 180 degrees per second.
+ * TRANSLATION
moves the view platform in the
+ * direction the valuator is pushed. The translation occurs along the X
+ * and Z basis vectors of either a 6DOF sensor or the view platform if a
+ * 6DOF sensor is not specified. The translation speed is scaled by the
+ * valuator read value up to a maximum set by the product of the
+ * setTranslationSpeed
and setFastSpeedFactor
+ * values.
+ * SCALE
, then the view platform is scaled
+ * smaller or larger when the valuator is pushed forward or backward. The
+ * scaling occurs about a point in the virtual world set by
+ * setTransformCenterSource
and
+ * setTransformCenter
. The scaling speed is set with
+ * setScaleSpeed
, with a default scale factor of 2.0 per
+ * second at the extreme negative range of -1.0, and a factor of 0.5 per
+ * second at the extreme positive range of +1.0.
+ * NONE
prevents ROTATION
from being
+ * bound by default to the 2D valuator reads.
+ * SensorEventAgent
used by this behavior directly.
+ *
+ * @param action either ROTATION
, TRANSLATION
,
+ * SCALE
, or NONE
+ * @see #setRotationCoords
+ * @see #setRotationSpeed
+ * @see #setTransformCenterSource
+ * @see #setTransformCenter
+ * @see #setTranslationSpeed
+ * @see #setFastSpeedFactor
+ * @see #setScaleSpeed
+ * @see #setMatrixIndices2D
+ * @see #getSensorEventAgent
+ * @see RotationListener2D
+ * @see TranslationListener2D
+ * @see ScaleListener2D
+ */
+ public void setReadAction2D(int action) {
+ if (! (action == ROTATION || action == TRANSLATION ||
+ action == SCALE || action == NONE))
+ throw new IllegalArgumentException
+ ("\nReadAction2D must be ROTATION, TRANSLATION, SCALE, " +
+ "or NONE") ;
+
+ this.readAction2D = action ;
+ }
+
+ /**
+ * Gets the configured 2D valuator read action.
+ *
+ * @return the action associated with the sensor read
+ */
+ public int getReadAction2D() {
+ if (readAction2D == UNSET)
+ return NONE ;
+ else
+ return readAction2D ;
+ }
+
+ /**
+ * Property which sets a button action for the 2D valuator. The possible
+ * values are Rotation
, Translation
,
+ * Scale
, or None
, with a default of
+ * None
. These actions are the same as those for
+ * ReadAction2D
.
+ * ArrayOutOfBoundsException
+ * when the behavior is initialized or attached to a
+ * ViewingPlatform
.
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * ButtonAction2D <button index>
+ * [Rotation | Translation | Scale | None])
+ *
+ * @param action array of length 2 containing a Double
and a
+ * String
.
+ * @see #setButtonAction2D
+ * @see #ReadAction2D ReadAction2D
+ * @see #RotationCoords RotationCoords
+ * @see #RotationSpeed RotationSpeed
+ * @see #TransformCenterSource TransformCenterSource
+ * @see #TransformCenter TransformCenter
+ * @see #TranslationSpeed TranslationSpeed
+ * @see #FastSpeedFactor FastSpeedFactor
+ * @see #ScaleSpeed ScaleSpeed
+ * @see #MatrixIndices2D MatrixIndices2D
+ * @see RotationListener2D
+ * @see TranslationListener2D
+ * @see ScaleListener2D
+ */
+ public void ButtonAction2D(Object[] action) {
+ if (! (action.length == 2 &&
+ action[0] instanceof Double && action[1] instanceof String))
+ throw new IllegalArgumentException
+ ("\nButtonAction2D must be a number and a string") ;
+
+ int button = ((Double)action[0]).intValue() ;
+ String actionString = (String)action[1] ;
+
+ if (actionString.equals("Rotation"))
+ setButtonAction2D(button, ROTATION) ;
+ else if (actionString.equals("Translation"))
+ setButtonAction2D(button, TRANSLATION) ;
+ else if (actionString.equals("Scale"))
+ setButtonAction2D(button, SCALE) ;
+ else if (actionString.equals("None"))
+ setButtonAction2D(button, NONE) ;
+ else
+ throw new IllegalArgumentException
+ ("\nButtonAction2D must be Rotation, Translation, Scale " +
+ "or None") ;
+ }
+
+ /**
+ * Sets a button action for the 2D valuator. The possible values are
+ * ROTATION
, TRANSLATION
, SCALE
, or
+ * NONE
, with a default of NONE
. These actions
+ * are the same as those for setReadAction2D
.
+ * ArrayOutOfBoundsException
+ * when the behavior is initialized or attached to a
+ * ViewingPlatform
.
+ * SensorEventAgent
used by this behavior directly.
+ *
+ * @param button index of the button to bind
+ * @param action either ROTATION
, TRANSLATION
,
+ * SCALE
, or NONE
+ * @see #setReadAction2D
+ * @see #setRotationCoords
+ * @see #setRotationSpeed
+ * @see #setTransformCenterSource
+ * @see #setTransformCenter
+ * @see #setTranslationSpeed
+ * @see #setFastSpeedFactor
+ * @see #setScaleSpeed
+ * @see #setMatrixIndices2D
+ * @see #getSensorEventAgent
+ * @see RotationListener2D
+ * @see TranslationListener2D
+ * @see ScaleListener2D
+ */
+ public synchronized void setButtonAction2D(int button, int action) {
+ if (! (action == ROTATION || action == TRANSLATION ||
+ action == SCALE || action == NONE))
+ throw new IllegalArgumentException
+ ("\naction must be ROTATION, TRANSLATION, SCALE, or NONE") ;
+
+ while (button >= buttonActions2D.size()) {
+ buttonActions2D.add(null) ;
+ }
+ buttonActions2D.set(button, new Integer(action)) ;
+ }
+
+
+ /**
+ * Gets the action associated with the specified button on the 2D valuator.
+ *
+ * @return the action associated with the button
+ */
+ public int getButtonAction2D(int button) {
+ if (button >= buttonActions2D.size())
+ return NONE ;
+
+ Integer i = (Integer)buttonActions2D.get(button) ;
+ if (i == null)
+ return NONE ;
+ else
+ return i.intValue() ;
+ }
+
+ /**
+ * Property which sets the action to be bound to 6DOF sensor reads. This
+ * action will be performed every frame whenever a button action has not
+ * been invoked.
+ * Echo
, which displays a geometric
+ * representation of the sensor's current position and orientation in the
+ * virtual world. A value of None
indicates that no default
+ * action is to be applied to the sensor's read.
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * ReadAction6D [Echo | None])
+ *
+ * @param action array of length 1 containing a String
+ * @see #setReadAction6D
+ * @see EchoReadListener6D
+ */
+ public void ReadAction6D(Object[] action) {
+ if (! (action.length == 1 && action[0] instanceof String))
+ throw new IllegalArgumentException
+ ("\nReadAction6D must be a String") ;
+
+ String actionString = (String)action[0] ;
+
+ if (actionString.equals("Echo"))
+ setReadAction6D(ECHO) ;
+ else if (actionString.equals("None"))
+ setReadAction6D(NONE) ;
+ else
+ throw new IllegalArgumentException
+ ("\nReadAction6D must be Echo or None") ;
+ }
+
+ /**
+ * Sets the action to be bound to 6DOF sensor reads. This action will be
+ * performed every frame whenever a button action has not been invoked.
+ * ECHO
, which displays a geometric
+ * representation of the sensor's current position and orientation in the
+ * virtual world. A value of NONE
indicates that no default
+ * action is to be associated with the sensor's read.
+ * SensorEventAgent
used by this behavior directly.
+ *
+ * @param action either ECHO
or NONE
+ * @see EchoReadListener6D
+ * @see #getSensorEventAgent
+ */
+ public void setReadAction6D(int action) {
+ if (! (action == ECHO || action == NONE))
+ throw new IllegalArgumentException
+ ("\naction must be ECHO or NONE") ;
+
+ this.readAction6D = action ;
+ }
+
+ /**
+ * Gets the configured 6DOF sensor read action.
+ *
+ * @return the configured 6DOF sensor read action
+ */
+ public int getReadAction6D() {
+ if (readAction6D == UNSET)
+ return NONE ;
+ else
+ return readAction6D ;
+ }
+
+ /**
+ * Property which sets the normal translation speed. The default is 0.1
+ * meters/second in physical units. This property is set in the
+ * configuration file read by ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * TranslationSpeed <speed> [PhysicalMeters | VirtualUnits]
+ * [PerFrame | PerSecond])
+ *
+ * @param speed array of length 3; first element is a Double
+ * for the speed, the second is a String
for the units, and
+ * the third is a String
for the time base
+ * @see #setTranslationSpeed
+ */
+ public void TranslationSpeed(Object[] speed) {
+ if (! (speed.length == 3 && speed[0] instanceof Double &&
+ speed[1] instanceof String && speed[2] instanceof String))
+ throw new IllegalArgumentException
+ ("\nTranslationSpeed must be number, units, and time base") ;
+
+ double v = ((Double)speed[0]).doubleValue() ;
+ String unitsString = (String)speed[1] ;
+ String timeBaseString = (String)speed[2] ;
+ int units, timeBase ;
+
+ if (unitsString.equals("PhysicalMeters"))
+ units = PHYSICAL_METERS ;
+ else if (unitsString.equals("VirtualUnits"))
+ units = VIRTUAL_UNITS ;
+ else
+ throw new IllegalArgumentException
+ ("\nTranslationSpeed units must be " +
+ "PhysicalMeters or VirtualUnits") ;
+
+ if (timeBaseString.equals("PerFrame"))
+ timeBase = PER_FRAME ;
+ else if (timeBaseString.equals("PerSecond"))
+ timeBase = PER_SECOND ;
+ else
+ throw new IllegalArgumentException
+ ("\ntime base must be PerFrame or PerSecond") ;
+
+ setTranslationSpeed(v, units, timeBase) ;
+ }
+
+ /**
+ * Sets the normal translation speed. The default is 0.1 physical
+ * meters/second.
+ *
+ * @param speed how fast to translate
+ * @param units either PHYSICAL_METERS
or
+ * VIRTUAL_UNITS
+ * @param timeBase either PER_SECOND
or
+ * PER_FRAME
+ */
+ public void setTranslationSpeed(double speed, int units, int timeBase) {
+ this.translationSpeed = speed ;
+
+ if (units == PHYSICAL_METERS || units == VIRTUAL_UNITS)
+ this.translationUnits = units ;
+ else
+ throw new IllegalArgumentException
+ ("\ntranslation speed units must be " +
+ "PHYSICAL_METERS or VIRTUAL_UNITS") ;
+
+ if (timeBase == PER_FRAME || timeBase == PER_SECOND)
+ this.translationTimeBase = timeBase ;
+ else
+ throw new IllegalArgumentException
+ ("\ntranslation time base must be PER_FRAME or PER_SECOND") ;
+ }
+
+ /**
+ * Gets the normal speed at which to translate the view platform.
+ *
+ * @return the normal translation speed
+ */
+ public double getTranslationSpeed() {
+ return translationSpeed ;
+ }
+
+ /**
+ * Gets the translation speed units.
+ *
+ * @return the translation units
+ */
+ public int getTranslationUnits() {
+ return translationUnits ;
+ }
+
+ /**
+ * Gets the time base for translation speed.
+ *
+ * @return the translation time base
+ */
+ public int getTranslationTimeBase() {
+ return translationTimeBase ;
+ }
+
+ /**
+ * Property which sets the time interval for accelerating to the
+ * translation, rotation, or scale speeds and for transitioning between
+ * the normal and fast translation speeds. The default is 1 second. This
+ * property is set in the configuration file read by
+ * ConfiguredUniverse
.
(ViewPlatformBehaviorProperty <name>
+ * AccelerationTime <seconds>)
+ *
+ * @param time array of length 1 containing a Double
+ * @see #setAccelerationTime
+ */
+ public void AccelerationTime(Object[] time) {
+ if (! (time.length == 1 && time[0] instanceof Double))
+ throw new IllegalArgumentException
+ ("\nAccelerationTime must be a number") ;
+
+ setAccelerationTime(((Double)time[0]).doubleValue()) ;
+ }
+
+ /**
+ * Sets the time interval for accelerating to the translation, rotation,
+ * or scale speeds and for transitioning between the normal and fast
+ * translation speeds. The default is 1 second.
+ *
+ * @param time number of seconds to accelerate to normal or fast speed
+ */
+ public void setAccelerationTime(double time) {
+ this.accelerationTime = time ;
+ }
+
+ /**
+ * Gets the time interval for accelerating to normal speed and for
+ * transitioning between the normal and fast translation speeds.
+ *
+ * @return the acceleration time
+ */
+ public double getAccelerationTime() {
+ return accelerationTime ;
+ }
+
+ /**
+ * Property which sets the time interval for which the translation occurs
+ * at the normal speed. The default is 8 seconds. This property is set
+ * in the configuration file read by ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * ConstantSpeedTime <seconds>)
+ *
+ * @param time array of length 1 containing a Double
+ * @see #setConstantSpeedTime
+ */
+ public void ConstantSpeedTime(Object[] time) {
+ if (! (time.length == 1 && time[0] instanceof Double))
+ throw new IllegalArgumentException
+ ("\nConstantSpeedTime must be a number") ;
+
+ setConstantSpeedTime(((Double)time[0]).doubleValue()) ;
+ }
+
+ /**
+ * Sets the time interval for which the translation occurs at the normal
+ * speed. The default is 8 seconds.
+ *
+ * @param time number of seconds to translate at a constant speed
+ */
+ public void setConstantSpeedTime(double time) {
+ this.constantSpeedTime = time ;
+ }
+
+ /**
+ * Gets the time interval for which the translation occurs at the
+ * normal speed.
+ *
+ * @return the constant speed time
+ */
+ public double getConstantSpeedTime() {
+ return constantSpeedTime ;
+ }
+
+ /**
+ * Property which sets the fast translation speed factor. The default is
+ * 10 times the normal speed. This property is set in the configuration
+ * file read by ConfiguredUniverse.
+ *
(ViewPlatformBehaviorProperty <name>
+ * FastSpeedFactor <factor>)
+ *
+ * @param factor array of length 1 containing a Double
+ * @see #setFastSpeedFactor
+ */
+ public void FastSpeedFactor(Object[] factor) {
+ if (! (factor.length == 1 && factor[0] instanceof Double))
+ throw new IllegalArgumentException
+ ("\nFastSpeedFactor must be a number") ;
+
+ setFastSpeedFactor(((Double)factor[0]).doubleValue()) ;
+ }
+
+ /**
+ * Sets the fast translation speed factor. The default is 10 times the
+ * normal speed.
+ *
+ * @param factor scale by which the normal translation speed is multiplied
+ */
+ public void setFastSpeedFactor(double factor) {
+ this.fastSpeedFactor = factor ;
+ }
+
+ /**
+ * Gets the factor by which the normal translation speed is multiplied
+ * after the constant speed time interval.
+ *
+ * @return the fast speed factor
+ */
+ public double getFastSpeedFactor() {
+ return fastSpeedFactor ;
+ }
+
+ /**
+ * Property which sets the threshold for 2D valuator reads. The default
+ * is 0.0. It can be set higher to handle noisy valuators. This property
+ * is set in the configuration file read by
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * Threshold2D <threshold>)
+ *
+ * @param threshold array of length 1 containing a Double
+ * @see #setThreshold2D
+ */
+ public void Threshold2D(Object[] threshold) {
+ if (! (threshold.length == 1 && threshold[0] instanceof Double))
+ throw new IllegalArgumentException
+ ("\nThreshold2D must be a number") ;
+
+ setThreshold2D(((Double)threshold[0]).doubleValue()) ;
+ }
+
+ /**
+ * Sets the threshold for 2D valuator reads. The default is 0.0. It can
+ * be set higher to handle noisy valuators.
+ *
+ * @param threshold if the absolute values of both the X and Y valuator
+ * reads are less than this value then the values are ignored
+ */
+ public void setThreshold2D(double threshold) {
+ this.threshold2D = threshold ;
+ }
+
+ /**
+ * Gets the 2D valuator threshold.
+ *
+ * @return the threshold value
+ */
+ public double getThreshold2D() {
+ return threshold2D ;
+ }
+
+ /**
+ * Property which specifies where to find the X and Y values in the matrix
+ * read generated by a 2D valuator. The defaults are along the
+ * translation components of the matrix, at indices 3 and 7. This
+ * property is set in the configuration file read by
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * MatrixIndices2D <X index> <Y index>)
+ *
+ * @param indices array of length 2 containing Doubles
+ * @see #setMatrixIndices2D
+ */
+ public void MatrixIndices2D(Object[] indices) {
+ if (! (indices.length == 2 &&
+ indices[0] instanceof Double && indices[1] instanceof Double))
+ throw new IllegalArgumentException
+ ("\nMatrixIndices2D must be a numbers") ;
+
+ setMatrixIndices2D(((Double)indices[0]).intValue(),
+ ((Double)indices[1]).intValue()) ;
+ }
+
+ /**
+ * Specifies where to find the X and Y values in the matrix read generated
+ * by a 2D valuator. The defaults are along the translation components of
+ * the matrix, at indices 3 and 7.
+ *
+ * @param xIndex index of the X valuator value
+ * @param yIndex index of the Y valuator value
+ */
+ public void setMatrixIndices2D(int xIndex, int yIndex) {
+ this.x2D = xIndex ;
+ this.y2D = yIndex ;
+ }
+
+ /**
+ * Gets the index where the X value of a 2D valuator read matrix can be
+ * found.
+ *
+ * @return the X index in the read matrix
+ */
+ public int getMatrixXIndex2D() {
+ return x2D ;
+ }
+
+ /**
+ * Gets the index where the Y value of a 2D valuator read matrix can be
+ * found.
+ *
+ * @return the Y index in the read matrix
+ */
+ public int getMatrixYIndex2D() {
+ return y2D ;
+ }
+
+ /**
+ * Property which sets the rotation speed. The default is 180
+ * degrees/second. This property is set in the configuration file read by
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * RotationSpeed <speed> [Degrees | Radians]
+ * [PerFrame | PerSecond])
+ *
+ * @param speed array of length 3; first element is a Double
+ * for the speed, the second is a String
for the units, and
+ * the third is a String
for the time base
+ * @see #setRotationSpeed
+ */
+ public void RotationSpeed(Object[] speed) {
+ if (! (speed.length == 3 && speed[0] instanceof Double &&
+ speed[1] instanceof String && speed[2] instanceof String))
+ throw new IllegalArgumentException
+ ("\nRotationSpeed must be number, units, and time base") ;
+
+ double v = ((Double)speed[0]).doubleValue() ;
+ String unitsString = (String)speed[1] ;
+ String timeBaseString = (String)speed[2] ;
+ int units, timeBase ;
+
+ if (unitsString.equals("Degrees"))
+ units = DEGREES ;
+ else if (unitsString.equals("Radians"))
+ units = RADIANS ;
+ else
+ throw new IllegalArgumentException
+ ("\nRotationSpeed units must be Degrees or Radians") ;
+
+ if (timeBaseString.equals("PerFrame"))
+ timeBase = PER_FRAME ;
+ else if (timeBaseString.equals("PerSecond"))
+ timeBase = PER_SECOND ;
+ else
+ throw new IllegalArgumentException
+ ("\nRotationSpeed time base must be PerFrame or PerSecond") ;
+
+ setRotationSpeed(v, units, timeBase) ;
+ }
+
+ /**
+ * Sets the rotation speed. The default is 180 degrees/second.
+ *
+ * @param speed how fast to rotate
+ * @param units either DEGREES
or RADIANS
+ * @param timeBase either PER_SECOND
or PER_FRAME
+ */
+ public void setRotationSpeed(double speed, int units, int timeBase) {
+ this.rotationSpeed = speed ;
+
+ if (units == DEGREES || units == RADIANS)
+ this.rotationUnits = units ;
+ else
+ throw new IllegalArgumentException
+ ("\nrotation speed units must be DEGREES or RADIANS") ;
+
+ if (timeBase == PER_FRAME || timeBase == PER_SECOND)
+ this.rotationTimeBase = timeBase ;
+ else
+ throw new IllegalArgumentException
+ ("\nrotation time base must be PER_FRAME or PER_SECOND") ;
+ }
+
+ /**
+ * Gets the rotation speed.
+ *
+ * @return the rotation speed
+ */
+ public double getRotationSpeed() {
+ return rotationSpeed ;
+ }
+
+ /**
+ * Gets the rotation speed units
+ *
+ * @return the rotation units
+ */
+ public int getRotationUnits() {
+ return rotationUnits ;
+ }
+
+ /**
+ * Gets the time base for rotation speed.
+ *
+ * @return the rotation time base
+ */
+ public int getRotationTimeBase() {
+ return rotationTimeBase ;
+ }
+
+ /**
+ * Property which sets the rotation coordinate system. The default is
+ * Sensor
, which means that the rotation axis is parallel to
+ * the XY plane of the current orientation of a specified 6DOF sensor. A
+ * value of ViewPlatform
means the rotation axis is parallel
+ * to the XY plane of the view platform. The latter is also the fallback
+ * if a 6DOF sensor is not specified. If the value is Head
,
+ * then the rotation occurs in head coordinates.
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * RotationCoords [Sensor | ViewPlatform | Head])
+ *
+ * @param coords array of length 1 containing a String
+ * @see #setRotationCoords
+ */
+ public void RotationCoords(Object[] coords) {
+ if (! (coords.length == 1 && coords[0] instanceof String))
+ throw new IllegalArgumentException
+ ("\nRotationCoords must be a String") ;
+
+ String coordsString = (String)coords[0] ;
+
+ if (coordsString.equals("Sensor"))
+ setRotationCoords(SENSOR) ;
+ else if (coordsString.equals("ViewPlatform"))
+ setRotationCoords(VIEW_PLATFORM) ;
+ else if (coordsString.equals("Head"))
+ setRotationCoords(HEAD) ;
+ else
+ throw new IllegalArgumentException
+ ("\nRotationCoords must be Sensor, ViewPlatform, or Head") ;
+ }
+
+ /**
+ * Sets the rotation coordinate system. The default is
+ * SENSOR
, which means that the rotation axis is parallel to
+ * the XY plane of the current orientation of a specified 6DOF sensor. A
+ * value of VIEW_PLATFORM
means the rotation axis is parallel
+ * to the XY plane of the view platform. The latter is also the fallback
+ * if a 6DOF sensor is not specified. If the value is HEAD
,
+ * then rotation occurs in head coordinates.
+ *
+ * @param coords either SENSOR
, VIEW_PLATFORM
, or
+ * HEAD
+ */
+ public void setRotationCoords(int coords) {
+ if (! (coords == SENSOR || coords == VIEW_PLATFORM || coords == HEAD))
+ throw new IllegalArgumentException
+ ("\nrotation coordinates be SENSOR, VIEW_PLATFORM, or HEAD") ;
+
+ this.rotationCoords = coords ;
+ }
+
+ /**
+ * Gets the rotation coordinate system.
+ *
+ * @return the rotation coordinate system
+ */
+ public int getRotationCoords() {
+ return rotationCoords ;
+ }
+
+ /**
+ * Property which sets the scaling speed. The default is 2.0 per second,
+ * which means magnification doubles the apparent size of the virtual
+ * world every second, and minification halves the apparent size of the
+ * virtual world every second.
+ * Math.pow(scaleSpeed,
+ * frameTime)
, where frameTime
is the time in seconds
+ * that the last frame took to render if the time base is
+ * PerSecond
, or 1.0 if the time base is
+ * PerFrame
. If scaling is performed with the 2D valuator,
+ * then the valuator's Y value as specified by
+ * MatrixIndices2D
is an additional scale applied to the
+ * exponent. If scaling is performed by the 6DOF sensor, then the scale
+ * speed can be inverted with a negative exponent by using the appropriate
+ * listener constructor flag.
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * ScaleSpeed <speed> [PerFrame | PerSecond])
+ *
+ * @param speed array of length 2; first element is a Double
+ * for the speed, and the second is a String
for the time
+ * base
+ * @see #setScaleSpeed
+ */
+ public void ScaleSpeed(Object[] speed) {
+ if (! (speed.length == 2 &&
+ speed[0] instanceof Double && speed[1] instanceof String))
+ throw new IllegalArgumentException
+ ("\nScalingSpeed must be a number and a string") ;
+
+ double v = ((Double)speed[0]).doubleValue() ;
+ String timeBaseString = (String)speed[2] ;
+ int timeBase ;
+
+ if (timeBaseString.equals("PerFrame"))
+ timeBase = PER_FRAME ;
+ else if (timeBaseString.equals("PerSecond"))
+ timeBase = PER_SECOND ;
+ else
+ throw new IllegalArgumentException
+ ("\nScalingSpeed time base must be PerFrame or PerSecond") ;
+
+ setScaleSpeed(v, timeBase) ;
+ }
+
+ /**
+ * Sets the scaling speed. The default is 2.0 per second, which means
+ * magnification doubles the apparent size of the virtual world every
+ * second, and minification halves the apparent size of the virtual world
+ * every second.
+ * Math.pow(scaleSpeed,
+ * frameTime)
, where frameTime
is the time in seconds
+ * that the last frame took to render if the time base is
+ * PER_SECOND
, or 1.0 if the time base is
+ * PER_FRAME
. If scaling is performed with the 2D valuator,
+ * then the valuator's Y value as specified by
+ * setMatrixIndices2D
is an additional scale applied to the
+ * exponent. If scaling is performed by the 6DOF sensor, then the scale
+ * speed can be inverted with a negative exponent by using the appropriate
+ * listener constructor flag.
+ *
+ * @param speed specifies the scale speed
+ * @param timeBase either PER_SECOND
or PER_FRAME
+ */
+ public void setScaleSpeed(double speed, int timeBase) {
+ this.scaleSpeed = speed ;
+
+ if (timeBase == PER_FRAME || timeBase == PER_SECOND)
+ this.scaleTimeBase = timeBase ;
+ else
+ throw new IllegalArgumentException
+ ("\nscaling time base must be PER_FRAME or PER_SECOND") ;
+ }
+
+ /**
+ * Gets the scaling speed.
+ *
+ * @return the scaling speed
+ */
+ public double getScaleSpeed() {
+ return scaleSpeed ;
+ }
+
+ /**
+ * Gets the time base for scaling speed.
+ *
+ * @return the scaling time base
+ */
+ public int getScaleTimeBase() {
+ return scaleTimeBase ;
+ }
+
+ /**
+ * Property which sets the source of the center of rotation and scale.
+ * The default is Hotspot
, which means the center of rotation
+ * or scale is a 6DOF sensor's current hotspot location. The alternative
+ * is VworldFixed
, which uses the fixed virtual world
+ * coordinates specified by the TransformCenter
property as
+ * the center. The latter is also the fallback if a 6DOF sensor is not
+ * specified. This property is set in the configuration file read by
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * TransformCenterSource [Hotspot | VworldFixed])
+ *
+ * @param source array of length 1 containing a String
+ * @see #setTransformCenterSource
+ */
+ public void TransformCenterSource(Object[] source) {
+ if (! (source.length == 1 && source[0] instanceof String))
+ throw new IllegalArgumentException
+ ("\nTransformCenterSource must be a String") ;
+
+ String sourceString = (String)source[0] ;
+
+ if (sourceString.equals("Hotspot"))
+ setTransformCenterSource(HOTSPOT) ;
+ else if (sourceString.equals("VworldFixed"))
+ setTransformCenterSource(VWORLD_FIXED) ;
+ else
+ throw new IllegalArgumentException
+ ("\nTransformCenterSource must be Hotspot or " +
+ "VworldFixed") ;
+ }
+
+ /**
+ * Sets the source of the center of rotation and scale. The default is
+ * HOTSPOT
, which means the center of rotation or scale is a
+ * 6DOF sensor's current hotspot location. The alternative is
+ * VWORLD_FIXED
, which uses the fixed virtual world
+ * coordinates specified by setTransformCenter
as the center.
+ * The latter is also the fallback if a 6DOF sensor is not specified.
+ * HOTSPOT
or VWORLD_FIXED
+ */
+ public void setTransformCenterSource(int source) {
+ if (! (source == HOTSPOT || source == VWORLD_FIXED))
+ throw new IllegalArgumentException
+ ("\nrotation/scale center source must be HOTSPOT or " +
+ "VWORLD_FIXED") ;
+
+ this.transformCenterSource = source ;
+ }
+
+ /**
+ * Gets the rotation/scale center source.
+ *
+ * @return the rotation/scale center source
+ */
+ public int getTransformCenterSource() {
+ return transformCenterSource ;
+ }
+
+ /**
+ * Property which sets the center of rotation and scale if the
+ * TransformCenterSource
property is VworldFixed
+ * or if a 6DOF sensor is not specified. The default is (0.0, 0.0, 0.0)
+ * in virtual world coordinates. This property is set in the
+ * configuration file read by ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * TransformCenter <Point3d>)
+ *
+ * @param center array of length 1 containing a Point3d
+ * @see #setTransformCenter
+ */
+ public void TransformCenter(Object[] center) {
+ if (! (center.length == 1 && center[0] instanceof Point3d))
+ throw new IllegalArgumentException
+ ("\nTransformCenter must be a Point3d") ;
+
+ setTransformCenter((Point3d)center[0]) ;
+ }
+
+ /**
+ * Sets the center of rotation and scale if
+ * setTransformCenterSource
is called with
+ * VWORLD_FIXED
or if a 6DOF sensor is not specified. The
+ * default is (0.0, 0.0, 0.0) in virtual world coordinates.
+ * Point3d
to receive a copy of the
+ * rotation/scale center
+ */
+ public void getTransformCenter(Point3d center) {
+ center.set(transformCenter) ;
+ }
+
+ /**
+ * Property which sets the nominal sensor rotation. The default is the
+ * identity transform.
+ * InputDevice
supporting the
+ * sensor handles its orientation. The NominalSensorRotation
+ * property can be used to correct the alignment by specifying the
+ * rotation needed to transform vectors from the nominal sensor coordinate
+ * system, aligned with the image plate coordinate system as described
+ * above, to the sensor's actual local coordinate system.
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * NominalSensorRotation [<Matrix4d> |
+ * <Matrix3d>])
+ *
+ * @param matrix array of length 1 containing a Matrix4d
or
+ * Matrix3d
+ * @see #setNominalSensorRotation
+ */
+ public void NominalSensorRotation(Object[] matrix) {
+ if (! (matrix.length == 1 && (matrix[0] instanceof Matrix3d ||
+ matrix[0] instanceof Matrix4d)))
+ throw new IllegalArgumentException
+ ("\nNominalSensorRotation must be a Matrix3d or Matrix4d") ;
+
+ Transform3D t3d = new Transform3D() ;
+
+ if (matrix[0] instanceof Matrix3d)
+ t3d.set((Matrix3d)matrix[0]) ;
+ else
+ t3d.set((Matrix4d)matrix[0]) ;
+
+ setNominalSensorRotation(t3d) ;
+ }
+
+ /**
+ * Sets the nominal sensor transform. The default is the identity
+ * transform.
+ * InputDevice
supporting the
+ * sensor handles its orientation. setNominalSensorRotation
+ * can be called to correct the alignment by specifying the rotation
+ * needed to transform vectors from the nominal sensor coordinate system,
+ * aligned with the image plate coordinate system as described above, to
+ * the sensor's actual local coordinate system.
+ * null
for
+ * identity.
+ */
+ public void setNominalSensorRotation(Transform3D transform) {
+ if (transform == null) {
+ nominalSensorRotation = null ;
+ return ;
+ }
+
+ if (nominalSensorRotation == null)
+ nominalSensorRotation = new Transform3D() ;
+
+ // Set transform and make sure it is a rotation only.
+ nominalSensorRotation.set(transform) ;
+ nominalSensorRotation.setTranslation(new Vector3d()) ;
+ }
+
+ /**
+ * Gets the nominal sensor transform.
+ *
+ * @param t3d Transform3D
to receive a copy of the
+ * nominal sensor transform
+ */
+ public void getNominalSensorRotation(Transform3D t3d) {
+ if (nominalSensorRotation != null) {
+ t3d.set(nominalSensorRotation);
+ } else {
+ t3d.setIdentity();
+ }
+ }
+
+ /**
+ * Property which sets the number of buttons to be pressed simultaneously
+ * on the 6DOF sensor in order to reset the view back to the home
+ * transform. The value must be greater than 1; the default is 3. A
+ * value of None
disables this action. This property is set
+ * in the configuration file read by ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * ResetViewButtonCount6D [<count> | None])
+ *
+ * @param count array of length 1 containing a Double
or
+ * String
+ * @see #setResetViewButtonCount6D
+ * @see ViewPlatformBehavior#setHomeTransform
+ * ViewPlatformBehavior.setHomeTransform
+ */
+ public void ResetViewButtonCount6D(Object[] count) {
+ if (! (count.length == 1 &&
+ (count[0] instanceof Double || count[0] instanceof String)))
+ throw new IllegalArgumentException
+ ("\nResetViewButtonCount6D must be a number or None") ;
+
+ if (count[0] instanceof String) {
+ String s = (String)count[0] ;
+ if (s.equals("None"))
+ setResetViewButtonCount6D(NONE) ;
+ else
+ throw new IllegalArgumentException
+ ("\nResetViewButtonCount6D string value must be None") ;
+ }
+ else {
+ setResetViewButtonCount6D(((Double)count[0]).intValue()) ;
+ }
+ }
+
+ /**
+ * Sets the number of buttons to be pressed simultaneously
+ * on the 6DOF sensor in order to reset the view back to the home
+ * transform. The value must be greater than 1; the default is 3. A
+ * value of NONE
disables this action.
+ *
+ * @param count either NONE
or button count > 1
+ * @see ViewPlatformBehavior#setHomeTransform
+ * ViewPlatformBehavior.setHomeTransform
+ */
+ public void setResetViewButtonCount6D(int count) {
+ if (count == NONE || count > 1) {
+ resetViewButtonCount6D = count ;
+ }
+ else {
+ throw new IllegalArgumentException
+ ("reset view button count must be > 1") ;
+ }
+ }
+
+ /**
+ * Gets the number of buttons to be pressed simultaneously on the 6DOF
+ * sensor in order to reset the view back to the home transform. A value
+ * of NONE
indicates this action is disabled.
+ *
+ * @return the number of buttons to press simultaneously for a view reset
+ */
+ public int getResetViewButtonCount6D() {
+ return resetViewButtonCount6D ;
+ }
+
+ /**
+ * Property which sets the number of buttons to be pressed simultaneously
+ * on the 2D valuator in order to reset the view back to the home
+ * transform. The value must be greater than 1; the default is
+ * None
. A value of None
disables this action.
+ * This property is set in the configuration file read by
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * ResetViewButtonCount2D [<count> | None])
+ *
+ * @param count array of length 1 containing a Double
or
+ * String
+ * @see #setResetViewButtonCount2D
+ * @see ViewPlatformBehavior#setHomeTransform
+ * ViewPlatformBehavior.setHomeTransform
+ */
+ public void ResetViewButtonCount2D(Object[] count) {
+ if (! (count.length == 1 &&
+ (count[0] instanceof Double || count[0] instanceof String)))
+ throw new IllegalArgumentException
+ ("\nResetViewButtonCount2D must be a number or None") ;
+
+ if (count[0] instanceof String) {
+ String s = (String)count[0] ;
+ if (s.equals("None"))
+ setResetViewButtonCount2D(NONE) ;
+ else
+ throw new IllegalArgumentException
+ ("\nResetViewButtonCount2D string value must be None") ;
+ }
+ else {
+ setResetViewButtonCount2D(((Double)count[0]).intValue()) ;
+ }
+ }
+
+ /**
+ * Sets the number of buttons to be pressed simultaneously on the 2D
+ * valuator in order to reset the view back to the home transform. The
+ * value must be greater than 1; the default is NONE
. A
+ * value of NONE
disables this action.
+ *
+ * @param count either NONE
or button count > 1
+ * @see ViewPlatformBehavior#setHomeTransform
+ * ViewPlatformBehavior.setHomeTransform
+ */
+ public void setResetViewButtonCount2D(int count) {
+ if (count == NONE || count > 1) {
+ resetViewButtonCount2D = count ;
+ }
+ else {
+ throw new IllegalArgumentException
+ ("reset view button count must be > 1") ;
+ }
+ }
+
+ /**
+ * Gets the number of buttons to be pressed simultaneously on the 2D
+ * valuator in order to reset the view back to the home transform. A value
+ * of NONE
indicates this action is disabled.
+ *
+ * @return the number of buttons to press simultaneously for a view reset
+ */
+ public int getResetViewButtonCount2D() {
+ return resetViewButtonCount2D ;
+ }
+
+ /**
+ * Property which sets the 6DOF sensor echo type. The default is
+ * Gnomon
, which displays an object with points indicating
+ * the direction of each of the sensor's coordinate system axes at the
+ * location of the sensor's hotspot. The alternative is
+ * Beam
, which displays a beam from the sensor's origin to
+ * the location of the sensor's hotspot; the hotspot must not be (0, 0, 0)
+ * or an IllegalArgumentException
will result. The width of
+ * each of these echo types is specified by the EchoSize
+ * property. The EchoType
property is set in the
+ * configuration file read by ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * EchoType [Gnomon | Beam | None])
+ *
+ * @param type array of length 1 containing a String
+ * @see #setEchoType
+ */
+ public void EchoType(Object[] type) {
+ if (! (type.length == 1 && type[0] instanceof String))
+ throw new IllegalArgumentException
+ ("\nEchoType must be a String") ;
+
+ String typeString = (String)type[0] ;
+
+ if (typeString.equals("Gnomon"))
+ setEchoType(GNOMON) ;
+ else if (typeString.equals("Beam"))
+ setEchoType(BEAM) ;
+ else if (typeString.equals("None"))
+ setEchoType(NONE) ;
+ else
+ throw new IllegalArgumentException
+ ("\nEchoType must be Gnomon, Beam, or None") ;
+ }
+
+ /**
+ * Sets the 6DOF sensor echo type. The default is GNOMON
,
+ * which displays an object with points indicating the direction of each
+ * of the sensor's coordinate axes at the location of the sensor's
+ * hotspot. The alternative is BEAM
, which displays a beam
+ * from the sensor's origin to the location of the sensor's hotspot; the
+ * hotspot must not be (0, 0, 0) or an
+ * IllegalArgumentException
will result. The width of each
+ * of these echo types is specified by setEchoSize
.
+ *
+ * @param type GNOMON
, BEAM
, or
+ * NONE
are recognized
+ */
+ public void setEchoType(int type) {
+ this.echoType = type ;
+ }
+
+ /**
+ * Gets the echo type.
+ *
+ * @return the echo type
+ */
+ public int getEchoType() {
+ return echoType ;
+ }
+
+ /**
+ * Property which sets the size of the 6DOF sensor echo in physical
+ * meters. This is used for the width of the gnomon and beam echoes. The
+ * default is 1 centimeter. This property is set in the configuration
+ * file read by ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * EchoSize <size>)
+ *
+ * @param echoSize array of length 1 containing a Double
+ * @see #setEchoSize
+ */
+ public void EchoSize(Object[] echoSize) {
+ if (! (echoSize.length == 1 && echoSize[0] instanceof Double))
+ throw new IllegalArgumentException
+ ("\nEchoSize must be a Double") ;
+
+ setEchoSize(((Double)echoSize[0]).doubleValue()) ;
+ }
+
+ /**
+ * Sets the size of the 6DOF sensor echo in physical meters. This is used
+ * for the width of the gnomon and beam echoes. The default is 1
+ * centimeter.
+ *
+ * @param echoSize the size in meters
+ */
+ public void setEchoSize(double echoSize) {
+ this.echoSize = echoSize ;
+ }
+
+ /**
+ * Gets the size of the 6DOF sensor echo in meters.
+ *
+ * @return the echo size
+ */
+ public double getEchoSize() {
+ return echoSize ;
+ }
+
+ /**
+ * Property which sets the color of the 6DOF sensor echo. The default is
+ * white. This property is set in the configuration file read by
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * EchoColor <red> <green> <blue>)
+ *
+ * @param color array of length 3 containing Doubles
+ * @see #setEchoColor
+ */
+ public void EchoColor(Object[] color) {
+ if (! (color.length == 3 && color[0] instanceof Double &&
+ color[1] instanceof Double && color[2] instanceof Double))
+ throw new IllegalArgumentException
+ ("\nEchoColor must be 3 numbers for red, green, and blue") ;
+
+ setEchoColor(new Color3f(((Double)color[0]).floatValue(),
+ ((Double)color[1]).floatValue(),
+ ((Double)color[2]).floatValue())) ;
+ }
+
+ /**
+ * Sets the color of the 6DOF sensor echo. The default is white. This
+ * can be called to set the color before or after the echo geometry is
+ * created.
+ *
+ * @param color the echo color
+ */
+ public void setEchoColor(Color3f color) {
+ if (echoColor == null)
+ echoColor = new Color3f(color) ;
+ else
+ echoColor.set(color) ;
+
+ if (echoGeometry != null) {
+ Appearance a = echoGeometry.getAppearance() ;
+ Material m = a.getMaterial() ;
+ m.setDiffuseColor(echoColor) ;
+ }
+ }
+
+ /**
+ * Gets the 6DOF sensor echo color.
+ *
+ * @param color the Color3f
into which to copy the echo color
+ */
+ public void getEchoColor(Color3f color) {
+ if (echoColor == null)
+ color.set(1.0f, 1.0f, 1.0f) ;
+ else
+ color.set(echoColor) ;
+ }
+
+ /**
+ * Property which sets the 6DOF sensor echo transparency. The default is
+ * opaque. A value of 0.0 is fully opaque and 1.0 is fully transparent.
+ * This property is set in the configuration file read by
+ * ConfiguredUniverse
.
+ *
(ViewPlatformBehaviorProperty <name>
+ * EchoTransparency <transparency>)
+ *
+ * @param transparency array of length 1 containing a Double
+ * @see #setEchoTransparency
+ */
+ public void EchoTransparency(Object[] transparency) {
+ if (! (transparency.length == 1 && transparency[0] instanceof Double))
+ throw new IllegalArgumentException
+ ("\nEchoTransparency must be a number") ;
+
+ setEchoTransparency(((Double)transparency[0]).floatValue()) ;
+ }
+
+ /**
+ * Sets the 6DOF sensor echo transparency. The default is opaque. A
+ * value of 0.0 is fully opaque and 1.0 is fully transparent. This can be
+ * called to set the transparency before or after the echo geometry is
+ * created.
+ *
+ * @param transparency the transparency value
+ */
+ public void setEchoTransparency(float transparency) {
+ echoTransparency = transparency ;
+
+ if (echoGeometry != null) {
+ Appearance a = echoGeometry.getAppearance() ;
+ TransparencyAttributes ta = a.getTransparencyAttributes() ;
+ if (echoTransparency == 0.0f) {
+ ta.setTransparencyMode(TransparencyAttributes.NONE) ;
+ ta.setTransparency(0.0f) ;
+ }
+ else {
+ ta.setTransparencyMode(TransparencyAttributes.BLENDED) ;
+ ta.setTransparency(echoTransparency) ;
+ // Use order independent additive blend for gnomon.
+ if (echoGeometry instanceof SensorGnomonEcho)
+ ta.setDstBlendFunction(TransparencyAttributes.BLEND_ONE) ;
+ }
+ }
+ }
+
+ /**
+ * Gets the 6DOF sensor echo transparency value.
+ *
+ * @return the transparency value
+ */
+ public float getEchoTransparency() {
+ return echoTransparency ;
+ }
+
+ /**
+ * Sets the transform group containing a 6DOF sensor's echo geometry.
+ * This is used to specify a custom echo. Its transform will be
+ * manipulated to represent the position and orientation of the 6DOF
+ * sensor. Capabilities to allow writing its transform and to read,
+ * write, and extend its children will be set.
+ * TransformGroup
containing the
+ * echo geometry
+ */
+ public void setEchoTransformGroup(TransformGroup echo) {
+ echo.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE) ;
+ echo.setCapability(Group.ALLOW_CHILDREN_READ) ;
+ echo.setCapability(Group.ALLOW_CHILDREN_WRITE) ;
+ echo.setCapability(Group.ALLOW_CHILDREN_EXTEND) ;
+ this.echoTransformGroup = echo ;
+ }
+
+ /**
+ * Gets the transform group containing a 6DOF sensor's echo geometry.
+ * Capabilities to write its transform and read, write, and extend its
+ * children are granted.
+ *
+ * @return the echo's transform group
+ */
+ public TransformGroup getEchoTransformGroup() {
+ return echoTransformGroup ;
+ }
+
+ /**
+ * Gets the Shape3D
defining the 6DOF sensor's echo geometry
+ * and appearance. The returned Shape3D
allows appearance
+ * read and write. If a custom echo was supplied by providing the echo
+ * transform group directly then the return value will be
+ * null
.
+ *
+ * @return the echo geometry, or null
if a custom echo was
+ * supplied
+ */
+ public Shape3D getEchoGeometry() {
+ return echoGeometry ;
+ }
+
+ /**
+ * Gets the SensorEventAgent
used by this behavior. Sensor
+ * event generation is delegated to this agent. This can be accessed to
+ * manipulate the sensor button and read action bindings directly.
+ *
+ * @return the sensor event agent
+ */
+ public SensorEventAgent getSensorEventAgent() {
+ return eventAgent ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/package.html b/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/package.html
new file mode 100644
index 0000000..81534d3
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/behaviors/vp/package.html
@@ -0,0 +1,11 @@
+
+
+org.jogamp.java3d.utils.geometry.compression
+instead.cloneTree
to duplicate the current node.
+ * cloneNode
should be overridden by any user subclassed
+ * objects. All subclasses must have their cloneNode
+ * method consist of the following lines:
+ *
+ * @param forceDuplicate when set to
+ * public Node cloneNode(boolean forceDuplicate) {
+ * UserSubClass usc = new UserSubClass();
+ * usc.duplicateNode(this, forceDuplicate);
+ * return usc;
+ * }
+ *
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.
+ *
+ * @see Node#cloneTree
+ * @see Node#duplicateNode
+ * @see NodeComponent#setDuplicateOnCloneTree
+ */
+ @Override
+ public Node cloneNode(boolean forceDuplicate) {
+ Box b = new Box(xDim, yDim, zDim, flags, getAppearance());
+ 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.
+ * 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
.
+ *
+ * @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.
+ *
+ * @see Node#cloneTree
+ * @see Node#cloneNode
+ * @see NodeComponent#setDuplicateOnCloneTree
+ */
+ @Override
+ public void duplicateNode(Node originalNode, boolean forceDuplicate) {
+ super.duplicateNode(originalNode, forceDuplicate);
+ }
+
+ /**
+ * Returns the X-dimension size of the Box
+ *
+ * @since Java 3D 1.2.1
+ */
+ public float getXdimension() {
+ return xDim;
+ }
+
+ /**
+ * Returns the Y-dimension size of the Box
+ *
+ * @since Java 3D 1.2.1
+ */
+ public float getYdimension() {
+ return yDim;
+ }
+
+ /**
+ * Returns the Z-dimension size of the Box
+ *
+ * @since Java 3D 1.2.1
+ */
+ public float getZdimension() {
+ return zDim;
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Bridge.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Bridge.java
new file mode 100644
index 0000000..15051f3
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Bridge.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+
+class Bridge {
+
+ static void constructBridges(Triangulator triRef, int loopMin, int loopMax) {
+ int i, j, numDist, numLeftMost;
+
+ int[] i0 = new int[1];
+ int[] ind0 = new int[1];
+ int[] i1 = new int[1];
+ int[] ind1 = new int[1];
+
+ int[] iTmp = new int[1];
+ int[] indTmp = new int[1];
+
+ if(triRef.noHashingEdges != true)
+ System.out.println("Bridge:constructBridges noHashingEdges is false");
+ if(loopMax <= loopMin)
+ System.out.println("Bridge:constructBridges loopMax<=loopMin");
+ if(loopMin < 0)
+ System.out.println("Bridge:constructBridges loopMin<0");
+ if(loopMax > triRef.numLoops)
+ System.out.println("Bridge:constructBridges loopMax>triRef.numLoops");
+
+ numLeftMost = loopMax - loopMin - 1;
+
+ if (numLeftMost > triRef.maxNumLeftMost) {
+ triRef.maxNumLeftMost = numLeftMost;
+ triRef.leftMost = new Left[numLeftMost];
+ }
+
+ // For each contour, find the left-most vertex. (we will use the fact
+ // that the vertices appear in sorted order!)
+ findLeftMostVertex(triRef, triRef.loops[loopMin], ind0, i0);
+ j = 0;
+ for (i = loopMin + 1; i < loopMax; ++i) {
+ findLeftMostVertex(triRef, triRef.loops[i], indTmp, iTmp);
+ triRef.leftMost[j] = new Left();
+ triRef.leftMost[j].ind = indTmp[0];
+ triRef.leftMost[j].index = iTmp[0];
+
+ ++j;
+ }
+
+ // sort the inner contours according to their left-most vertex
+ sortLeft(triRef.leftMost, numLeftMost);
+
+ // construct bridges. every bridge will eminate at the left-most point of
+ // its corresponding inner loop.
+ numDist = triRef.numPoints + 2 * triRef.numLoops;
+ triRef.maxNumDist = numDist;
+ triRef.distances = new Distance[numDist];
+ for (int k = 0; k < triRef.maxNumDist; k++)
+ triRef.distances[k] = new Distance();
+
+
+ for (j = 0; j < numLeftMost; ++j) {
+ if (!findBridge(triRef, ind0[0], i0[0], triRef.leftMost[j].index, ind1, i1)) {
+ // if (verbose)
+ // fprintf(stderr, "\n\n***** yikes! the loops intersect! *****\n");
+ }
+ if (i1[0] == triRef.leftMost[j].index)
+ // the left-most node of the hole coincides with a node of the
+ // boundary
+ simpleBridge(triRef, ind1[0], triRef.leftMost[j].ind);
+ else
+ // two bridge edges need to be inserted
+ insertBridge(triRef, ind1[0], i1[0], triRef.leftMost[j].ind,
+ triRef.leftMost[j].index);
+ }
+
+ }
+
+
+ /**
+ * We try to find a vertex i1 on the loop which contains i such that i1
+ * is close to start, and such that i1, start is a valid diagonal.
+ */
+ static boolean findBridge(Triangulator triRef, int ind, int i, int start,
+ int[] ind1, int[] i1) {
+ int i0, i2, j, numDist = 0;
+ int ind0, ind2;
+ BBox bb;
+ Distance old[] = null;
+ boolean convex, coneOk;
+
+ // sort the points according to their distance from start.
+ ind1[0] = ind;
+ i1[0] = i;
+ if (i1[0] == start) return true;
+ if (numDist >= triRef.maxNumDist) {
+ // System.out.println("(1) Expanding distances array ...");
+ triRef.maxNumDist += triRef.INC_DIST_BK;
+ old = triRef.distances;
+ triRef.distances = new Distance[triRef.maxNumDist];
+ System.arraycopy(old, 0, triRef.distances, 0, old.length);
+ for (int k = old.length; k < triRef.maxNumDist; k++)
+ triRef.distances[k] = new Distance();
+ }
+
+ triRef.distances[numDist].dist = Numerics.baseLength(triRef.points[start],
+ triRef.points[i1[0]]);
+ triRef.distances[numDist].ind = ind1[0];
+ ++numDist;
+
+
+ ind1[0] = triRef.fetchNextData(ind1[0]);
+ i1[0] = triRef.fetchData(ind1[0]);
+ while (ind1[0] != ind) {
+ if (i1[0] == start) return true;
+ if (numDist >= triRef.maxNumDist) {
+ // System.out.println("(2) Expanding distances array ...");
+ triRef.maxNumDist += triRef.INC_DIST_BK;
+ old = triRef.distances;
+ triRef.distances = new Distance[triRef.maxNumDist];
+ System.arraycopy(old, 0, triRef.distances, 0, old.length);
+ for (int k = old.length; k < triRef.maxNumDist; k++)
+ triRef.distances[k] = new Distance();
+ }
+
+ triRef.distances[numDist].dist = Numerics.baseLength(triRef.points[start],
+ triRef.points[i1[0]]);
+ triRef.distances[numDist].ind = ind1[0];
+ ++numDist;
+ ind1[0] = triRef.fetchNextData(ind1[0]);
+ i1[0] = triRef.fetchData(ind1[0]);
+ }
+
+ // qsort(distances, num_dist, sizeof(distance), &d_comp);
+ sortDistance(triRef.distances, numDist);
+
+ // find a valid diagonal. note that no node with index i1 > start can
+ // be feasible!
+ for (j = 0; j < numDist; ++j) {
+ ind1[0] = triRef.distances[j].ind;
+ i1[0] = triRef.fetchData(ind1[0]);
+ if (i1[0] <= start) {
+ ind0 = triRef.fetchPrevData(ind1[0]);
+ i0 = triRef.fetchData(ind0);
+ ind2 = triRef.fetchNextData(ind1[0]);
+ i2 = triRef.fetchData(ind2);
+ convex = triRef.getAngle(ind1[0]) > 0;
+
+ coneOk = Numerics.isInCone(triRef, i0, i1[0], i2, start, convex);
+ if (coneOk) {
+ bb = new BBox(triRef, i1[0], start);
+ if (!NoHash.noHashEdgeIntersectionExists(triRef, bb, -1, -1, ind1[0], -1))
+ return true;
+ }
+ }
+ }
+
+ // the left-most point of the hole does not lie within the outer
+ // boundary! what is the best bridge in this case??? I make a
+ // brute-force decision... perhaps this should be refined during a
+ // revision of the code...
+ for (j = 0; j < numDist; ++j) {
+ ind1[0] = triRef.distances[j].ind;
+ i1[0] = triRef.fetchData(ind1[0]);
+ ind0 = triRef.fetchPrevData(ind1[0]);
+ i0 = triRef.fetchData(ind0);
+ ind2 = triRef.fetchNextData(ind1[0]);
+ i2 = triRef.fetchData(ind2);
+ bb = new BBox(triRef, i1[0], start);
+ if (!NoHash.noHashEdgeIntersectionExists(triRef, bb, -1, -1, ind1[0], -1))
+ return true;
+ }
+
+ // still no diagonal??? yikes! oh well, this polygon is messed up badly!
+ ind1[0] = ind;
+ i1[0] = i;
+
+ return false;
+ }
+
+
+ static void findLeftMostVertex(Triangulator triRef, int ind, int[] leftInd,
+ int[] leftI) {
+ int ind1, i1;
+
+ ind1 = ind;
+ i1 = triRef.fetchData(ind1);
+ leftInd[0] = ind1;
+ leftI[0] = i1;
+ ind1 = triRef.fetchNextData(ind1);
+ i1 = triRef.fetchData(ind1);
+ while (ind1 != ind) {
+ if (i1 < leftI[0]) {
+ leftInd[0] = ind1;
+ leftI[0] = i1;
+ }
+ else if (i1 == leftI[0]) {
+ if (triRef.getAngle(ind1) < 0) {
+ leftInd[0] = ind1;
+ leftI[0] = i1;
+ }
+ }
+ ind1 = triRef.fetchNextData(ind1);
+ i1 = triRef.fetchData(ind1);
+ }
+
+ }
+
+ static void simpleBridge(Triangulator triRef, int ind1, int ind2) {
+ int prev, next;
+ int i1, i2, prv, nxt;
+ int angle;
+
+
+ // change the links
+ triRef.rotateLinks(ind1, ind2);
+
+ // reset the angles
+ i1 = triRef.fetchData(ind1);
+ next = triRef.fetchNextData(ind1);
+ nxt = triRef.fetchData(next);
+ prev = triRef.fetchPrevData(ind1);
+ prv = triRef.fetchData(prev);
+ angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind1);
+ triRef.setAngle(ind1, angle);
+
+ i2 = triRef.fetchData(ind2);
+ next = triRef.fetchNextData(ind2);
+ nxt = triRef.fetchData(next);
+ prev = triRef.fetchPrevData(ind2);
+ prv = triRef.fetchData(prev);
+ angle = Numerics.isConvexAngle(triRef, prv, i2, nxt, ind2);
+ triRef.setAngle(ind2, angle);
+
+ }
+
+
+ static void insertBridge(Triangulator triRef, int ind1, int i1,
+ int ind3, int i3) {
+ int ind2, ind4, prev, next;
+ int prv, nxt, angle;
+ int vcntIndex;
+
+ // duplicate nodes in order to form end points of the bridge edges
+ ind2 = triRef.makeNode(i1);
+ triRef.insertAfter(ind1, ind2);
+
+ // Need to get the original data, before setting it.
+
+ vcntIndex = triRef.list[ind1].getCommonIndex();
+
+ triRef.list[ind2].setCommonIndex(vcntIndex);
+
+
+ ind4 = triRef.makeNode(i3);
+ triRef.insertAfter(ind3, ind4);
+
+ vcntIndex = triRef.list[ind3].getCommonIndex();
+ triRef.list[ind4].setCommonIndex(vcntIndex);
+
+ // insert the bridge edges into the boundary loops
+ triRef.splitSplice(ind1, ind2, ind3, ind4);
+
+ // reset the angles
+ next = triRef.fetchNextData(ind1);
+ nxt = triRef.fetchData(next);
+ prev = triRef.fetchPrevData(ind1);
+ prv = triRef.fetchData(prev);
+ angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind1);
+ triRef.setAngle(ind1, angle);
+
+ next = triRef.fetchNextData(ind2);
+ nxt = triRef.fetchData(next);
+ prev = triRef.fetchPrevData(ind2);
+ prv = triRef.fetchData(prev);
+ angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind2);
+ triRef.setAngle(ind2, angle);
+
+ next = triRef.fetchNextData(ind3);
+ nxt = triRef.fetchData(next);
+ prev = triRef.fetchPrevData(ind3);
+ prv = triRef.fetchData(prev);
+ angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind3);
+ triRef.setAngle(ind3, angle);
+
+ next = triRef.fetchNextData(ind4);
+ nxt = triRef.fetchData(next);
+ prev = triRef.fetchPrevData(ind4);
+ prv = triRef.fetchData(prev);
+ angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind4);
+ triRef.setAngle(ind4, angle);
+
+ }
+
+
+ static int l_comp(Left a, Left b) {
+ if (a.index < b.index) return -1;
+ else if (a.index > b.index) return 1;
+ else return 0;
+ }
+
+ static int d_comp(Distance a, Distance b) {
+ if (a.dist < b.dist) return -1;
+ else if (a.dist > b.dist) return 1;
+ else return 0;
+ }
+
+
+ static void sortLeft(Left[] lefts, int numPts) {
+ int i,j;
+ Left swap = new Left();
+
+ for (i = 0; i < numPts; i++){
+ for (j = i + 1; j < numPts; j++){
+ if (l_comp(lefts[i], lefts[j]) > 0){
+ swap.copy(lefts[i]);
+ lefts[i].copy(lefts[j]);
+ lefts[j].copy(swap);
+ }
+ }
+ }
+ }
+
+
+ static void sortDistance(Distance[] distances, int numPts) {
+ int i,j;
+ Distance swap = new Distance();
+
+ for (i = 0; i < numPts; i++){
+ for (j = i + 1; j < numPts; j++){
+ if (d_comp(distances[i], distances[j]) > 0){
+ swap.copy(distances[i]);
+ distances[i].copy(distances[j]);
+ distances[j].copy(swap);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Clean.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Clean.java
new file mode 100644
index 0000000..41a8804
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Clean.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+import org.jogamp.vecmath.Point2f;
+
+class Clean {
+
+ static void initPUnsorted(Triangulator triRef, int number) {
+ if (number > triRef.maxNumPUnsorted) {
+ triRef.maxNumPUnsorted = number;
+ triRef.pUnsorted = new Point2f[triRef.maxNumPUnsorted];
+ for(int i = 0; igetShape
.
+ *
+ * @see Cone#getShape
+ */
+ public static final int BODY = 0;
+
+ /**
+ * Designates the end-cap of the cone. Used by getShape
.
+ *
+ * @see Cone#getShape
+ */
+ public static final int CAP = 1;
+
+ /**
+ * Constructs a default Cone of radius of 1.0 and height
+ * of 2.0. Resolution defaults to 15 divisions along X and axis
+ * and 1 along the Y axis. Normals are generated, texture
+ * coordinates are not.
+ */
+ public Cone(){
+ this(1.0f, 2.0f, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, null);
+ }
+
+ /**
+ *
+ * Constructs a default Cone of a given radius and height. Normals
+ * are generated, texture coordinates are not.
+ * @param radius Radius
+ * @param height Height
+ */
+ public Cone (float radius, float height)
+ {
+ this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, null);
+ }
+
+ /**
+ *
+ * Constructs a default cone of a given radius, height,
+ * and appearance. Normals are generated, texture coordinates are not.
+ * @param radius Radius
+ * @param height Height
+ * @param ap Appearance
+ *
+ * @since Java 3D 1.2.1
+ */
+ public Cone (float radius, float height, Appearance ap)
+ {
+ this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, ap);
+ }
+
+ /**
+ *
+ * Constructs a default cone of a given radius, height,
+ * primitive flags, and appearance.
+ * @param radius Radius
+ * @param height Height
+ * @param primflags Primitive flags
+ * @param ap Appearance
+ */
+ public Cone (float radius, float height, int primflags, Appearance ap)
+ {
+ this(radius, height, primflags, MID_REZ_DIV_X, MID_REZ_DIV_Y, ap);
+ }
+
+ /**
+ * Obtains the Shape3D node associated with one of the parts of the
+ * cone (the body or the cap). This allows users to modify the appearance
+ * or geometry of individual parts.
+ * @param partId The part to return (BODY or CAP).
+ * @return The Shape3D object associated with the partId. If an
+ * invalid partId is passed in, null is returned.
+ */
+ @Override
+ public Shape3D getShape(int partId){
+ if (partId > CAP || partId < BODY) return null;
+ return (Shape3D)getChild(partId);
+ }
+
+
+ /**
+ * Sets appearance of the cone. This will set each part of the
+ * cone (cap & body) to the same appearance. To set each
+ * part's appearance separately, use getShape(partId) to get the
+ * individual shape and call shape.setAppearance(ap).
+ */
+ @Override
+ public void setAppearance(Appearance ap){
+ ((Shape3D)getChild(BODY)).setAppearance(ap);
+ ((Shape3D)getChild(CAP)).setAppearance(ap);
+ }
+
+ /**
+ * Gets the appearance of the specified part of the cone.
+ *
+ * @param partId identifier for a given subpart of the cone
+ *
+ * @return The appearance object associated with the partID. If an
+ * invalid partId is passed in, null is returned.
+ *
+ * @since Java 3D 1.2.1
+ */
+ @Override
+ public Appearance getAppearance(int partId) {
+ if (partId > CAP || partId < BODY) return null;
+ return getShape(partId).getAppearance();
+ }
+
+
+ /**
+ * Constructs a customized Cone of a given radius, height, flags,
+ * resolution (X and Y dimensions), and appearance. The
+ * resolution is defined in terms of number of subdivisions
+ * along the object's X axis (width) and Y axis (height). More divisions
+ * lead to finer tesselated objects.
+ * cloneTree
to duplicate the current node.
+ * cloneNode
should be overridden by any user subclassed
+ * objects. All subclasses must have their cloneNode
+ * method consist of the following lines:
+ *
+ * @param forceDuplicate when set to
+ * public Node cloneNode(boolean forceDuplicate) {
+ * UserSubClass usc = new UserSubClass();
+ * usc.duplicateNode(this, forceDuplicate);
+ * return usc;
+ * }
+ *
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.
+ *
+ * @see Node#cloneTree
+ * @see Node#duplicateNode
+ * @see NodeComponent#setDuplicateOnCloneTree
+ */
+ @Override
+ public Node cloneNode(boolean forceDuplicate) {
+ Cone c = new Cone(radius, height, flags, xdivisions,
+ ydivisions, getAppearance());
+ c.duplicateNode(this, forceDuplicate);
+ return c;
+ }
+
+ /**
+ * 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.
+ * 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
.
+ *
+ * @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.
+ *
+ * @see Node#cloneTree
+ * @see Node#cloneNode
+ * @see NodeComponent#setDuplicateOnCloneTree
+ */
+ @Override
+ public void duplicateNode(Node originalNode, boolean forceDuplicate) {
+ super.duplicateNode(originalNode, forceDuplicate);
+ }
+
+ /**
+ * Returns the radius of the cone
+ *
+ * @since Java 3D 1.2.1
+ */
+ public float getRadius() {
+ return radius;
+ }
+
+ /**
+ * Returns the height of the cone
+ *
+ * @since Java 3D 1.2.1
+ */
+ public float getHeight() {
+ return height;
+ }
+
+ /**
+ * Returns the number divisions along the X direction
+ *
+ * @since Java 3D 1.2.1
+ */
+ public int getXdivisions() {
+ return xdivisions;
+ }
+
+ /**
+ * Returns the number of divisions along the height of the cone
+ *
+ * @since Java 3D 1.2.1
+ */
+ public int getYdivisions() {
+ return ydivisions;
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Cylinder.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Cylinder.java
new file mode 100644
index 0000000..99eb458
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Cylinder.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry;
+
+import org.jogamp.java3d.Appearance;
+import org.jogamp.java3d.Node;
+import org.jogamp.java3d.NodeComponent;
+import org.jogamp.java3d.Shape3D;
+
+/**
+ * Cylinder is a geometry primitive defined with a radius and a height.
+ * It is a capped cylinder centered at the origin with its central axis
+ * aligned along the Y-axis.
+ * getShape
.
+ *
+ * @see Cylinder#getShape
+ */
+ public static final int BODY = 0;
+
+ /**
+ * Designates the top end-cap of the cylinder.
+ * Used by getShape
.
+ *
+ * @see Cylinder#getShape
+ */
+ public static final int TOP = 1;
+
+ /**
+ * Designates the bottom end-cap of the cylinder.
+ * Used by getShape
.
+ *
+ * @see Cylinder#getShape
+ */
+ public static final int BOTTOM = 2;
+
+ /**
+ * Constructs a default cylinder of radius of 1.0 and height
+ * of 2.0. Normals are generated by default, texture
+ * coordinates are not. Resolution defaults to 15 divisions
+ * along X axis and 1 along the Y axis.
+ */
+ public Cylinder() {
+ this(1.0f, 2.0f, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y, null);
+ }
+
+ /**
+ * Constructs a default cylinder of a given radius and height.
+ * Normals are generated by default, texture coordinates are not.
+ * @param radius Radius
+ * @param height Height
+ */
+ public Cylinder (float radius, float height) {
+ this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y,
+ null);
+ }
+
+ /**
+ * Constructs a default cylinder of a given radius, height, and
+ * appearance. Normals are generated by default, texture
+ * coordinates are not.
+ * @param radius Radius
+ * @param height Height
+ * @param ap Appearance
+ */
+ public Cylinder (float radius, float height, Appearance ap)
+ {
+ this(radius, height, GENERATE_NORMALS, MID_REZ_DIV_X, MID_REZ_DIV_Y,
+ ap);
+ }
+
+ /**
+ *
+ * Constructs a default cylinder of a given radius, height,
+ * primitive flags and appearance.
+ * @param radius Radius
+ * @param height Height
+ * @param primflags Flags
+ * @param ap Appearance
+ */
+ public Cylinder (float radius, float height, int primflags, Appearance ap)
+ {
+ this(radius, height, primflags, MID_REZ_DIV_X, MID_REZ_DIV_Y, ap);
+ }
+
+ /**
+ * Obtains the Shape3D node associated with a given part of the cylinder.
+ * This allows users to modify the appearance or geometry
+ * of individual parts.
+ * @param partId The part to return (BODY, TOP, or BOTTOM).
+ * @return The Shape3D object associated with the partID. If an
+ * invalid partId is passed in, null is returned.
+ */
+ @Override
+ public Shape3D getShape(int partId){
+ if (partId > BOTTOM || partId < BODY) return null;
+ return (Shape3D)getChild(partId);
+ }
+
+ /** Sets appearance of the cylinder. This will set each part of the
+ * cylinder (TOP,BOTTOM,BODY) to the same appearance. To set each
+ * part's appearance separately, use getShape(partId) to get the
+ * individual shape and call shape.setAppearance(ap).
+ */
+ @Override
+ public void setAppearance(Appearance ap) {
+ ((Shape3D)getChild(BODY)).setAppearance(ap);
+ ((Shape3D)getChild(TOP)).setAppearance(ap);
+ ((Shape3D)getChild(BOTTOM)).setAppearance(ap);
+ }
+
+ /**
+ * Gets the appearance of the specified part of the cylinder.
+ *
+ * @param partId identifier for a given subpart of the cylinder
+ *
+ * @return The appearance object associated with the partID. If an
+ * invalid partId is passed in, null is returned.
+ *
+ * @since Java 3D 1.2.1
+ */
+ @Override
+ public Appearance getAppearance(int partId) {
+ if (partId > BOTTOM || partId < BODY) return null;
+ return getShape(partId).getAppearance();
+ }
+
+
+ /**
+ * Constructs a customized cylinder of a given radius, height,
+ * resolution (X and Y dimensions), and appearance. The
+ * resolution is defined in terms of number of subdivisions
+ * along the object's X axis (width) and Y axis (height). More divisions
+ * lead to more finely tesselated objects.
+ * @param radius Radius
+ * @param height Height
+ * @param xdivision Number of divisions along X direction.
+ * @param ydivision Number of divisions along height of cylinder.
+ * @param primflags Primitive flags.
+ * @param ap Appearance
+ */
+ public Cylinder(float radius, float height, int primflags,
+ int xdivision, int ydivision, Appearance ap) {
+ super();
+
+ this.radius = radius;
+ this.height = height;
+ this.xdivisions = xdivision;
+ this.ydivisions = ydivision;
+ flags = primflags;
+ boolean outside = (flags & GENERATE_NORMALS_INWARD) == 0;
+ boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0;
+ // Create many body of the cylinder.
+ Quadrics q = new Quadrics();
+ GeomBuffer gbuf = null;
+ Shape3D shape[] = new Shape3D[3];
+
+ GeomBuffer cache = getCachedGeometry(Primitive.CYLINDER,
+ (float)BODY, radius, height,
+ xdivision, ydivision, primflags);
+ if (cache != null){
+// System.out.println("using cached geometry");
+ shape[BODY] = new Shape3D(cache.getComputedGeometry());
+ numVerts += cache.getNumVerts();
+ numTris += cache.getNumTris();
+ }
+ else {
+ gbuf = q.cylinder((double)height, (double)radius,
+ xdivision, ydivision, outside, texCoordYUp);
+ shape[BODY] = new Shape3D(gbuf.getGeom(flags));
+ numVerts += gbuf.getNumVerts();
+ numTris += gbuf.getNumTris();
+ if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0)
+ cacheGeometry(Primitive.CYLINDER,
+ (float)BODY, radius, height,
+ xdivision, ydivision, primflags, gbuf);
+ }
+
+ if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
+ (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
+ (shape[BODY]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
+ }
+
+ if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
+ (shape[BODY]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
+ }
+
+ this.addChild(shape[BODY]);
+
+ // Create top of cylinder
+ cache = getCachedGeometry(Primitive.TOP_DISK, radius, radius,
+ height/2.0f, xdivision, xdivision, primflags);
+ if (cache != null) {
+// System.out.println("using cached top");
+ shape[TOP] = new Shape3D(cache.getComputedGeometry());
+ numVerts += cache.getNumVerts();
+ numTris += cache.getNumTris();
+ }
+ else {
+ gbuf = q.disk((double)radius, xdivision, height/2.0,
+ outside, texCoordYUp);
+ shape[TOP] = new Shape3D(gbuf.getGeom(flags));
+ numVerts += gbuf.getNumVerts();
+ numTris += gbuf.getNumTris();
+ if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
+ cacheGeometry(Primitive.TOP_DISK, radius, radius,
+ height/2.0f, xdivision, xdivision,
+ primflags, gbuf);
+ }
+ }
+
+ if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
+ (shape[TOP]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
+ (shape[TOP]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
+ }
+
+ if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
+ (shape[TOP]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
+ }
+
+ this.addChild(shape[TOP]);
+
+ // Create bottom
+ cache = getCachedGeometry(Primitive.BOTTOM_DISK, radius, radius,
+ -height/2.0f, xdivision, xdivision,
+ primflags);
+ if (cache != null) {
+// System.out.println("using cached bottom");
+ shape[BOTTOM] = new Shape3D(cache.getComputedGeometry());
+ numVerts += cache.getNumVerts();
+ numTris += cache.getNumTris();
+ }
+ else {
+ gbuf = q.disk((double)radius, xdivision, -height/2.0, !outside, texCoordYUp);
+ shape[BOTTOM] = new Shape3D(gbuf.getGeom(flags));
+ numVerts += gbuf.getNumVerts();
+ numTris += gbuf.getNumTris();
+ if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
+ cacheGeometry(Primitive.BOTTOM_DISK, radius, radius,
+ -height/2.0f, xdivision, xdivision,
+ primflags, gbuf);
+ }
+ }
+
+ if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
+ (shape[BOTTOM]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
+ (shape[BOTTOM]).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
+ }
+
+ if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
+ (shape[BOTTOM]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
+ }
+
+ this.addChild(shape[BOTTOM]);
+
+ // Set Appearance
+ if (ap == null){
+ setAppearance();
+ }
+ else setAppearance(ap);
+ }
+
+ /**
+ * Used to create a new instance of the node. This routine is called
+ * by cloneTree
to duplicate the current node.
+ * cloneNode
should be overridden by any user subclassed
+ * objects. All subclasses must have their cloneNode
+ * method consist of the following lines:
+ *
+ * @param forceDuplicate when set to
+ * public Node cloneNode(boolean forceDuplicate) {
+ * UserSubClass usc = new UserSubClass();
+ * usc.duplicateNode(this, forceDuplicate);
+ * return usc;
+ * }
+ *
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.
+ *
+ * @see Node#cloneTree
+ * @see Node#duplicateNode
+ * @see NodeComponent#setDuplicateOnCloneTree
+ */
+ @Override
+ public Node cloneNode(boolean forceDuplicate) {
+ Cylinder c = new Cylinder(radius, height, flags, xdivisions,
+ ydivisions, getAppearance());
+ c.duplicateNode(this, forceDuplicate);
+ return c;
+ }
+
+ /**
+ * 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.
+ * 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
.
+ *
+ * @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.
+ *
+ * @see Node#cloneTree
+ * @see Node#cloneNode
+ * @see NodeComponent#setDuplicateOnCloneTree
+ */
+ @Override
+ public void duplicateNode(Node originalNode, boolean forceDuplicate) {
+ super.duplicateNode(originalNode, forceDuplicate);
+ }
+
+ /**
+ * Returns the radius of the cylinder
+ *
+ * @since Java 3D 1.2.1
+ */
+ public float getRadius() {
+ return radius;
+ }
+
+ /**
+ * Returns the height of the cylinder
+ *
+ * @since Java 3D 1.2.1
+ */
+ public float getHeight() {
+ return height;
+ }
+
+ /**
+ * Returns the number divisions along the X direction
+ *
+ * @since Java 3D 1.2.1
+ */
+ public int getXdivisions() {
+ return xdivisions;
+ }
+
+ /**
+ * Returns the number of divisions along the height of the cylinder
+ *
+ * @since Java 3D 1.2.1
+ */
+ public int getYdivisions() {
+ return ydivisions;
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Degenerate.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Degenerate.java
new file mode 100644
index 0000000..5837058
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Degenerate.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+
+class Degenerate {
+
+ /**
+ * This function checks whether the triangle i1, i2, i3 is an ear, where
+ * the vertex i4 lies on at least one of the two edges i1, i2 or i3, i1.
+ * basically, we can cut the polygon at i4 into two pieces. the polygon
+ * touches at i4 back to back if following the next-pointers in one
+ * subpolygon and following the prev-pointers in the other subpolygon yields
+ * the same orientation for both subpolygons. otherwise, i4 forms a
+ * bottle neck of the polygon, and i1, i2, i3 is no valid ear.
+ *
+ * Note that this function may come up with the incorrect answer if the
+ * polygon has self-intersections.
+ */
+ static boolean handleDegeneracies(Triangulator triRef, int i1, int ind1, int i2,
+ int i3, int i4, int ind4) {
+ int i0, i5;
+ int type[] = new int[1];
+ int ind0, ind2, ind5;
+ boolean flag;
+ double area = 0.0, area1 = 0, area2 = 0.0;
+
+ /* assert(InPointsList(i1));
+ assert(InPointsList(i2));
+ assert(InPointsList(i3));
+ assert(InPointsList(i4));
+ */
+
+ // first check whether the successor or predecessor of i4 is inside the
+ // triangle, or whether any of the two edges incident at i4 intersects
+ // i2, i3.
+ ind5 = triRef.fetchPrevData(ind4);
+ i5 = triRef.fetchData(ind5);
+
+ // assert(ind4 != ind5);
+ //assert(InPointsList(i5));
+ if ((i5 != i2) && (i5 != i3)) {
+ flag = Numerics.vtxInTriangle(triRef, i1, i2, i3, i5, type);
+ if (flag && (type[0] == 0)) return true;
+ if (i2 <= i3) {
+ if (i4 <= i5)
+ flag = Numerics.segIntersect(triRef, i2, i3, i4, i5, -1);
+ else
+ flag = Numerics.segIntersect(triRef, i2, i3, i5, i4, -1);
+ }
+ else {
+ if (i4 <= i5)
+ flag = Numerics.segIntersect(triRef, i3, i2, i4, i5, -1);
+ else
+ flag = Numerics.segIntersect(triRef, i3, i2, i5, i4, -1);
+ }
+ if (flag)
+ return true;
+ }
+
+ ind5 = triRef.fetchNextData(ind4);
+ i5 = triRef.fetchData(ind5);
+ // assert(ind4 != ind5);
+ // assert(InPointsList(i5));
+ if ((i5 != i2) && (i5 != i3)) {
+ flag = Numerics.vtxInTriangle(triRef, i1, i2, i3, i5, type);
+ if (flag && (type[0] == 0)) return true;
+ if (i2 <= i3) {
+ if (i4 <= i5) flag = Numerics.segIntersect(triRef, i2, i3, i4, i5, -1);
+ else flag = Numerics.segIntersect(triRef, i2, i3, i5, i4, -1);
+ }
+ else {
+ if (i4 <= i5) flag = Numerics.segIntersect(triRef, i3, i2, i4, i5, -1);
+ else flag = Numerics.segIntersect(triRef, i3, i2, i5, i4, -1);
+ }
+ if (flag) return true;
+ }
+
+ i0 = i1;
+ ind0 = ind1;
+ ind1 = triRef.fetchNextData(ind1);
+ i1 = triRef.fetchData(ind1);
+ while (ind1 != ind4) {
+ ind2 = triRef.fetchNextData(ind1);
+ i2 = triRef.fetchData(ind2);
+ area = Numerics.stableDet2D(triRef, i0, i1, i2);
+ area1 += area;
+ ind1 = ind2;
+ i1 = i2;
+ }
+
+ ind1 = triRef.fetchPrevData(ind0);
+ i1 = triRef.fetchData(ind1);
+ while (ind1 != ind4) {
+ ind2 = triRef.fetchPrevData(ind1);
+ i2 = triRef.fetchData(ind2);
+ area = Numerics.stableDet2D(triRef, i0, i1, i2);
+ area2 += area;
+ ind1 = ind2;
+ i1 = i2;
+ }
+
+ if (Numerics.le(area1, triRef.ZERO) && Numerics.le(area2, triRef.ZERO))
+ return false;
+ else if (Numerics.ge(area1, triRef.ZERO) && Numerics.ge(area2, triRef.ZERO))
+ return false;
+ else
+ return true;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Desperate.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Desperate.java
new file mode 100644
index 0000000..e82a991
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Desperate.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+import org.jogamp.vecmath.Point2f;
+
+class Desperate {
+
+ /**
+ * the functions in this file try to ensure that we always end up with
+ * something that (topologically) is a triangulation.
+ *
+ * the more desperate we get, the more aggressive means we choose for making
+ * diagonals "valid".
+ */
+ static boolean desperate(Triangulator triRef, int ind, int i, boolean[] splitted) {
+ int[] i1 = new int[1];
+ int[] i2 = new int[1];
+ int[] i3 = new int[1];
+ int[] i4 = new int[1];
+ int[] ind1 = new int[1];
+ int[] ind2 = new int[1];
+ int[] ind3 = new int[1];
+ int[] ind4 = new int[1];
+
+ splitted[0] = false;
+
+ // check whether there exist consecutive vertices i1, i2, i3, i4 such
+ // that i1, i2 and i3, i4 intersect
+ if (existsCrossOver(triRef, ind, ind1, i1, ind2, i2, ind3, i3, ind4, i4)) {
+ // insert two new diagonals around the cross-over without checking
+ // whether they are intersection-free
+ handleCrossOver(triRef, ind1[0], i1[0], ind2[0], i2[0], ind3[0], i3[0],
+ ind4[0], i4[0]);
+ return false;
+ }
+
+ NoHash.prepareNoHashEdges(triRef, i, i+1);
+
+ // check whether there exists a valid diagonal that splits the polygon
+ // into two parts
+ if (existsSplit(triRef, ind, ind1, i1, ind2, i2)) {
+ // break up the polygon by inserting this diagonal (which can't be an
+ // ear -- otherwise, we would not have ended up in this part of the
+ // code). then, let's treat the two polygons separately. hopefully,
+ // this will help to handle self-overlapping polygons in the "correct"
+ // way.
+ handleSplit(triRef, ind1[0], i1[0], ind2[0], i2[0]);
+ splitted[0] = true;
+ return false;
+ }
+
+ return true;
+ }
+
+
+ static boolean existsCrossOver(Triangulator triRef, int ind, int[] ind1, int[] i1,
+ int[] ind2, int[] i2, int[] ind3, int[] i3,
+ int[] ind4, int[] i4) {
+ BBox bb1, bb2;
+
+ ind1[0] = ind;
+ i1[0] = triRef.fetchData(ind1[0]);
+ ind2[0] = triRef.fetchNextData(ind1[0]);
+ i2[0] = triRef.fetchData(ind2[0]);
+ ind3[0] = triRef.fetchNextData(ind2[0]);
+ i3[0] = triRef.fetchData(ind3[0]);
+ ind4[0] = triRef.fetchNextData(ind3[0]);
+ i4[0] = triRef.fetchData(ind4[0]);
+
+ do {
+ bb1 = new BBox(triRef, i1[0], i2[0]);
+ bb2 = new BBox(triRef, i3[0], i4[0]);
+ if (bb1.BBoxOverlap(bb2)) {
+ if (Numerics.segIntersect(triRef, bb1.imin, bb1.imax, bb2.imin, bb2.imax, -1))
+ return true;
+ }
+ ind1[0] = ind2[0];
+ i1[0] = i2[0];
+ ind2[0] = ind3[0];
+ i2[0] = i3[0];
+ ind3[0] = ind4[0];
+ i3[0] = i4[0];
+ ind4[0] = triRef.fetchNextData(ind3[0]);
+ i4[0] = triRef.fetchData(ind4[0]);
+
+ } while (ind1[0] != ind);
+
+ return false;
+ }
+
+
+ static void handleCrossOver(Triangulator triRef, int ind1, int i1, int ind2,
+ int i2, int ind3, int i3, int ind4, int i4) {
+ double ratio1, ratio4;
+ boolean first;
+ int angle1, angle4;
+
+ // which pair of triangles shall I insert?? we can use either i1, i2, i3
+ // and i1, i3, i4, or we can use i2, i3, i4 and i1, i2, i4...
+ angle1 = triRef.getAngle(ind1);
+ angle4 = triRef.getAngle(ind4);
+ if (angle1 < angle4) first = true;
+ else if (angle1 > angle4) first = false;
+ else if (triRef.earsSorted) {
+ ratio1 = Numerics.getRatio(triRef, i3, i4, i1);
+ ratio4 = Numerics.getRatio(triRef, i1, i2, i4);
+ if (ratio4 < ratio1) first = false;
+ else first = true;
+ }
+ else {
+ first = true;
+ }
+
+ if (first) {
+ // first clip i1, i2, i3, then clip i1, i3, i4
+ triRef.deleteLinks(ind2);
+ // StoreTriangle(GetOriginal(ind1), GetOriginal(ind2), GetOriginal(ind3));
+ triRef.storeTriangle(ind1, ind2, ind3);
+ triRef.setAngle(ind3, 1);
+ Heap.insertIntoHeap(triRef, 0.0, ind3, ind1, ind4);
+ }
+ else {
+ // first clip i2, i3, i4, then clip i1, i2, i4
+ triRef.deleteLinks(ind3);
+ //StoreTriangle(GetOriginal(ind2), GetOriginal(ind3), GetOriginal(ind4));
+ triRef.storeTriangle(ind2, ind3, ind4);
+ triRef.setAngle(ind2, 1);
+ Heap.insertIntoHeap(triRef, 0.0, ind2, ind1, ind4);
+ }
+ }
+
+
+ static boolean letsHope(Triangulator triRef, int ind) {
+ int ind0, ind1, ind2;
+ int i0, i1, i2;
+
+ // let's clip the first convex corner. of course, we know that this is no
+ // ear in an ideal world. but this polygon isn't ideal, either!
+ ind1 = ind;
+ i1 = triRef.fetchData(ind1);
+
+ do {
+ if (triRef.getAngle(ind1) > 0) {
+ ind0 = triRef.fetchPrevData(ind1);
+ i0 = triRef.fetchData(ind0);
+ ind2 = triRef.fetchNextData(ind1);
+ i2 = triRef.fetchData(ind2);
+ Heap.insertIntoHeap(triRef, 0.0, ind1, ind0, ind2);
+ return true;
+ }
+ ind1 = triRef.fetchNextData(ind1);
+ i1 = triRef.fetchData(ind1);
+ } while (ind1 != ind);
+
+ // no convex corners? so, let's cheat! this code won't stop without some
+ // triangulation... ;-) g-i-g-o? right! perhaps, this is what you
+ // call a robust code?!
+ triRef.setAngle(ind, 1);
+ ind0 = triRef.fetchPrevData(ind);
+ i0 = triRef.fetchData(ind0);
+ ind2 = triRef.fetchNextData(ind);
+ i2 = triRef.fetchData(ind2);
+ Heap.insertIntoHeap(triRef, 0.0, ind, ind0, ind2);
+ i1 = triRef.fetchData(ind);
+
+ return true;
+
+ // see, we never have to return "false"...
+ /*
+ return false;
+ */
+ }
+
+
+ static boolean existsSplit(Triangulator triRef, int ind, int[] ind1, int[] i1,
+ int[] ind2, int[] i2) {
+ int ind3, ind4, ind5;
+ int i3, i4, i5;
+
+ if (triRef.numPoints > triRef.maxNumDist) {
+ // System.out.println("Desperate: Expanding distances array ...");
+ triRef.maxNumDist = triRef.numPoints;
+ triRef.distances = new Distance[triRef.maxNumDist];
+ for (int k = 0; k < triRef.maxNumDist; k++)
+ triRef.distances[k] = new Distance();
+ }
+ ind1[0] = ind;
+ i1[0] = triRef.fetchData(ind1[0]);
+ ind4 = triRef.fetchNextData(ind1[0]);
+ i4 = triRef.fetchData(ind4);
+ // assert(*ind1 != ind4);
+ ind5 = triRef.fetchNextData(ind4);
+ i5 = triRef.fetchData(ind5);
+ // assert(*ind1 != *ind2);
+ ind3 = triRef.fetchPrevData(ind1[0]);
+ i3 = triRef.fetchData(ind3);
+ // assert(*ind2 != ind3);
+ if (foundSplit(triRef, ind5, i5, ind3, ind1[0], i1[0], i3, i4, ind2, i2))
+ return true;
+ i3 = i1[0];
+ ind1[0] = ind4;
+ i1[0] = i4;
+ ind4 = ind5;
+ i4 = i5;
+ ind5 = triRef.fetchNextData(ind4);
+ i5 = triRef.fetchData(ind5);
+
+ while (ind5 != ind) {
+ if (foundSplit(triRef, ind5, i5, ind, ind1[0], i1[0], i3, i4, ind2, i2))
+ return true;
+ i3 = i1[0];
+ ind1[0] = ind4;
+ i1[0] = i4;
+ ind4 = ind5;
+ i4 = i5;
+ ind5 = triRef.fetchNextData(ind4);
+ i5 = triRef.fetchData(ind5);
+ }
+
+ return false;
+ }
+
+
+ /**
+ * This function computes the winding number of a polygon with respect to a
+ * point p. no care is taken to handle cases where p lies on the
+ * boundary of the polygon. (this is no issue in our application, as we will
+ * always compute the winding number with respect to the mid-point of a
+ * valid diagonal.)
+ */
+ static int windingNumber(Triangulator triRef, int ind, Point2f p) {
+ double angle;
+ int ind2;
+ int i1, i2, number;
+
+ i1 = triRef.fetchData(ind);
+ ind2 = triRef.fetchNextData(ind);
+ i2 = triRef.fetchData(ind2);
+ angle = Numerics.angle(triRef, p, triRef.points[i1], triRef.points[i2]);
+ while (ind2 != ind) {
+ i1 = i2;
+ ind2 = triRef.fetchNextData(ind2);
+ i2 = triRef.fetchData(ind2);
+ angle += Numerics.angle(triRef, p, triRef.points[i1], triRef.points[i2]);
+ }
+
+ angle += Math.PI;
+ number = (int)(angle / (Math.PI*2.0));
+
+ return number;
+ }
+
+
+
+
+ static boolean foundSplit(Triangulator triRef, int ind5, int i5, int ind, int ind1,
+ int i1, int i3, int i4, int[] ind2, int[] i2) {
+ Point2f center;
+ int numDist = 0;
+ int j, i6, i7;
+ int ind6, ind7;
+ BBox bb;
+ boolean convex, coneOk;
+
+ // Sort the points according to their distance from i1
+ do {
+ // assert(numDist < triRef.maxNumDist);
+ triRef.distances[numDist].dist = Numerics.baseLength(triRef.points[i1],
+ triRef.points[i5]);
+ triRef.distances[numDist].ind = ind5;
+ ++numDist;
+ ind5 = triRef.fetchNextData(ind5);
+ i5 = triRef.fetchData(ind5);
+ } while (ind5 != ind);
+
+ Bridge.sortDistance(triRef.distances, numDist);
+
+ // find a valid diagonal.
+ for (j = 0; j < numDist; ++j) {
+ ind2[0] = triRef.distances[j].ind;
+ i2[0] = triRef.fetchData(ind2[0]);
+ if (i1 != i2[0]) {
+ ind6 = triRef.fetchPrevData(ind2[0]);
+ i6 = triRef.fetchData(ind6);
+ ind7 = triRef.fetchNextData(ind2[0]);
+ i7 = triRef.fetchData(ind7);
+
+ convex = triRef.getAngle(ind2[0]) > 0;
+ coneOk = Numerics.isInCone(triRef, i6, i2[0], i7, i1, convex);
+ if (coneOk) {
+ convex = triRef.getAngle(ind1) > 0;
+ coneOk = Numerics.isInCone(triRef, i3, i1, i4, i2[0], convex);
+ if (coneOk) {
+ bb = new BBox(triRef, i1, i2[0]);
+ if (!NoHash.noHashEdgeIntersectionExists(triRef, bb, -1, -1, ind1, -1)) {
+ // check whether this is a good diagonal; we do not want a
+ // diagonal that may create figure-8's!
+ center = new Point2f();
+ Basic.vectorAdd2D(triRef.points[i1], triRef.points[i2[0]], center);
+ Basic.multScalar2D(0.5, center);
+ if (windingNumber(triRef, ind, center) == 1) return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ static void handleSplit(Triangulator triRef, int ind1, int i1, int ind3, int i3) {
+ int ind2, ind4, prev, next;
+ int prv, nxt, angle;
+ int vIndex, comIndex = -1;
+
+ // duplicate nodes in order to form end points of the new diagonal
+ ind2 = triRef.makeNode(i1);
+ triRef.insertAfter(ind1, ind2);
+
+ // Need to get the original data, before setting it.
+
+ comIndex = triRef.list[ind1].getCommonIndex();
+
+ triRef.list[ind2].setCommonIndex(comIndex);
+
+ ind4 = triRef.makeNode(i3);
+ triRef.insertAfter(ind3, ind4);
+
+ comIndex = triRef.list[ind3].getCommonIndex();
+ triRef.list[ind4].setCommonIndex(comIndex);
+
+ // insert the diagonal into the boundary loop, thus splitting the loop
+ // into two loops
+ triRef.splitSplice(ind1, ind2, ind3, ind4);
+
+ // store pointers to the two new loops
+ triRef.storeChain(ind1);
+ triRef.storeChain(ind3);
+
+ // reset the angles
+ next = triRef.fetchNextData(ind1);
+ nxt = triRef.fetchData(next);
+ prev = triRef.fetchPrevData(ind1);
+ prv = triRef.fetchData(prev);
+ angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind1);
+ triRef.setAngle(ind1, angle);
+
+ next = triRef.fetchNextData(ind2);
+ nxt = triRef.fetchData(next);
+ prev = triRef.fetchPrevData(ind2);
+ prv = triRef.fetchData(prev);
+ angle = Numerics.isConvexAngle(triRef, prv, i1, nxt, ind2);
+ triRef.setAngle(ind2, angle);
+
+ next = triRef.fetchNextData(ind3);
+ nxt = triRef.fetchData(next);
+ prev = triRef.fetchPrevData(ind3);
+ prv = triRef.fetchData(prev);
+ angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind3);
+ triRef.setAngle(ind3, angle);
+
+ next = triRef.fetchNextData(ind4);
+ nxt = triRef.fetchData(next);
+ prev = triRef.fetchPrevData(ind4);
+ prv = triRef.fetchData(prev);
+ angle = Numerics.isConvexAngle(triRef, prv, i3, nxt, ind4);
+ triRef.setAngle(ind4, angle);
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Distance.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Distance.java
new file mode 100644
index 0000000..7b5b59e
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Distance.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+class Distance extends Object {
+ int ind;
+ double dist;
+
+ Distance() {
+ }
+
+ void copy(Distance d) {
+ ind = d.ind;
+ dist = d.dist;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/EarClip.java b/src/classes/share/org/jogamp/java3d/utils/geometry/EarClip.java
new file mode 100644
index 0000000..12ca16b
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/EarClip.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+
+class EarClip {
+
+ /**
+ * Classifies all the internal angles of the loop referenced by ind.
+ * the following classification is used:
+ * 0 ... if angle is 180 degrees
+ * 1 ... if angle between 0 and 180 degrees
+ * 2 ... if angle is 0 degrees
+ * -1 ... if angle between 180 and 360 degrees
+ * -2 ... if angle is 360 degrees
+ */
+ static void classifyAngles(Triangulator triRef, int ind) {
+ int ind0, ind1, ind2;
+ int i0, i1, i2;
+ int angle;
+
+ ind1 = ind;
+ i1 = triRef.fetchData(ind1);
+ ind0 = triRef.fetchPrevData(ind1);
+ i0 = triRef.fetchData(ind0);
+
+ do {
+ ind2 = triRef.fetchNextData(ind1);
+ i2 = triRef.fetchData(ind2);
+ angle = Numerics.isConvexAngle(triRef, i0, i1, i2, ind1);
+ triRef.setAngle(ind1, angle);
+ i0 = i1;
+ i1 = i2;
+ ind1 = ind2;
+ } while (ind1 != ind);
+
+ }
+
+
+ static void classifyEars(Triangulator triRef, int ind) {
+ int ind1;
+ int i1;
+ int[] ind0, ind2;
+ double[] ratio;
+
+ ind0 = new int[1];
+ ind2 = new int[1];
+ ratio = new double[1];
+
+ Heap.initHeap(triRef);
+
+ ind1 = ind;
+ i1 = triRef.fetchData(ind1);
+
+ do {
+ if ((triRef.getAngle(ind1) > 0) &&
+ isEar(triRef, ind1, ind0, ind2, ratio)) {
+
+ Heap.dumpOnHeap(triRef, ratio[0], ind1, ind0[0], ind2[0]);
+ }
+ ind1 = triRef.fetchNextData(ind1);
+ i1 = triRef.fetchData(ind1);
+ } while (ind1 != ind);
+
+ // Not using sorted_ear so don't have to do MakeHeap();
+ // MakeHeap();
+
+ // Heap.printHeapData(triRef);
+
+ }
+
+
+ /**
+ * This function checks whether a diagonal is valid, that is, whether it is
+ * locally within the polygon, and whether it does not intersect any other
+ * segment of the polygon. also, some degenerate cases get a special
+ * handling.
+ */
+ static boolean isEar(Triangulator triRef, int ind2, int[] ind1, int[] ind3,
+ double[] ratio) {
+ int i0, i1, i2, i3, i4;
+ int ind0, ind4;
+ BBox bb;
+ boolean convex, coneOk;
+
+ i2 = triRef.fetchData(ind2);
+ ind3[0] = triRef.fetchNextData(ind2);
+ i3 = triRef.fetchData(ind3[0]);
+ ind4 = triRef.fetchNextData(ind3[0]);
+ i4 = triRef.fetchData(ind4);
+ ind1[0] = triRef.fetchPrevData(ind2);
+ i1 = triRef.fetchData(ind1[0]);
+ ind0 = triRef.fetchPrevData(ind1[0]);
+ i0 = triRef.fetchData(ind0);
+
+ /*
+ System.out.println("isEar : i0 " + i0 + " i1 " + i1 + " i2 " + i2 +
+ " i3 " + i3 + " i4 " + i4);
+ */
+
+ if ((i1 == i3) || (i1 == i2) || (i2 == i3) || (triRef.getAngle(ind2) == 2)) {
+ // oops, this is not a simple polygon!
+ ratio[0] = 0.0;
+ return true;
+ }
+
+ if (i0 == i3) {
+ // again, this is not a simple polygon!
+ if ((triRef.getAngle(ind0) < 0) || (triRef.getAngle(ind3[0]) < 0)) {
+ ratio[0] = 0.0;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ if (i1 == i4) {
+ // again, this is not a simple polygon!
+ if ((triRef.getAngle(ind1[0]) < 0) || (triRef.getAngle(ind4) < 0)) {
+ ratio[0] = 0.0;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ // check whether the new diagonal i1, i3 locally is within the polygon
+ convex = triRef.getAngle(ind1[0]) > 0;
+ coneOk = Numerics.isInCone(triRef, i0, i1, i2, i3, convex);
+ // System.out.println("isEar :(1) convex " + convex + " coneOk " + coneOk );
+
+ if (!coneOk) return false;
+ convex = triRef.getAngle(ind3[0]) > 0;
+ coneOk = Numerics.isInCone(triRef, i2, i3, i4, i1, convex);
+ // System.out.println("isEar :(2) convex " + convex + " coneOk " + coneOk );
+
+ if (coneOk) {
+ // check whether this diagonal is a valid diagonal. this translates to
+ // checking either condition CE1 or CE2 (see my paper). If CE1 is to
+ // to be checked, then we use a BV-tree or a grid. Otherwise, we use
+ // "buckets" (i.e., a grid) or no hashing at all.
+ bb = new BBox(triRef, i1, i3);
+ // use CE2 + no_hashing
+ if(!NoHash.noHashIntersectionExists(triRef, i2, ind2, i3, i1, bb)) {
+ if (triRef.earsSorted) {
+ // determine the quality of the triangle
+ ratio[0] = Numerics.getRatio(triRef, i1, i3, i2);
+ }
+ else {
+ ratio[0] = 1.0;
+ }
+ return true;
+ }
+ }
+
+ // System.out.println("isEar : false");
+ return false;
+ }
+
+
+
+ /**
+ * This is the main function that drives the ear-clipping. it obtains an ear
+ * from set of ears maintained in a priority queue, clips this ear, and
+ * updates all data structures appropriately. (ears are arranged in the
+ * priority queue (i.e., heap) according to a quality criterion that tries
+ * to avoid skinny triangles.)
+ */
+ static boolean clipEar(Triangulator triRef, boolean[] done) {
+
+ int ind0, ind1, ind3, ind4;
+
+ int i0, i1, i2, i3, i4;
+ int angle1, angle3;
+
+ double ratio[] = new double[1];
+ int index0[] = new int[1];
+ int index1[] = new int[1];
+ int index2[] = new int[1];
+ int index3[] = new int[1];
+ int index4[] = new int[1];
+ int ind2[] = new int[1];
+
+ int testCnt = 0;
+
+ // Heap.printHeapData(triRef);
+
+ do {
+
+ // System.out.println("In clipEarloop " + testCnt++);
+
+ if (!Heap.deleteFromHeap(triRef, ind2, index1, index3))
+ // no ear exists?!
+ return false;
+
+ // get the successors and predecessors in the list of nodes and check
+ // whether the ear still is part of the boundary
+ ind1 = triRef.fetchPrevData(ind2[0]);
+ i1 = triRef.fetchData(ind1);
+ ind3 = triRef.fetchNextData(ind2[0]);
+ i3 = triRef.fetchData(ind3);
+
+ } while ((index1[0] != ind1) || (index3[0] != ind3));
+
+ //System.out.println("Out of clipEarloop ");
+
+ i2 = triRef.fetchData(ind2[0]);
+
+ // delete the clipped ear from the list of nodes, and update the bv-tree
+ triRef.deleteLinks(ind2[0]);
+
+ // store the ear in a list of ears which have already been clipped
+ // StoreTriangle(GetOriginal(ind1), GetOriginal(ind2), GetOriginal(ind3));
+ triRef.storeTriangle(ind1, ind2[0], ind3);
+
+ /* */
+ /* update the angle classification at ind1 and ind3 */
+ /* */
+ ind0 = triRef.fetchPrevData(ind1);
+ i0 = triRef.fetchData(ind0);
+ if (ind0 == ind3) {
+ // nothing left
+ done[0] = true;
+ return true;
+ }
+ angle1 = Numerics.isConvexAngle(triRef, i0, i1, i3, ind1);
+
+ ind4 = triRef.fetchNextData(ind3);
+ i4 = triRef.fetchData(ind4);
+
+ angle3 = Numerics.isConvexAngle(triRef, i1, i3, i4, ind3);
+
+ if (i1 != i3) {
+ if ((angle1 >= 0) && (triRef.getAngle(ind1) < 0))
+ NoHash.deleteReflexVertex(triRef, ind1);
+ if ((angle3 >= 0) && (triRef.getAngle(ind3) < 0))
+ NoHash.deleteReflexVertex(triRef, ind3);
+ }
+ else {
+ if ((angle1 >= 0) && (triRef.getAngle(ind1) < 0))
+ NoHash.deleteReflexVertex(triRef, ind1);
+ else if ((angle3 >= 0) && (triRef.getAngle(ind3) < 0))
+ NoHash.deleteReflexVertex(triRef, ind3);
+
+ }
+
+ triRef.setAngle(ind1, angle1);
+ triRef.setAngle(ind3, angle3);
+
+ // check whether either of ind1 and ind3 is an ear. (the "ratio" is
+ // the length of the triangle's longest side divided by the length of the
+ // height normal onto this side; it is used as a quality criterion.)
+ if (angle1 > 0) {
+ if (isEar(triRef, ind1, index0, index2, ratio)) {
+ // insert the new ear into the priority queue of ears
+ Heap.insertIntoHeap(triRef, ratio[0], ind1, index0[0], index2[0]);
+ }
+ }
+
+ if (angle3 > 0) {
+ if(isEar(triRef, ind3, index2, index4, ratio)) {
+ Heap.insertIntoHeap(triRef, ratio[0], ind3, index2[0], index4[0]);
+ }
+ }
+
+ // check whether the triangulation is finished.
+ ind0 = triRef.fetchPrevData(ind1);
+ i0 = triRef.fetchData(ind0);
+ ind4 = triRef.fetchNextData(ind3);
+ i4 = triRef.fetchData(ind4);
+ if (ind0 == ind4) {
+ // only one triangle left -- clip it!
+ triRef.storeTriangle(ind1, ind3, ind4);
+ done[0] = true;
+ }
+ else {
+ done[0] = false;
+ }
+
+ return true;
+ }
+
+}
+
+
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Edge.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Edge.java
new file mode 100644
index 0000000..3f8ccbe
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Edge.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry;
+
+// Class created so that the two vertex indices that make up an
+// edge can be hashed.
+class Edge {
+
+ public int v1;
+ public int v2;
+ private static final int HASHCONST = 0xEDCBA987;
+
+ @Override
+ public int hashCode()
+ {
+ return ((v1 * HASHCONST) << 2) ^ (v2 * HASHCONST);
+ } // end of Edge.hashCode
+
+ @Override
+ public boolean equals(Object x)
+ {
+ if (!(x instanceof Edge)) return false;
+ Edge e = (Edge)x;
+ return (v1 == e.v1) && (v2 == e.v2);
+ } // End of Edge.equals
+
+ @Override
+ public String toString()
+ {
+ return "(" + v1 + ", " + v2 + ")";
+ } // End of toString
+
+ public Edge(int a, int b)
+ {
+ v1 = a;
+ v2 = b;
+ }
+
+ public Edge(Edge e)
+ {
+ v1 = e.v1;
+ v2 = e.v2;
+ }
+
+ public Edge()
+ {
+ }
+} // end of class Edge
+
+// End of file Edge.java
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/EdgeTable.java b/src/classes/share/org/jogamp/java3d/utils/geometry/EdgeTable.java
new file mode 100644
index 0000000..dc9180e
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/EdgeTable.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+class EdgeTable {
+
+ private HashMap edgeTable;
+ private static final int DEBUG = 0;
+
+
+
+ Integer get(int a, int b)
+ {
+ return (Integer)edgeTable.get(new Edge(a, b));
+ } // End of get()
+
+
+ Integer get(Edge e)
+ {
+ return (Integer)edgeTable.get(e);
+ } // End of get()
+
+
+
+ // This function creates a table used to connect the triangles.
+ // Here's how it works. If a triangle is made of indices 12,
+ // 40, and 51, then edge(12, 40) gets 51, edge(40, 51) gets 12,
+ // and edge(51, 12) gets 40. This lets us quickly move from
+ // triangle to triangle without saving a lot of extra data.
+ EdgeTable(int triangleIndices[])
+ {
+ // We'll have one edge for each vertex
+ edgeTable = new HashMap(triangleIndices.length * 2);
+
+ // Fill in table
+ Edge e;
+ for (int t = 0 ; t < triangleIndices.length ; t += 3) {
+ // Put all 3 edges of triangle into table
+ for (int v = 0 ; v < 3 ; v++) {
+ e = new Edge(triangleIndices[t + v],
+ triangleIndices[t + ((v + 1) % 3)]);
+
+ if (edgeTable.get(e) != null) {
+ if ((DEBUG & 1) != 0) {
+ System.out.println("EdgeTable Error: duplicate edge (" +
+ triangleIndices[t + v] + ", " +
+ triangleIndices[t + ((v + 1) % 3)] + ").");
+ }
+ } else {
+ // Store index of 3rd vertex (across from edge)
+ edgeTable.put(e, new Integer(t + ((v + 2) % 3)));
+ }
+ }
+ }
+
+ if ((DEBUG & 1) != 0) {
+ System.out.println("Edge Table:");
+ Iterator list = edgeTable.keySet().iterator();
+ while (list.hasNext()) {
+ Edge edge = (Edge)list.next();
+ System.out.println(" (" + edge.v1 + ", " + edge.v2 + ") = " +
+ get(edge.v1, edge.v2));
+ }
+ }
+ } // End of constructor EdgeTable
+
+} // End of class EdgeTable
+
+// End of file EdgeTable.java
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/GeomBuffer.java b/src/classes/share/org/jogamp/java3d/utils/geometry/GeomBuffer.java
new file mode 100644
index 0000000..f03e89a
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/GeomBuffer.java
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry;
+
+import org.jogamp.java3d.Geometry;
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.QuadArray;
+import org.jogamp.java3d.TriangleArray;
+import org.jogamp.java3d.TriangleFanArray;
+import org.jogamp.java3d.TriangleStripArray;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.TexCoord2f;
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * GeomBuffer allows OpenGL-like input of geometry data. It outputs
+ * Java 3D geometry array objects. This utility is to simplify porting
+ * of OpenGL programs to Java 3D.
+ *
+ * Notice, that you only need to specify some upperbound on the number of
+ * points you'll use at the beginning (100 in this case).
+ *
+ *
+ * GeomBuffer gbuf = new GeomBuffer(100);
+ * gbuf.begin(GeomBuffer.QUADS);
+ *
+ * for (int i = 0; i < 5; i++){
+ * gbuf.normal3d(0.0, 1.0, 0.0);
+ * gbuf.vertex3d(1.0, 1.0, 0.0);
+ *
+ * gbuf.normal3d(0.0, 1.0, 0.0);
+ * gbuf.vertex3d(0.0, 1.0, 0.0);
+ *
+ * gbuf.normal3d(0.0, 1.0, 0.0);
+ * gbuf.vertex3d(0.0, 0.0, 0.0);
+ *
+ * gbuf.normal3d(0.0, 1.0, 0.0);
+ * gbuf.vertex3d(1.0, 0.0, 0.0);
+ * }
+ * gbuf.end();
+ * Shape3D shape = new Shape3D(gbuf.getGeom(GeomBuffer.GENERATE_NORMALS));
+ *
+ *
+ * The NormalGenerator adds normals to geometry without normals.
+ *
+ * Also, the GeometryCompressor can take a set of GeometryInfo objects in a
+ * CompressionSteam and generate a CompressedGeometry object from the
+ * geometry.
+ *
+ * @see NormalGenerator
+ * @see Stripifier
+ * @see org.jogamp.java3d.utils.compression.CompressionStream
+ * @see org.jogamp.java3d.utils.compression.GeometryCompressor
+ * @see org.jogamp.java3d.GeometryArray
+ */
+
+public class GeometryInfo {
+
+ /**
+ * Send to the constructor to inform that the data will be arranged so
+ * that each set of three vertices form an independent triangle
+ */
+ public static final int TRIANGLE_ARRAY = 1;
+
+ /**
+ * Send to the constructor to inform that the data will be arranged so
+ * that each set of four vertices form an independent quad
+ */
+ public static final int QUAD_ARRAY = 2;
+
+ /**
+ * Send to the constructor to inform that the data will be arranged so
+ * that the stripCounts array indicates how many vertices to use
+ * for each triangle fan.
+ */
+ public static final int TRIANGLE_FAN_ARRAY = 3;
+
+ /**
+ * Send to the constructor to inform that the data will be arranged so
+ * that the stripCounts array indicates how many vertices to use
+ * for each triangle strip.
+ */
+ public static final int TRIANGLE_STRIP_ARRAY = 4;
+
+ /**
+ * Send to the constructor to inform that the data is arranged as
+ * possibly multi-contour, possible non-planar polygons.
+ * The stripCounts array indicates how many vertices to use
+ * for each contour, and the contourCounts array indicates how many
+ * stripCounts entries to use for each polygon. The first
+ * contour is the bounding polygon, and subsequent contours are
+ * "holes." If contourCounts is left null, the default is
+ * one contour per polygon.
+ */
+ public static final int POLYGON_ARRAY = 5;
+
+ private int prim;
+
+ // 1 Show indexification details
+ private static final int DEBUG = 0;
+
+ private Point3f coordinates[] = null;
+ private Color3f colors3[] = null;
+ private Color4f colors4[] = null;
+ private Vector3f normals[] = null;
+ private Object texCoordSets[][] = null;
+
+ private int coordinateIndices[] = null;
+ private int colorIndices[] = null;
+ private int normalIndices[] = null;
+ private int texCoordIndexSets[][] = null;
+
+ private int[] texCoordSetMap = null;
+ private int texCoordSetCount = 0;
+ private int texCoordDim = 0;
+
+ private int stripCounts[] = null;
+ private int contourCounts[] = null;
+
+ private Triangulator tr = null;
+ private NormalGenerator ng = null;
+
+ private int oldPrim = 0;
+ private int oldStripCounts[] = null;
+
+ private boolean coordOnly = false;
+
+
+
+ /**
+ * Constructor.
+ * Creates an empty GeometryInfo object.
+ * @param primitive Tells the GeometryInfo object the type of
+ * primitive data to be stored
+ * in it, so it will know the format of the data. It can be one of
+ * TRIANGLE_ARRAY,
+ * QUAD_ARRAY, TRIANGLE_FAN_ARRAY, TRIANGLE_STRIP_ARRAY, or POLYGON_ARRAY.
+ */
+ public GeometryInfo(int primitive)
+ {
+ if ((primitive >= TRIANGLE_ARRAY) && (primitive <= POLYGON_ARRAY)) {
+ prim = primitive;
+ } else {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo0"));
+ }
+ } // End of GeometryInfo(int)
+
+
+
+ /**
+ * Contructor. Populates the GeometryInfo with the geometry from
+ * the GeometryArray.
+ * GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
+ * // initialize the geometry info here
+ * // generate normals
+ * NormalGenerator ng = new NormalGenerator();
+ * ng.generateNormals(gi);
+ * // stripify
+ * Stripifier st = new Stripifier();
+ * st.stripify(gi);
+ * GeometryArray result = gi.getGeometryArray();
+ *
Initial
and
+ * Valid
GeometryArray methods (
+ * setInitialVertexIndex()
and setValidVertexCount()
+ *
and their cousins) then only the needed geometry
+ * is copied into the GeometryInfo.
+ */
+ public GeometryInfo(GeometryArray ga)
+ {
+ GeometryInfoGenerator.create(this, ga);
+ } // End of GeometryInfo(GeometryArray)
+
+
+
+ /**
+ * Removes all data from the GeometryInfo and resets the primitive.
+ * After a call to reset(), the GeometryInfo object will be just like
+ * it was when it was newly constructed.
+ * @param primitive Either TRIANGLE_ARRAY, QUAD_ARRAY,
+ * TRIANGLE_FAN_ARRAY, TRIANGLE_STRIP_ARRAY, or POLYGON_ARRAY.
+ * Tells the GeometryInfo object the type of primitive data to be stored
+ * in it, so it will know the format of the data.
+ */
+ public void reset(int primitive)
+ {
+ if ((primitive >= TRIANGLE_ARRAY) && (primitive <= POLYGON_ARRAY)) {
+ prim = primitive;
+ } else {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo0"));
+ }
+
+ coordinates = null;
+ colors3 = null;
+ colors4 = null;
+ normals = null;
+
+ coordinateIndices = null;
+ colorIndices = null;
+ normalIndices = null;
+
+ stripCounts = null;
+ contourCounts = null;
+
+ oldPrim = 0;
+ oldStripCounts = null;
+
+ texCoordDim = 0;
+ texCoordSetCount = 0;
+ texCoordSets = null;
+ texCoordIndexSets = null;
+ texCoordSetMap = null;
+
+ coordOnly = false;
+
+ } // End of reset(int)
+
+
+
+ /**
+ * Removes all data from this GeometryInfo and populates it with
+ * the geometry from the GeometryArray.
+ */
+ public void reset(GeometryArray ga)
+ {
+ GeometryInfoGenerator.create(this, ga);
+ } // End of reset(GeometryArray)
+
+
+
+ // This method takes an indexed quad array and expands it to
+ // a list of indexed triangles. It is used for the Coordinate
+ // indices as well as the color and texture indices.
+ private int[] expandQuad(int indices[])
+ {
+ int triangles[] = new int[indices.length / 4 * 6];
+
+ for (int i = 0 ; i < indices.length / 4 ; i++ ) {
+ triangles[i * 6 + 0] = indices[i * 4];
+ triangles[i * 6 + 1] = indices[i * 4 + 1];
+ triangles[i * 6 + 2] = indices[i * 4 + 2];
+ triangles[i * 6 + 3] = indices[i * 4];
+ triangles[i * 6 + 4] = indices[i * 4 + 2];
+ triangles[i * 6 + 5] = indices[i * 4 + 3];
+ }
+
+ return triangles;
+ } // End of expandQuad
+
+
+
+ // This method takes an indexed triangle fan and expands it to
+ // a list of indexed triangles. It is used for the Coordinate
+ // indices as well as the color and texture indices.
+ private int[] expandTriFan(int numTris, int indices[])
+ {
+ int triangles[] = new int[numTris * 3];
+ int p = 0;
+ int base = 0;
+ for (int f = 0 ; f < stripCounts.length ; f++) {
+ for (int t = 0 ; t < stripCounts[f] - 2 ; t++) {
+ triangles[p++] = indices[base];
+ triangles[p++] = indices[base + t + 1];
+ triangles[p++] = indices[base + t + 2];
+ }
+ base += stripCounts[f];
+ }
+ return triangles;
+ } // End of expandTriFan
+
+
+
+ // This method takes an indexed triangle strip and expands it to
+ // a list of indexed triangles. It is used for the Coordinate
+ // indices as well as the color and texture indices.
+ private int[] expandTriStrip(int numTris, int indices[])
+ {
+ int triangles[] = new int[numTris * 3];
+
+ int p = 0;
+ int base = 0;
+ for (int s = 0 ; s < stripCounts.length ; s++) {
+ for (int t = 0 ; t < stripCounts[s] - 2 ; t++) {
+
+ // Use a ping-ponging algorithm to reverse order on every other
+ // triangle to preserve winding
+ if (t % 2 == 0) {
+ triangles[p++] = indices[base + t + 0];
+ triangles[p++] = indices[base + t + 1];
+ triangles[p++] = indices[base + t + 2];
+ } else {
+ triangles[p++] = indices[base + t + 0];
+ triangles[p++] = indices[base + t + 2];
+ triangles[p++] = indices[base + t + 1];
+ }
+ }
+ base += stripCounts[s];
+ }
+
+ return triangles;
+ } // End of expandTriStrip
+
+
+
+ // Used by the NormalGenerator utility. Informs the GeometryInfo object
+ // to remember its current primitive and stripCounts arrays so that
+ // they can be used to convert the object back to its original
+ // primitive
+ void rememberOldPrim()
+ {
+ oldPrim = prim;
+ oldStripCounts = stripCounts;
+ } // End of rememberOldPrim
+
+
+
+ // The NormalGenerator needs to know the original primitive for
+ // facet normal generation for quads
+ int getOldPrim()
+ {
+ return oldPrim;
+ } // End of getOldPrim
+
+
+
+ // Used by the Utility libraries other than the NormalGenerator.
+ // Informs the GeometryInfo object that the geometry need not
+ // be converted back to the original primitive before returning.
+ // For example, if a list of Fans is sent, converted to Triangles
+ // for normal generation, and then stripified by the Stripifyer,
+ // we want to make sure that GeometryInfo doesn't convert the
+ // geometry *back* to fans before creating the output GeometryArray.
+ void forgetOldPrim()
+ {
+ oldPrim = 0;
+ oldStripCounts = null;
+ } // End of forgetOldPrim
+
+
+
+ // We have changed the user's data from their original primitive
+ // type to TRIANGLE_ARRAY. If this method is being called, it
+ // means we need to change it back (to try and hide from the user
+ // the fact that we've converted). This usually happens when
+ // the user has used GeometryInfo for generating normals, but
+ // they are not Stripifying or Triangulating. The function is
+ // called from getGeometryArray before creating the output data.
+ private void changeBackToOldPrim()
+ {
+ if (oldPrim != 0) {
+ convertToIndexedTriangles();
+ if (ng == null) ng = new NormalGenerator();
+ ng.convertBackToOldPrim(this, oldPrim, oldStripCounts);
+ oldPrim = 0;
+ oldStripCounts = null;
+ }
+ } // End of changeBackToOldPrim
+
+
+
+ /**
+ * Convert the GeometryInfo object to have primitive type TRIANGLE_ARRAY
+ * and be indexed.
+ * @throws IllegalArgumentException if coordinate data is missing,
+ * if the index lists aren't all the
+ * same length, if an index list is set and the corresponding data
+ * list isn't set, if a data list is set and the corresponding
+ * index list is unset (unless all index lists are unset or in
+ * USE_COORD_INDEX_ONLY format),
+ * if StripCounts or ContourCounts is inconsistent with the current
+ * primitive, if the sum of the contourCounts array doesn't equal
+ * the length of the StripCounts array, or if the number of vertices
+ * isn't a multiple of three (for triangles) or four (for quads).
+ */
+ public void convertToIndexedTriangles()
+ {
+ int triangles = 0;
+
+ // This calls checkForBadData
+ indexify();
+
+ if (prim == TRIANGLE_ARRAY) return;
+
+ switch(prim) {
+
+ case QUAD_ARRAY:
+
+ coordinateIndices = expandQuad(coordinateIndices);
+ if (colorIndices != null) colorIndices = expandQuad(colorIndices);
+ if (normalIndices != null)
+ normalIndices = expandQuad(normalIndices);
+ for (int i = 0 ; i < texCoordSetCount ; i++)
+ texCoordIndexSets[i] = expandQuad(texCoordIndexSets[i]);
+ break;
+
+ case TRIANGLE_FAN_ARRAY:
+ // Count how many triangles are in the object
+ for (int i = 0 ; i < stripCounts.length ; i++) {
+ triangles += stripCounts[i] - 2;
+ }
+
+ coordinateIndices = expandTriFan(triangles, coordinateIndices);
+ if (colorIndices != null)
+ colorIndices = expandTriFan(triangles, colorIndices);
+ if (normalIndices != null)
+ normalIndices = expandTriFan(triangles, normalIndices);
+ for (int i = 0 ; i < texCoordSetCount ; i++)
+ texCoordIndexSets[i] = expandTriFan(triangles,
+ texCoordIndexSets[i]);
+ break;
+
+ case TRIANGLE_STRIP_ARRAY:
+ // Count how many triangles are in the object
+ for (int i = 0 ; i < stripCounts.length ; i++) {
+ triangles += stripCounts[i] - 2;
+ }
+
+ coordinateIndices = expandTriStrip(triangles, coordinateIndices);
+ if (colorIndices != null)
+ colorIndices = expandTriStrip(triangles, colorIndices);
+ if (normalIndices != null)
+ normalIndices = expandTriStrip(triangles, normalIndices);
+ for (int i = 0 ; i < texCoordSetCount ; i++)
+ texCoordIndexSets[i] = expandTriStrip(triangles,
+ texCoordIndexSets[i]);
+ break;
+
+ case POLYGON_ARRAY:
+ if (tr == null) tr = new Triangulator();
+ tr.triangulate(this);
+ break;
+ }
+
+ prim = TRIANGLE_ARRAY;
+ stripCounts = null;
+ } // End of convertToIndexedTriangles
+
+
+
+ /**
+ * Get the current primitive. Some of the utilities may change the
+ * primitive type of the data stored in the GeometryInfo object
+ * (for example, the stripifyer will change it to TRIANGLE_STRIP_ARRAY).
+ */
+ public int getPrimitive()
+ {
+ return prim;
+ } // End of getPrimitive()
+
+
+
+ /**
+ * Set the current primitive. Some of the utilities may change the
+ * primitive type of the data stored in the GeometryInfo object
+ * (for example, the stripifyer will change it to TRIANGLE_STRIP_ARRAY).
+ * But the user can't change the primitive type - it is set in the
+ * constructor. Therefore, this method has package scope.
+ */
+ void setPrimitive(int primitive)
+ {
+ if ((prim >= TRIANGLE_ARRAY) && (prim <= POLYGON_ARRAY)) {
+ prim = primitive;
+ } else {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo0"));
+ }
+ } // End of setPrimitive()
+
+
+
+ /**
+ * Sets the coordinates array.
+ * No data copying is done because a reference to user data is used.
+ */
+ public void setCoordinates(Point3f coordinates[])
+ {
+ this.coordinates = coordinates;
+ } // End of setCoordinates
+
+
+
+ /**
+ * Sets the coordinates array.
+ * The points are copied into the GeometryInfo object.
+ */
+ public void setCoordinates(Point3d coordinates[])
+ {
+ if (coordinates == null) this.coordinates = null;
+ else {
+ this.coordinates = new Point3f[coordinates.length];
+ for (int i = 0 ; i < coordinates.length ; i++) {
+ this.coordinates[i] = new Point3f(
+ (float)(coordinates[i].x),
+ (float)(coordinates[i].y),
+ (float)(coordinates[i].z));
+ }
+ }
+ } // End of setCoordinates
+
+
+
+ /**
+ * Sets the coordinates array.
+ * The points are copied into the GeometryInfo object.
+ */
+ public void setCoordinates(float coordinates[])
+ {
+ if (coordinates == null) this.coordinates = null;
+ else {
+ this.coordinates = new Point3f[coordinates.length / 3];
+ for (int i = 0 ; i < this.coordinates.length ; i++) {
+ this.coordinates[i] = new Point3f(coordinates[i * 3],
+ coordinates[i * 3 + 1],
+ coordinates[i * 3 + 2]);
+ }
+ }
+ } // End of setCoordinates
+
+
+
+ /**
+ * Sets the coordinates array.
+ * The points are copied into the GeometryInfo object.
+ */
+ public void setCoordinates(double coordinates[])
+ {
+ if (coordinates == null) this.coordinates = null;
+ else {
+ this.coordinates = new Point3f[coordinates.length / 3];
+ for (int i = 0 ; i < coordinates.length / 3 ; i++) {
+ this.coordinates[i] = new Point3f((float)coordinates[i * 3],
+ (float)coordinates[i * 3 + 1],
+ (float)coordinates[i * 3 + 2]);
+ }
+ }
+ } // End of setCoordinates
+
+
+
+ /**
+ * Retrieves a reference to the coordinate array.
+ */
+ public Point3f[] getCoordinates()
+ {
+ return coordinates;
+ } // End of getCoordinates
+
+
+
+ /**
+ * Sets the colors array.
+ * No data copying is done because a reference to
+ * user data is used.
+ */
+ public void setColors(Color3f colors[])
+ {
+ colors3 = colors;
+ colors4 = null;
+ } // End of setColors
+
+
+
+ /**
+ * Sets the colors array.
+ * No data copying is done because a reference to
+ * user data is used.
+ */
+ public void setColors(Color4f colors[])
+ {
+ colors3 = null;
+ colors4 = colors;
+ } // End of setColors
+
+
+
+ /**
+ * Sets the colors array.
+ * The points are copied into the GeometryInfo object.
+ */
+ public void setColors(Color3b colors[])
+ {
+ if (colors == null) {
+ colors3 = null;
+ colors4 = null;
+ } else {
+ colors3 = new Color3f[colors.length];
+ colors4 = null;
+ for (int i = 0 ; i < colors.length ; i++) {
+ colors3[i] = new Color3f((float) (colors[i].x & 0xff) / 255.0f,
+ (float) (colors[i].y & 0xff) / 255.0f,
+ (float) (colors[i].z & 0xff) / 255.0f);
+ }
+ }
+ } // End of setColors
+
+
+
+ /**
+ * Sets the colors array.
+ * The points are copied into the GeometryInfo object.
+ */
+ public void setColors(Color4b colors[])
+ {
+ if (colors == null) {
+ colors3 = null;
+ colors4 = null;
+ } else {
+ colors3 = null;
+ colors4 = new Color4f[colors.length];
+ for (int i = 0 ; i < colors.length ; i++) {
+ colors4[i] = new Color4f((float) (colors[i].x & 0xff) / 255.0f,
+ (float) (colors[i].y & 0xff) / 255.0f,
+ (float) (colors[i].z & 0xff) / 255.0f,
+ (float) (colors[i].w & 0xff) / 255.0f);
+ }
+ }
+ } // End of setColors
+
+
+
+ /**
+ * Sets the colors array.
+ * The points are copied into the GeometryInfo object, assuming
+ * 3 components (R, G, and B) per vertex.
+ */
+ public void setColors3(float colors[])
+ {
+ if (colors == null) {
+ colors3 = null;
+ colors4 = null;
+ } else {
+ colors3 = new Color3f[colors.length / 3];
+ colors4 = null;
+ for (int i = 0 ; i < colors.length / 3 ; i++) {
+ colors3[i] = new Color3f(colors[i * 3],
+ colors[i * 3 + 1],
+ colors[i * 3 + 2]);
+ }
+ }
+ } // End of setColors3
+
+
+
+ /**
+ * Sets the colors array.
+ * The points are copied into the GeometryInfo object, assuming
+ * 4 components (R, G, B, and A) per vertex.
+ */
+ public void setColors4(float colors[])
+ {
+ if (colors == null) {
+ colors3 = null;
+ colors4 = null;
+ } else {
+ colors3 = null;
+ colors4 = new Color4f[colors.length / 4];
+ for (int i = 0 ; i < colors.length / 4 ; i++) {
+ colors4[i] = new Color4f(colors[i * 4],
+ colors[i * 4 + 1],
+ colors[i * 4 + 2],
+ colors[i * 4 + 3]);
+ }
+ }
+ } // End of setColors4
+
+
+
+ /**
+ * Sets the colors array.
+ * The points are copied into the GeometryInfo object, assuming
+ * 3 components (R, G, and B) per vertex.
+ */
+ public void setColors3(byte colors[])
+ {
+ if (colors == null) {
+ colors3 = null;
+ colors4 = null;
+ } else {
+ colors3 = new Color3f[colors.length / 3];
+ colors4 = null;
+ for (int i = 0 ; i < colors.length / 3 ; i++) {
+ colors3[i] =
+ new Color3f((float)(colors[i * 3] & 0xff) / 255.0f,
+ (float)(colors[i * 3 + 1] & 0xff) / 255.0f,
+ (float)(colors[i * 3 + 2] & 0xff) / 255.0f);
+ }
+ }
+ } // End of setColors3
+
+
+
+ /**
+ * Sets the colors array.
+ * The points are copied into the GeometryInfo object, assuming
+ * 4 components (R, G, B, and A) per vertex.
+ */
+ public void setColors4(byte colors[])
+ {
+ if (colors == null) {
+ colors3 = null;
+ colors4 = null;
+ } else {
+ colors3 = null;
+ colors4 = new Color4f[colors.length / 4];
+ for (int i = 0 ; i < colors.length / 4 ; i++) {
+ colors4[i] =
+ new Color4f((float)(colors[i * 4] & 0xff) / 255.0f,
+ (float)(colors[i * 4 + 1] & 0xff) / 255.0f,
+ (float)(colors[i * 4 + 2] & 0xff) / 255.0f,
+ (float)(colors[i * 4 + 3] & 0xff) / 255.0f);
+ }
+ }
+ } // End of setColors4
+
+
+
+ /**
+ * Retrieves a reference to the colors array. Will be either
+ * Color3f[]
or Color4f[]
depending on
+ * the type of the input data. Call
+ * getNumColorComponents() to find out which version is returned.
+ */
+ public Object[] getColors()
+ {
+ if (colors3 != null) return colors3;
+ else return colors4;
+ } // End of getColors
+
+
+
+ /**
+ * Returns the number of color data components stored per vertex
+ * in the current GeometryInfo object (3 for RGB or 4 for RGBA).
+ * If no colors are currently defined, 0 is returned.
+ */
+ public int getNumColorComponents()
+ {
+ if (colors3 != null) return 3;
+ else if (colors4 != null) return 4;
+ else return 0;
+ } // End of getNumColorComponents
+
+
+
+ /**
+ * Sets the normals array.
+ * No data copying is done because a reference to
+ * user data is used.
+ */
+ public void setNormals(Vector3f normals[])
+ {
+ this.normals = normals;
+ } // End of setNormals
+
+
+
+ /**
+ * Sets the normals array.
+ * The points are copied into the GeometryInfo object.
+ */
+ public void setNormals(float normals[])
+ {
+ if (normals == null) this.normals = null;
+ else {
+ this.normals = new Vector3f[normals.length / 3];
+ for (int i = 0 ; i < this.normals.length ; i++) {
+ this.normals[i] = new Vector3f(normals[i * 3],
+ normals[i * 3 + 1],
+ normals[i * 3 + 2]);
+ }
+ }
+ } // End of setNormals(float[])
+
+
+
+ /**
+ * Retrieves a reference to the normal array.
+ */
+ public Vector3f[] getNormals()
+ {
+ return normals;
+ } // End of getNormals
+
+
+
+ /**
+ * This method is used to specify the number of texture coordinate sets
+ * and the dimensionality of the texture coordinates.
+ * The number of texture coordinate sets must be specified to the GeometryInfo
+ * class before any of the sets are specified. The dimensionality of the
+ * texture coordinates may be 2, 3, or 4, corresponding to 2D, 3D, or 4D
+ * texture coordinates respectively.(All sets must have the same
+ * dimensionality.) The default is zero, 2D texture coordinate sets.
+ * This method should be called before any texture coordinate sets are
+ * specified because calling this method will delete all previously
+ * specified texture coordinate and texture coordinate index arrays
+ * associated with this GeometryInfo. For example:
+ *
+ * The second call to
+ * geomInfo.setTextureCoordinateParams(2, 3);
+ * geomInfo.setTextureCoordinates(0, tex0);
+ * geomInfo.setTextureCoordinates(1, tex1);
+ * geomInfo.setTextureCoordinateParams(1, 2);
+ * geomInfo.getTexCoordSetCount();
+ *
setTextureCoordinateParams
will erase all
+ * the texture coordinate arrays, so the subsequent call to
+ * getTexCoordSetCount
will return 1.
+ * @param numSets The number of texture coordinate sets that will be
+ * specified for this GeometryInfo object.
+ * @param dim The dimensionality of the texture coordinates. Has to be 2, 3
+ * or 4.
+ * @throws IllegalArgumentException if the dimensionality of the texture
+ * coordinates is not one of 2, 3 or 4.
+ */
+ public void setTextureCoordinateParams(int numSets, int dim)
+ {
+ if (dim == 2) {
+ texCoordSets = new TexCoord2f[numSets][];
+ } else if (dim == 3) {
+ texCoordSets = new TexCoord3f[numSets][];
+ } else if (dim == 4) {
+ texCoordSets = new TexCoord4f[numSets][];
+ } else {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo9"));
+ }
+ texCoordIndexSets = new int[numSets][];
+ texCoordDim = dim;
+ texCoordSetCount = numSets;
+ } // End of setTextureCoordinateParams
+
+
+
+ /**
+ * Returns the number of texture coordinate sets in this GeometryInfo.
+ * This value is set with setTextureCoordinateParams().
+ * If setTextureCoordinateParams()
+ * has not been called, 0 is returned unless one of the deprecated
+ * texture coordinate methods has been called. Calling one of the
+ * deprecated texture coordinate methods sets the count to 1.
+ * The deprecated texture coordinate methods are those that don't
+ * take texCoordSet as the first parameter.
+ * @return the number of texture coordinate sets in this
+ * GeometryInfo.
+ */
+ public int getTexCoordSetCount() {
+ return texCoordSetCount;
+ }
+
+
+
+ /**
+ * Returns the number of texture coordinate components that are stored
+ * per vertex. Returns 2 for ST (2D), 3 for STR (3D),
+ * or 4 for STRQ (4D), aslo known as the "dimensionality" of the
+ * coordinates. This value is set with
+ * setTextureCoordinateParams(). If setTextureCoordinateParams()
+ * has not been called, 0 is returned unless one of the deprecated
+ * texture coordinate methods has been called. Calling one of the
+ * deprecated texture coordinate methods sets the dimensionality
+ * explicitly (if you called setTextureCoordinates(Point2f[]) then
+ * 2 is returned).
+ * The deprecated texture coordinate methods are those that don't
+ * take texCoordSet as the first parameter.
+ */
+ public int getNumTexCoordComponents()
+ {
+ return texCoordDim;
+ } // End of getNumTexCoordComponents
+
+
+
+ /**
+ * Sets the mapping between texture coordinate sets and texture units.
+ * See the
+ *
+ * GeometryArray constructor for further details.
+ * texCoordSet
< 0 or
+ * texCoordSet >= texCoordSetCount
,
+ * or the texture coordinate parameters were not previously set by
+ * calling setTextureCoordinateParams(texCoordSetCount, 2)
.
+ */
+ public void setTextureCoordinates(int texCoordSet, TexCoord2f texCoords[])
+ {
+ if (texCoordDim != 2)
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo15"));
+ if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo18"));
+
+ texCoordSets[texCoordSet] = texCoords;
+ } // End of setTextureCoordinates(int, TexCoord3f[])
+
+
+
+ /**
+ * Sets the TextureCoordinates array by copying the data
+ * into the GeometryInfo object.
+ * This method sets the number of texture coordinate sets to 1,
+ * sets the dimensionality of the texture coordinates to 2,
+ * and sets the coordinates for texture coordinate set 0.
+ * @deprecated As of Java 3D 1.3 replaced by
+ * setTextureCoordinates(int texCoordSet, TexCoord2f coords[])
+ */
+ public void setTextureCoordinates(Point2f texCoords[])
+ {
+ texCoordSetCount = 1;
+ texCoordDim = 2;
+ texCoordSets = new TexCoord2f[1][];
+ if (texCoords != null) {
+ TexCoord2f[] tex = new TexCoord2f[texCoords.length];
+ for (int i = 0 ; i < texCoords.length ; i++)
+ tex[i] = new TexCoord2f(texCoords[i]);
+ texCoordSets[0] = tex;
+ }
+ } // End of setTextureCoordinates(Point2f[])
+
+
+
+ /**
+ * Sets the texture coordinates array for the specified set.
+ * No data copying is done - a reference to user data is used.
+ * @param texCoordSet The texture coordinate set for which these coordinates
+ * are being specified.
+ * @param texCoords Array of 3D texture coordinates.
+ * @throws IllegalArgumentException if texCoordSet
< 0 or
+ * texCoordSet >= texCoordSetCount
,
+ * or the texture coordinate parameters were not previously set by
+ * calling setTextureCoordinateParams(texCoordSetCount, 3)
.
+ */
+ public void setTextureCoordinates(int texCoordSet, TexCoord3f texCoords[])
+ {
+ if (texCoordDim != 3)
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo16"));
+ if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo18"));
+
+ texCoordSets[texCoordSet] = texCoords;
+ } // End of setTextureCoordinates(int, TexCoord3f[])
+
+
+
+ /**
+ * Sets the TextureCoordinates array by copying the data
+ * into the GeometryInfo object.
+ * This method sets the number of texture coordinate sets to 1,
+ * sets the dimensionality of the texture coordinates to 3,
+ * and sets the coordinates for texture coordinate set 0.
+ * @deprecated As of Java 3D 1.3 replaced by
+ * setTextureCoordinates(int texCoordSet, TexCoord3f coords[])
+ */
+ public void setTextureCoordinates(Point3f texCoords[])
+ {
+ texCoordSetCount = 1;
+ texCoordDim = 3;
+ texCoordSets = new TexCoord3f[1][];
+ if (texCoords != null) {
+ TexCoord3f[] tex = new TexCoord3f[texCoords.length];
+ for (int i = 0 ; i < texCoords.length ; i++)
+ tex[i] = new TexCoord3f(texCoords[i]);
+ texCoordSets[0] = tex;
+ }
+ } // End of setTextureCoordinates(Point3f[])
+
+
+
+ /**
+ * Sets the texture coordinates array for the specified set.
+ * No data copying is done - a reference to user data is used.
+ * @param texCoordSet The texture coordinate set for which these coordinates
+ * are being specified.
+ * @param texCoords Array of 4D texture coordinates.
+ * @throws IllegalArgumentException if texCoordSet
< 0 or
+ * texCoordSet >= texCoordSetCount
,
+ * or the texture coordinate parameters were not previously set by
+ * calling setTextureCoordinateParams(texCoordSetCount, 4)
.
+ */
+ public void setTextureCoordinates(int texCoordSet, TexCoord4f texCoords[]) {
+ if (texCoordDim != 4)
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo17"));
+ if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo18"));
+
+ texCoordSets[texCoordSet] = texCoords;
+ } // End of setTextureCoordinates(int, TexCoord4f[])
+
+
+
+ /**
+ * Sets the texture coordinates array by copying the data into the
+ * GeometryInfo object. The number of sets and dimensionality of
+ * the sets must have been set previously with
+ * setTextureCoordinateParams(texCoordSetCount, dim).
+ * @param texCoordSet The texture coordinate set for which these coordinates
+ * are being specified.
+ * @param texCoords The float array of texture coordinates. For n texture
+ * coordinates with dimensionality d, there must be d*n floats in the array.
+ * @throws IllegalArgumentException if texCoordSet
< 0 or
+ * texCoordSet >= texCoordSetCount
,
+ * or the texture coordinate parameters were not previously set by
+ * calling setTextureCoordinateParams
.
+ */
+ public void setTextureCoordinates(int texCoordSet, float texCoords[])
+ {
+ if ((texCoords.length % texCoordDim) != 0)
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo2"));
+
+ // Copy the texCoords into this GeometryInfo object
+ if (texCoordDim == 2) {
+ TexCoord2f tcoords[] = new TexCoord2f[texCoords.length / 2];
+ for (int i = 0 ; i < tcoords.length ; i++)
+ tcoords[i] = new TexCoord2f(texCoords[i * 2],
+ texCoords[i * 2 + 1]);
+ setTextureCoordinates(texCoordSet, tcoords);
+ } else if (texCoordDim == 3) {
+ TexCoord3f tcoords[] = new TexCoord3f[texCoords.length / 3];
+ for (int i = 0 ; i < tcoords.length ; i++)
+ tcoords[i] = new TexCoord3f(texCoords[i * 3],
+ texCoords[i * 3 + 1],
+ texCoords[i * 3 + 2]);
+ setTextureCoordinates(texCoordSet, tcoords);
+ } else if (texCoordDim == 4) {
+ TexCoord4f tcoords[] = new TexCoord4f[texCoords.length / 4];
+ for (int i = 0 ; i < tcoords.length ; i++)
+ tcoords[i] = new TexCoord4f(texCoords[i * 4],
+ texCoords[i * 4 + 1],
+ texCoords[i * 4 + 2],
+ texCoords[i * 4 + 3]);
+ setTextureCoordinates(texCoordSet, tcoords);
+ } else {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo21"));
+ }
+ } // End of setTextureCoordinates(int, float[])
+
+
+
+ /**
+ * Sets the texture coordinates array by copying the data
+ * into the GeometryInfo object, assuming two numbers
+ * (S and T) per vertex.
+ * This method sets the number of texture coordinate sets to 1,
+ * sets the dimensionality of the texture coordinates to 2,
+ * and sets the coordinates for texture coordinate set 0.
+ * @deprecated As of Java 3D 1.3 replaced by
+ * setTextureCoordinates(int texCoordSet, float texCoords[])
+ */
+ public void setTextureCoordinates2(float texCoords[])
+ {
+ texCoordSetCount = 1;
+ texCoordDim = 2;
+ texCoordSets = new TexCoord2f[1][];
+ setTextureCoordinates(0, texCoords);
+ } // End of setTextureCoordinates2(float[])
+
+
+
+ /**
+ * Sets the TextureCoordinates array by copying the data
+ * into the GeometryInfo object, assuming three numbers
+ * (S, T, & R) per vertex.
+ * This method sets the number of texture coordinate sets to 1,
+ * sets the dimensionality of the texture coordinates to 3,
+ * and sets the coordinates for texture coordinate set 0.
+ * @deprecated As of Java 3D 1.3 replaced by
+ * setTextureCoordinates(int texCoordSet, float texCoords[])
+ */
+ public void setTextureCoordinates3(float texCoords[])
+ {
+ texCoordSetCount = 1;
+ texCoordDim = 3;
+ texCoordSets = new TexCoord3f[1][];
+ setTextureCoordinates(0, texCoords);
+ } // End of setTextureCoordinates3(float[])
+
+
+
+ /**
+ * Returns a reference to the indicated texture coordinate array.
+ * The return type will be TexCoord2f[]
, TexCoord3f[]
+ *
, or TexCoord4f[]
depending on the
+ * current dimensionality of the texture coordinates in the GeometryInfo
+ * object. Use getNumTexCoordComponents()
to find out which
+ * version is returned.
+ * @param texCoordSet The index of the texture coordinate set to
+ * retrieve.
+ * @return An array of texture coordinates at the specified index
+ * @throws IllegalArgumentException If texCoordSet
< 0
+ * or texCoordSet >= texCoordSetCount
+ */
+ public Object[] getTextureCoordinates(int texCoordSet)
+ {
+ if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo18"));
+ return texCoordSets[texCoordSet];
+ } // End of getTextureCoordinates(int)
+
+
+
+ /**
+ * Retrieves a reference to texture coordinate set 0.
+ * The return type will be TexCoord2f[]
, TexCoord3f[]
+ *
, or TexCoord4f[]
depending on the
+ * current dimensionality of the texture coordinates in the GeometryInfo
+ * object. Use getNumTexCoordComponents()
to find out which
+ * version is returned. Equivalent to getTextureCoordinates(0)
.
+ * @return An array of texture coordinates for set 0.
+ * @deprecated As of Java 3D 1.3 replaced by
+ * getTextureCoordinates(int texCoordSet)
+ */
+ public Object[] getTextureCoordinates()
+ {
+ return texCoordSets[0];
+ } // End of getTextureCoordinates()
+
+
+
+ /**
+ * Sets the array of indices into the Coordinate array.
+ * No data copying is done - a reference to user data is used.
+ */
+ public void setCoordinateIndices(int coordinateIndices[])
+ {
+ this.coordinateIndices = coordinateIndices;
+ } // End of setCoordinateIndices
+
+
+
+ /**
+ * Retrieves a reference to the array of indices into the
+ * coordinate array.
texCoordSet
< 0 or
+ * texCoordSet >= texCoordSetCount
.
+ */
+ public void setTextureCoordinateIndices(int texCoordSet, int texIndices[])
+ {
+ if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo18"));
+
+ // Texture coordinates are indexed
+ texCoordIndexSets[texCoordSet] = texIndices;
+ } // End of setTextureCoordinateIndices(int, int[])
+
+
+
+ /**
+ * Sets the array of indices into texture coordinate set 0. Do not
+ * call this method if you are using more than one set of texture
+ * coordinates.
+ * No data is copied - a reference to the user data is used.
+ * @deprecated As of Java 3D 1.3 replaced by
+ * setTextureCoordinateIndices(int texCoordSet, int indices[])
+ * @throws IllegalArgumentException If texCoordSetCount > 1
.
+ */
+ public void setTextureCoordinateIndices(int texIndices[])
+ {
+ if (texCoordSetCount > 1)
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo1"));
+ texCoordIndexSets = new int[1][];
+ texCoordIndexSets[0] = texIndices;
+ } // End of setTextureCoordinateIndices(int[])
+
+
+
+ /**
+ * Retrieves a reference to the specified array of texture
+ * coordinate indices.+ * + * This method should be considered for advanced users only. + * Novice users should just use getGeometryArray() to retrieve + * their data so that the internal format of GeometryInfo is + * of no concern.
+ * + * Depending on which of the utility routines you've called + * on your GeometryInfo object, the results may not be what you + * expect. If you've called the Stripifier, your GeometryInfo + * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY + * and your data will be formatted accordingly. Similarly, if + * you've called the Triangulator, your data is in indexed + * TRIANGLE_ARRAY format. Generating normals with the NormalGenerator + * utility will convert your data to indexed TRIANGLE_ARRAY also, + * but if you call getGeometryArray without calling the Stripifier or + * Triangulator, your data will be converted back to the original + * primitive type when creating the GeometryArray object to pass + * back. However, if your creaseAngle was not Math.PI (no creases - + * smooth shading), then the introduction of + * creases into your model may have split primitives, lengthening + * the StripCounts and index arrays from your original data. + * @param texCoordSet The texture coordinate index set to be + * retrieved. + * @return Integer array of the texture coordinate indices for the specified + * set. + */ + public int[] getTextureCoordinateIndices(int texCoordSet) { + return texCoordIndexSets[texCoordSet]; + } + + + /** + * Returns a reference to texture coordinate index set 0. + * Equivalent to + *getTextureCoordinateIndices(0)
.
+ * @deprecated As of Java 3D 1.3 replaced by
+ * int[] getTextureCoordinateIndices(int texCoordSet)
+ * @return Integer array of the texture coordinate indices for set 0
+ */
+ public int[] getTextureCoordinateIndices()
+ {
+ if (texCoordIndexSets == null) return null;
+ return texCoordIndexSets[0];
+ } // End of getTextureCoordinateIndices()
+
+
+
+ /**
+ * Sets the array of strip counts. If index lists have been set for
+ * this GeomteryInfo object then the data is indexed and the stripCounts
+ * are like stripIndexCounts. If no index lists have been set then
+ * the data is non-indexed and the stripCounts are like
+ * stripVertexCounts.
+ * @see GeometryStripArray#GeometryStripArray(int, int,
+ * int[] stripVertexCounts)
+ * @see IndexedGeometryStripArray#IndexedGeometryStripArray(int, int, int,
+ * int[] stripIndexCounts)
+ */
+ public void setStripCounts(int stripCounts[])
+ {
+ this.stripCounts = stripCounts;
+ } // End of setStripCounts
+
+
+
+ /**
+ * Retrieves a reference to the array of stripCounts.
+ *
+ * This method should be considered for advanced users only.
+ * Novice users should just use getGeometryArray() to retrieve
+ * their data so that the internal format of GeometryInfo is
+ * of no concern.
+ *
+ * Depending on which of the utility routines you've called
+ * on your GeometryInfo object, the results may not be what you
+ * expect. If you've called the Stripifier, your GeometryInfo
+ * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY
+ * and your data will be formatted accordingly. Similarly, if
+ * you've called the Triangulator, your data is in indexed
+ * TRIANGLE_ARRAY format. Generating normals with the NormalGenerator
+ * utility will convert your data to indexed TRIANGLE_ARRAY also,
+ * but if you call getGeometryArray without calling the Stripifier or
+ * Triangulator, your data will be converted back to the original
+ * primitive type when creating the GeometryArray object to pass
+ * back. However, if your creaseAngle was not Math.PI (no creases -
+ * smooth shading), then the introduction of
+ * creases into your model may have split primitives, lengthening
+ * the StripCounts and index arrays from your original data.
+ */
+ public int[] getStripCounts()
+ {
+ return stripCounts;
+ } // End of getStripCounts
+
+
+
+ /**
+ * Sets the list of contour counts. Only used with the POLYGON_ARRAY
+ * primitive. Polygons can be made of several vertex lists
+ * called contours. The first list is the polygon, and
+ * subsequent lists are "holes" that are removed from the
+ * polygon. All of the holes must be contained entirely
+ * within the polygon.
+ */
+ public void setContourCounts(int contourCounts[])
+ {
+ this.contourCounts = contourCounts;
+ } // End of setContourCounts
+
+
+
+ /**
+ * Retrieves a reference to the array of contourCounts.
+ */
+ public int[] getContourCounts()
+ {
+ return contourCounts;
+ } // End of getContourCounts
+
+
+
+ /*
+ * This routine will return an index list for any array of objects.
+ */
+ int[] getListIndices(Object list[])
+ {
+ // Create list of indices to return
+ int indices[] = new int[list.length];
+
+ // Create hash table with initial capacity equal to the number
+ // of components (assuming about half will be duplicates)
+ HashMap table = new HashMap(list.length);
+
+ Integer idx;
+ for (int i = 0 ; i < list.length ; i++) {
+
+ // Find index associated with this object
+ idx = (Integer)table.get(list[i]);
+
+ if (idx == null) {
+ // We haven't seen this object before
+ indices[i] = i;
+
+ // Put into hash table and remember the index
+ table.put(list[i], new Integer(i));
+
+ } else {
+ // We've seen this object
+ indices[i] = idx.intValue();
+ }
+ }
+
+ return indices;
+ } // End of getListIndices
+
+
+
+ // Class to hash 'size' integers
+ private class IndexRow {
+ int[] val;
+ int size;
+ private static final int HASHCONST = 0xBABEFACE;
+
+ @Override
+ public int hashCode()
+ {
+ int bits = 0;
+ for (int i = 0 ; i < size ; i++) {
+ bits ^= (bits * HASHCONST) << 2;
+ }
+ return bits;
+ } // End of IndexRow.hashCode
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ for (int i = 0 ; i < size ; i++) {
+ if (((IndexRow)obj).get(i) != val[i]) return false;
+ }
+ return true;
+ } // End of IndexRow.equals()
+
+ public int get(int index)
+ {
+ return val[index];
+ } // End of IndexRow.get
+
+ public void set(int index, int value)
+ {
+ val[index] = value;
+ } // End of IndexRow.set
+
+ IndexRow(int numColumns)
+ {
+ size = numColumns;
+ val = new int[size];
+ } // End of IndexRow constructor
+ } // End of class IndexRow
+
+
+
+ /**
+ * Create index lists for all data lists.
+ * Identical data entries are guaranteed to
+ * use the same index value. Does not remove unused data values
+ * from the object - call compact() to do this.
+ * @param useCoordIndexOnly Reformat the data into the
+ * GeometryArray.USE_COORD_INDEX_ONLY format where there is only
+ * one index list. If the data is already in the USE_COORD_INDEX_ONLY
+ * format, sending false (or calling indexify()) will change
+ * it to the normal indexed format.
+ * @throws IllegalArgumentException if coordinate data is missing,
+ * if the index lists aren't all the
+ * same length, if an index list is set and the corresponding data
+ * list isn't set, if a data list is set and the corresponding
+ * index list is unset (unless all index lists are unset or in
+ * USE_COORD_INDEX_ONLY format),
+ * if StripCounts or ContourCounts is inconsistent with the current
+ * primitive, if the sum of the contourCounts array doesn't equal
+ * the length of the StripCounts array, or if the number of vertices
+ * isn't a multiple of three (for triangles) or four (for quads).
+ */
+ public void indexify(boolean useCoordIndexOnly)
+ {
+ checkForBadData();
+
+ if (useCoordIndexOnly) {
+ // Return if already in this format
+ if (coordOnly) return;
+
+ // Start from normal indexed format
+ indexify(false);
+
+ // Reformat data to USE_COORD_INDEX_ONLY format
+ // Need to make an index into the index lists using each
+ // row of indexes as one value
+
+ // First, find out how many index lists there are;
+ int numLists = 1; // Always have coordinates
+ if (colorIndices != null) numLists++;
+ if (normalIndices != null) numLists++;
+ numLists += texCoordSetCount;
+
+ // Make single array containing all indices
+ int n = coordinateIndices.length;
+ IndexRow[] ir = new IndexRow[n];
+ int j;
+ for (int i = 0 ; i < n ; i++) {
+ ir[i] = new IndexRow(numLists);
+ j = 0;
+ ir[i].set(j++, coordinateIndices[i]);
+ if (colorIndices != null) ir[i].set(j++, colorIndices[i]);
+ if (normalIndices != null) ir[i].set(j++, normalIndices[i]);
+ for (int k = 0 ; k < texCoordSetCount ; k++) {
+ ir[i].set(j++, texCoordIndexSets[k][i]);
+ }
+ }
+
+ // Get index into that array
+ int[] coordOnlyIndices = getListIndices(ir);
+
+ // Get rid of duplicate rows
+ int newInd[] = new int[coordOnlyIndices.length];
+ ir = (IndexRow[])compactData(coordOnlyIndices, ir, newInd);
+ coordOnlyIndices = newInd;
+
+ // Reformat data lists to correspond to new index
+
+ // Allocate arrays to hold reformatted data
+ Point3f[] newCoords = new Point3f[ir.length];
+ Color3f[] newColors3 = null;
+ Color4f[] newColors4 = null;
+ Vector3f[] newNormals = null;
+ Object newTexCoordSets[][] = null;
+ if (colors3 != null) newColors3 = new Color3f[ir.length];
+ else if (colors4 != null) newColors4 = new Color4f[ir.length];
+ if (normals != null) newNormals = new Vector3f[ir.length];
+ for (int i = 0 ; i < texCoordSetCount ; i++) {
+ if (texCoordDim == 2) {
+ if (i == 0) newTexCoordSets = new TexCoord2f[texCoordSetCount][];
+ newTexCoordSets[i] = new TexCoord2f[ir.length];
+ } else if (texCoordDim == 3) {
+ if (i == 0) newTexCoordSets = new TexCoord3f[texCoordSetCount][];
+ newTexCoordSets[i] = new TexCoord3f[ir.length];
+ } else if (texCoordDim == 4) {
+ if (i == 0) newTexCoordSets = new TexCoord4f[texCoordSetCount][];
+ newTexCoordSets[i] = new TexCoord4f[ir.length];
+ }
+ }
+
+ // Copy data into new arrays
+ n = ir.length;
+ for (int i = 0 ; i < n ; i++) {
+ j = 0;
+ newCoords[i] = coordinates[(ir[i]).get(j++)];
+ if (colors3 != null) {
+ newColors3[i] = colors3[(ir[i]).get(j++)];
+ } else if (colors4 != null) {
+ newColors4[i] = colors4[(ir[i]).get(j++)];
+ }
+ if (normals != null) newNormals[i] = normals[(ir[i]).get(j++)];
+ for (int k = 0 ; k < texCoordSetCount ; k++) {
+ newTexCoordSets[k][i] = texCoordSets[k][(ir[i]).get(j++)];
+ }
+ }
+
+ // Replace old arrays with new arrays
+ coordinates = newCoords;
+ colors3 = newColors3;
+ colors4 = newColors4;
+ normals = newNormals;
+ texCoordSets = newTexCoordSets;
+ coordinateIndices = coordOnlyIndices;
+ colorIndices = null;
+ normalIndices = null;
+ texCoordIndexSets = new int[texCoordSetCount][];
+
+ coordOnly = true;
+ } else if (coordOnly) {
+ // Need to change from useCoordIndexOnly format to normal
+ // indexed format. Should make a more efficient implementation
+ // later.
+
+ int n = coordinateIndices.length;
+ if ((colors3 != null) || (colors4 != null)) {
+ colorIndices = new int[n];
+ for (int i = 0 ; i < n ; i++) colorIndices[i] = coordinateIndices[i];
+ }
+ if (normals != null) {
+ normalIndices = new int[n];
+ for (int i = 0 ; i < n ; i++) normalIndices[i] = coordinateIndices[i];
+ }
+ texCoordIndexSets = new int[texCoordSetCount][];
+ for (int i = 0 ; i < texCoordSetCount ; i++) {
+ texCoordIndexSets[i] = new int[n];
+ for (int j = 0 ; j < n ; j++) {
+ texCoordIndexSets[i][j] = coordinateIndices[j];
+ }
+ }
+ coordOnly = false;
+ } else {
+
+ // No need to indexify if already indexed
+ if (coordinateIndices != null) return;
+
+ coordinateIndices = getListIndices(coordinates);
+
+ if (colors3 != null) colorIndices = getListIndices(colors3);
+ else if (colors4 != null) colorIndices = getListIndices(colors4);
+
+ if (normals != null) normalIndices = getListIndices(normals);
+
+ texCoordIndexSets = new int[texCoordSetCount][];
+ for(int i = 0 ; i < texCoordSetCount ; i++) {
+ texCoordIndexSets[i] = getListIndices(texCoordSets[i]);
+ }
+
+ coordOnly = false;
+ }
+
+ if ((DEBUG & 1) == 1) {
+ System.out.println("Coordinate Array:");
+ for (int i = 0 ; i < coordinates.length ; i++) {
+ System.out.println(" " + i + " " + coordinates[i] +
+ " " + coordinates[i].hashCode());
+ }
+ System.out.println("Index array:");
+ for (int i = 0 ; i < coordinateIndices.length ; i++) {
+ System.out.println(" " + i + " " + coordinateIndices[i]);
+ }
+ }
+
+ } // End of indexify
+
+
+
+ public void indexify()
+ {
+ indexify(false);
+ } // End of indexify()
+
+
+
+ /**
+ * Allocates an array of the same type as the input type. This allows us to
+ * use a generic compactData method.
+ *
+ * @param data Array of coordinate, color, normal or texture coordinate data
+ * The data can be in one of the following formats - Point3f, Color3f,
+ * Color4f, TexCoord2f, TexCoord3f, TexCoord4f.
+ *
+ * @param num The size of the array to be allocated
+ *
+ * @return An array of size num of the same type as the input type
+ *
+ * @exception IllegalArgumentException if the input array is not one of the
+ * types listed above.
+ */
+ Object[] allocateArray(Object data[], int num) {
+ Object newData[] = null;
+ if (data instanceof org.jogamp.vecmath.Point3f[]) {
+ newData = new Point3f[num];
+ } else if (data instanceof org.jogamp.vecmath.Vector3f[]) {
+ newData = new Vector3f[num];
+ } else if (data instanceof org.jogamp.vecmath.Color3f[]) {
+ newData = new Color3f[num];
+ } else if (data instanceof org.jogamp.vecmath.Color4f[]) {
+ newData = new Color4f[num];
+ } else if (data instanceof org.jogamp.vecmath.TexCoord2f[]) {
+ newData = new TexCoord2f[num];
+ } else if (data instanceof org.jogamp.vecmath.TexCoord3f[]) {
+ newData = new TexCoord3f[num];
+ } else if (data instanceof org.jogamp.vecmath.TexCoord4f[]) {
+ newData = new TexCoord4f[num];
+ } else if (data instanceof IndexRow[]) {
+ // Hack so we can use compactData for coordIndexOnly
+ newData = new IndexRow[num];
+ } else throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo9"));
+ return newData;
+ } // End of allocateArray
+
+
+
+ /**
+ * Generic method that compacts (ie removes unreferenced/duplicate data)
+ * any type of indexed data.
+ * Used to compact coordinate, color, normal and texture coordinate data.
+ * @param indices Array of indices
+ * @param data Array of coordinate, color, normal or texture coordinate data
+ * The data can be in one of the following formats - Point3f, Color3f,
+ * Color4f, TexCoord2f, TexCoord3f, TexCoord4f.
+ * @param newInd The new array of indexes after the data has been compacted.
+ * This must be allocated by the calling method. On return, this array will
+ * contain the new index data. The size of this array must be equal to
+ * indices.length
+ * @return Array of the data with unreferenced and duplicate entries removed.
+ * The return type will be the same as the type that was passed in data.
+ */
+ // TODO: Remove duplicate entries in data lists.
+ private Object[] compactData(int indices[], Object data[], int newInd[]) {
+ Object newData[] = null;
+ /*
+ * This is a three step process.
+ * First, find out how many unique indexes are used. This
+ * will be the size of the new data array.
+ */
+ int numUnique = 0;
+ int translationTable[] = new int[data.length];
+ for (int i = 0 ; i < indices.length ; i++) {
+ if (translationTable[indices[i]] == 0) {
+
+ numUnique++;
+ translationTable[indices[i]] = 1;
+ }
+ }
+ /*
+ * Second, build the new data list. Remember the new indexes so
+ * we can use the table to translate the old indexes to the new
+ */
+ newData = allocateArray(data, numUnique);
+ int newIdx = 0;
+ for (int i = 0 ; i < translationTable.length ; i++) {
+ if (translationTable[i] != 0) {
+ newData[newIdx] = data[i];
+ translationTable[i] = newIdx++;
+ }
+ }
+ /*
+ * Third, make the new index list
+ */
+ for (int i = 0 ; i < indices.length ; i++) {
+ newInd[i] = translationTable[indices[i]];
+ }
+ return newData;
+ } // End of compactData
+
+
+
+ /**
+ * Remove unused data from an indexed dataset.
+ * Indexed data may contain data entries that are never referenced by
+ * the dataset. This routine will remove those entries where
+ * appropriate and renumber the indices to match the new values.
+ * @throws IllegalArgumentException if coordinate data is missing,
+ * if the index lists aren't all the
+ * same length, if an index list is set and the corresponding data
+ * list isn't set, if a data list is set and the corresponding
+ * index list is unset (unless all index lists are unset or in
+ * USE_COORD_INDEX_ONLY format),
+ * if StripCounts or ContourCounts is inconsistent with the current
+ * primitive, if the sum of the contourCounts array doesn't equal
+ * the length of the StripCounts array, or if the number of vertices
+ * isn't a multiple of three (for triangles) or four (for quads).
+ */
+ public void compact()
+ {
+ checkForBadData();
+
+ // Only usable on indexed data
+ if (coordinateIndices == null) return;
+
+ // USE_COORD_INDEX_ONLY never has unused data
+ if (coordOnly) return;
+
+ int newInd[] = new int[coordinateIndices.length];
+ coordinates =
+ (Point3f[])compactData(coordinateIndices, coordinates, newInd);
+ coordinateIndices = newInd;
+
+ if (colorIndices != null) {
+ newInd = new int[colorIndices.length];
+ if (colors3 != null)
+ colors3 = (Color3f[])compactData(colorIndices, colors3, newInd);
+ else if (colors4 != null)
+ colors4 = (Color4f[])compactData(colorIndices, colors4, newInd);
+ colorIndices = newInd;
+ }
+
+ if (normalIndices != null) {
+ newInd = new int[normalIndices.length];
+ normals = (Vector3f[])compactData(normalIndices, normals, newInd);
+ normalIndices = newInd;
+ }
+
+ for (int i = 0 ; i < texCoordSetCount ; i++) {
+ newInd = new int[texCoordIndexSets[i].length];
+ texCoordSets[i] = compactData(texCoordIndexSets[i],
+ texCoordSets[i], newInd);
+ texCoordIndexSets[i] = newInd;
+ }
+ } // End of compact
+
+
+
+ /**
+ * Check the data to make sure everything's consistent.
+ */
+ private void checkForBadData() {
+ boolean badData = false;
+
+ //
+ // Coordinates are required
+ //
+ if (coordinates == null) {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo3"));
+ }
+
+ //
+ // Check for indices with no data
+ //
+ if ((colors3 == null) && (colors4 == null) && (colorIndices != null))
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo4"));
+ if ((normals == null) && (normalIndices != null))
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo11"));
+
+ //
+ // Make sure all TextureCoordinate data is set (indices or not)
+ //
+ for (int i = 0 ; i < texCoordSetCount ; i++) {
+ if (texCoordSets[i] == null)
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo10"));
+ }
+
+ //
+ // Check for Missing Index lists
+ //
+ boolean texInds = false; // Indicates whether we have texcoord indices
+ if (texCoordIndexSets != null) {
+ for (int i = 0 ; i < texCoordSetCount ; i++) {
+ if (texCoordIndexSets[i] != null) texInds = true;
+ }
+ }
+ if ((coordinateIndices != null) ||
+ (colorIndices != null) ||
+ (normalIndices != null) ||
+ texInds) {
+ // At least one index list is present, so they all must be
+ // present (unless coordOnly)
+ if (coordinateIndices == null) badData = true;
+ else if (coordOnly) {
+ if ((colorIndices != null) ||
+ (normalIndices != null) ||
+ (texInds == true)) {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo20"));
+ }
+ } else if (((colors3 != null) || (colors4 != null)) &&
+ (colorIndices == null)) badData = true;
+ else if ((normals != null) && (normalIndices == null)) badData = true;
+ else if ((texCoordSetCount > 0) && !texInds) badData = true;
+ if (badData) throw new
+ IllegalArgumentException(J3dUtilsI18N.getString("GeometryInfo19"));
+ }
+
+ //
+ // Make sure index lists are all the same length
+ //
+ if ((coordinateIndices != null) && (!coordOnly)) {
+ if (((colors3 != null) || (colors4 != null)) &&
+ (colorIndices.length != coordinateIndices.length))
+ badData = true;
+ else if ((normals != null) &&
+ (normalIndices.length != coordinateIndices.length))
+ badData = true;
+ else {
+ //Check all texCoord indices have the same length
+ for (int i = 0 ; i < texCoordSetCount ; i++) {
+ if (texCoordIndexSets[i].length != coordinateIndices.length) {
+ badData = true;
+ break;
+ }
+ }
+ }
+ if (badData) {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo5"));
+ }
+ }
+
+ //
+ // For stripped primitives, make sure we have strip counts
+ //
+ if ((prim == TRIANGLE_STRIP_ARRAY) ||
+ (prim == TRIANGLE_FAN_ARRAY) ||
+ (prim == POLYGON_ARRAY)) {
+ if (stripCounts == null) badData = true;
+ } else if (stripCounts != null) badData = true;
+ if (badData) {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo6"));
+ }
+
+ // Find out how much data we have
+ int count;
+ if (coordinateIndices == null) count = coordinates.length;
+ else count = coordinateIndices.length;
+
+ //
+ // Make sure sum of strip counts equals indexCount (or vertexCount)
+ // and check to make sure triangles and quads have the right number
+ // of vertices
+ //
+ if ((prim == TRIANGLE_STRIP_ARRAY) ||
+ (prim == TRIANGLE_FAN_ARRAY) ||
+ (prim == POLYGON_ARRAY)) {
+ int sum = 0;
+ for (int i = 0 ; i < stripCounts.length ; i++) {
+ sum += stripCounts[i];
+ }
+ if (sum != count) {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo7"));
+ }
+ } else if (prim == TRIANGLE_ARRAY) {
+ if (count % 3 != 0) {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo12"));
+ }
+ } else if (prim == QUAD_ARRAY) {
+ if (count % 4 != 0) {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo13"));
+ }
+ }
+
+ //
+ // For polygons, make sure the contours add up.
+ //
+ if (prim == POLYGON_ARRAY) {
+ if (contourCounts != null) {
+ int c = 0;
+ for (int i = 0 ; i < contourCounts.length ; i++)
+ c += contourCounts[i];
+ if (c != stripCounts.length) {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo8"));
+ }
+ }
+ } else {
+ if (contourCounts != null) {
+ throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfo14"));
+ }
+ }
+ } // End of checkForBadData
+
+
+
+ /**
+ * Get rid of index lists by reorganizing data into an un-indexed
+ * format. Does nothing if no index lists are set.
+ * @throws IllegalArgumentException if coordinate data is missing,
+ * if the index lists aren't all the
+ * same length, if an index list is set and the corresponding data
+ * list isn't set, if a data list is set and the corresponding
+ * index list is unset (unless all index lists are unset or in
+ * USE_COORD_INDEX_ONLY format),
+ * if StripCounts or ContourCounts is inconsistent with the current
+ * primitive, if the sum of the contourCounts array doesn't equal
+ * the length of the StripCounts array, or if the number of vertices
+ * isn't a multiple of three (for triangles) or four (for quads).
+ */
+ public void unindexify() {
+ checkForBadData();
+ if (coordinateIndices != null) {
+ // Switch from USE_COORD_INDEX_ONLY format
+ if (coordOnly) indexify(false);
+
+ coordinates =
+ (Point3f[])unindexifyData(coordinates, coordinateIndices);
+ coordinateIndices = null;
+
+ if (colors3 != null) {
+ colors3 = (Color3f[])unindexifyData(colors3, colorIndices);
+ } else if (colors4 != null) {
+ colors4 = (Color4f[])unindexifyData(colors4, colorIndices);
+ }
+ colorIndices = null;
+
+ if (normals != null) {
+ normals = (Vector3f[])unindexifyData(normals, normalIndices);
+ normalIndices = null;
+ }
+
+ for (int i = 0 ; i < texCoordSetCount ; i++)
+ texCoordSets[i] = unindexifyData(texCoordSets[i],
+ texCoordIndexSets[i]);
+ texCoordIndexSets = new int[texCoordSetCount][];
+ }
+ } // End of unindexify
+
+
+
+ /**
+ * Generic unindexify method. Can unindex data in any of the following
+ * formats Point3f, Color3f, Color4f, Vector3f, TexCoord2f, TexCoord3f,
+ * TexCoord4f.
+ */
+ private Object[] unindexifyData(Object data[], int index[])
+ {
+ Object newData[] = allocateArray(data, index.length);
+ for (int i = 0 ; i < index.length ; i++) {
+ newData[i] = data[index[i]];
+ }
+ return newData;
+ } // End of unindexifyData
+
+
+
+ /**
+ * Calculate vertexFormat based on data.
+ */
+ private int getVertexFormat()
+ {
+ int vertexFormat = GeometryArray.COORDINATES;
+
+ if (colors3 != null) vertexFormat |= GeometryArray.COLOR_3;
+ else if (colors4 != null) vertexFormat |= GeometryArray.COLOR_4;
+
+ if (normals != null) vertexFormat |= GeometryArray.NORMALS;
+
+ if (texCoordDim == 2)
+ vertexFormat |= GeometryArray.TEXTURE_COORDINATE_2;
+ else if (texCoordDim == 3)
+ vertexFormat |= GeometryArray.TEXTURE_COORDINATE_3;
+ else if (texCoordDim == 4)
+ vertexFormat |= GeometryArray.TEXTURE_COORDINATE_4;
+
+ return vertexFormat;
+ } // End of getVertexFormat
+
+
+
+ /**
+ * Calculate vertexCount based on data
+ */
+ private int getVertexCount()
+ {
+ int vertexCount = coordinates.length;
+
+ if (colors3 != null) {
+ if (colors3.length > vertexCount) vertexCount = colors3.length;
+ } else if (colors4 != null) {
+ if (colors4.length > vertexCount) vertexCount = colors4.length;
+ }
+
+ if (normals != null) {
+ if (normals.length > vertexCount) vertexCount = normals.length;
+ }
+
+ // Find max length tex coord set
+ for (int i = 0 ; i < texCoordSetCount ; i++) {
+ if (texCoordSets[i].length > vertexCount)
+ vertexCount = texCoordSets[i].length;
+ }
+
+ return vertexCount;
+ } // End of getVertexCount
+
+
+
+ /**
+ * Converts an array of Tuple2f, Tuple3f, or Tuple4f values into
+ * an array of floats. Assumes array is not null. Returns null
+ * if array is not Tuple2f, Tuple3f, or Tuple4f. Used by fillIn()
+ * for BY_REFERENCE not INTERLEAVED geometry.
+ */
+ private float[] vecmathToFloat(Object[] ar)
+ {
+ if (ar[0] instanceof Tuple2f) {
+ float[] p = new float[ar.length * 2];
+ Tuple2f[] a = (Tuple2f[])ar;
+ for (int i = 0 ; i < ar.length ; i++) {
+ p[i * 2] = a[i].x;
+ p[i * 2 + 1] = a[i].y;
+ }
+ return p;
+ } else if (ar[0] instanceof Tuple3f) {
+ float[] p = new float[ar.length * 3];
+ Tuple3f[] a = (Tuple3f[])ar;
+ for (int i = 0 ; i < ar.length ; i++) {
+ p[i * 3] = a[i].x;
+ p[i * 3 + 1] = a[i].y;
+ p[i * 3 + 2] = a[i].z;
+ }
+ return p;
+ } else if (ar[0] instanceof Tuple4f) {
+ float[] p = new float[ar.length * 4];
+ Tuple4f[] a = (Tuple4f[])ar;
+ for (int i = 0 ; i < ar.length ; i++) {
+ p[i * 4] = a[i].x;
+ p[i * 4 + 1] = a[i].y;
+ p[i * 4 + 2] = a[i].z;
+ p[i * 4 + 3] = a[i].w;
+ }
+ return p;
+ }
+ return null;
+ } // End of vecmathToFloat
+
+
+
+ /**
+ * Fill in the GeometryArray object. Used by getGeometryArray and
+ * getIndexedGeometryArray. checkForBadData has already been called.
+ */
+ private void fillIn(GeometryArray ga, boolean byRef, boolean interleaved,
+ boolean nio)
+ {
+ if (interleaved) {
+ // Calculate number of words per vertex
+ int wpv = 3; // Always have coordinate data
+ if (normals != null) wpv += 3;
+ if (colors3 != null) wpv += 3;
+ else if (colors4 != null) wpv += 4;
+ wpv += (texCoordSetCount * texCoordDim);
+
+ // Build array of interleaved data
+ float[] d = new float[wpv * coordinates.length];
+
+ // Fill in the array
+ int offset = 0;
+ for (int i = 0 ; i < coordinates.length ; i++) {
+ if (texCoordDim == 2) {
+ for (int j = 0 ; j < texCoordSetCount ; j++) {
+ d[offset++] = ((TexCoord2f)texCoordSets[j][i]).x;
+ d[offset++] = ((TexCoord2f)texCoordSets[j][i]).y;
+ }
+ } else if (texCoordDim == 3) {
+ for (int j = 0 ; j < texCoordSetCount ; j++) {
+ d[offset++] = ((TexCoord3f)texCoordSets[j][i]).x;
+ d[offset++] = ((TexCoord3f)texCoordSets[j][i]).y;
+ d[offset++] = ((TexCoord3f)texCoordSets[j][i]).z;
+ }
+ } else if (texCoordDim == 4) {
+ for (int j = 0 ; j < texCoordSetCount ; j++) {
+ d[offset++] = ((TexCoord4f)texCoordSets[j][i]).x;
+ d[offset++] = ((TexCoord4f)texCoordSets[j][i]).y;
+ d[offset++] = ((TexCoord4f)texCoordSets[j][i]).z;
+ d[offset++] = ((TexCoord4f)texCoordSets[j][i]).w;
+ }
+ }
+
+ if (colors3 != null) {
+ d[offset++] = colors3[i].x;
+ d[offset++] = colors3[i].y;
+ d[offset++] = colors3[i].z;
+ } else if (colors4 != null) {
+ d[offset++] = colors4[i].x;
+ d[offset++] = colors4[i].y;
+ d[offset++] = colors4[i].z;
+ d[offset++] = colors4[i].w;
+ }
+
+ if (normals != null) {
+ d[offset++] = normals[i].x;
+ d[offset++] = normals[i].y;
+ d[offset++] = normals[i].z;
+ }
+
+ d[offset++] = coordinates[i].x;
+ d[offset++] = coordinates[i].y;
+ d[offset++] = coordinates[i].z;
+ }
+ // Register reference to array of interleaved data
+ if (nio) {
+ ByteBuffer b = ByteBuffer.allocateDirect(d.length * 4);
+ FloatBuffer f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
+ f.put(d);
+ ga.setInterleavedVertexBuffer(new J3DBuffer(f));
+ } else ga.setInterleavedVertices(d);
+ } else if (nio) {
+
+ ByteBuffer b = ByteBuffer.allocateDirect(coordinates.length * 4 * 3);
+ FloatBuffer f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
+ f.put(vecmathToFloat(coordinates));
+ ga.setCoordRefBuffer(new J3DBuffer(f));
+
+ if (colors3 != null) {
+ b = ByteBuffer.allocateDirect(colors3.length * 4 * 3);
+ f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
+ f.put(vecmathToFloat(colors3));
+ ga.setColorRefBuffer(new J3DBuffer(f));
+ } else if (colors4 != null) {
+ b = ByteBuffer.allocateDirect(colors4.length * 4 * 4);
+ f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
+ f.put(vecmathToFloat(colors4));
+ ga.setColorRefBuffer(new J3DBuffer(f));
+ }
+
+ if (normals != null) {
+ b = ByteBuffer.allocateDirect(normals.length * 4 * 3);
+ f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
+ f.put(vecmathToFloat(normals));
+ ga.setNormalRefBuffer(new J3DBuffer(f));
+ }
+
+ for (int i = 0 ; i < texCoordSetCount ; i++) {
+ b = ByteBuffer.allocateDirect(texCoordSets[i].length * 4 * texCoordDim);
+ f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
+ f.put(vecmathToFloat(texCoordSets[i]));
+ ga.setTexCoordRefBuffer(i, new J3DBuffer(f));
+ }
+ } else if (byRef) {
+ // Need to copy the data into float arrays - GeometryArray
+ // prefers them over the vecmath types
+ ga.setCoordRefFloat(vecmathToFloat(coordinates));
+ if (colors3 != null) ga.setColorRefFloat(vecmathToFloat(colors3));
+ else if (colors4 != null) ga.setColorRefFloat(vecmathToFloat(colors4));
+ if (normals != null) ga.setNormalRefFloat(vecmathToFloat(normals));
+ for (int i = 0 ; i < texCoordSetCount ; i++) {
+ ga.setTexCoordRefFloat(i, vecmathToFloat(texCoordSets[i]));
+ }
+ } else {
+ ga.setCoordinates(0, coordinates);
+ if (colors3 != null) ga.setColors(0, colors3);
+ else if (colors4 != null) ga.setColors(0, colors4);
+ if (normals != null) ga.setNormals(0, normals);
+ for (int i = 0 ; i < texCoordSetCount ; i++) {
+ if (texCoordDim == 2) {
+ ga.setTextureCoordinates(i, 0, (TexCoord2f[])texCoordSets[i]);
+ } else if (texCoordDim == 3) {
+ ga.setTextureCoordinates(i, 0, (TexCoord3f[])texCoordSets[i]);
+ } else if (texCoordDim == 4) {
+ ga.setTextureCoordinates(i, 0, (TexCoord4f[])texCoordSets[i]);
+ }
+ }
+ }
+
+ if (coordinateIndices != null) {
+ IndexedGeometryArray iga = null;
+ iga = (IndexedGeometryArray)ga;
+ iga.setCoordinateIndices(0, coordinateIndices);
+ if (!coordOnly) {
+ if (colorIndices != null) iga.setColorIndices(0, colorIndices);
+ if (normalIndices != null) iga.setNormalIndices(0, normalIndices);
+ for (int i = 0 ; i < texCoordSetCount ; i++)
+ iga.setTextureCoordinateIndices(i, 0, texCoordIndexSets[i]);
+ }
+ }
+ } // End of fillIn
+
+
+
+ /**
+ * Redo indexes to guarantee connection information.
+ * Use this routine if your original data is in indexed format, but
+ * you don't trust that the indexing is correct. After this
+ * routine it is guaranteed that two points with the same
+ * position will have the same coordinate index (for example).
+ * Try this if you see
+ * glitches in your normals or stripification, to rule out
+ * bad indexing as the source of the problem. Works with normal
+ * indexed format or USE_COORD_INDEX_ONLY format.
+ * @throws IllegalArgumentException if coordinate data is missing,
+ * if the index lists aren't all the
+ * same length, if an index list is set and the corresponding data
+ * list isn't set, if a data list is set and the corresponding
+ * index list is unset (unless all index lists are unset or in
+ * USE_COORD_INDEX_ONLY format),
+ * if StripCounts or ContourCounts is inconsistent with the current
+ * primitive, if the sum of the contourCounts array doesn't equal
+ * the length of the StripCounts array, or if the number of vertices
+ * isn't a multiple of three (for triangles) or four (for quads).
+ */
+ public void recomputeIndices()
+ {
+ boolean remember = coordOnly;
+
+ // Can make more efficient implementation later
+ unindexify();
+ indexify(remember);
+ } // End of recomputeIndices
+
+
+
+ /**
+ * Reverse the order of an array of ints (computer class homework
+ * problem).
+ */
+ private void reverseList(int list[])
+ {
+ int t;
+
+ if (list == null) return;
+
+ for (int i = 0 ; i < list.length / 2 ; i++) {
+ t = list[i];
+ list[i] = list[list.length - i - 1];
+ list[list.length - i - 1] = t;
+ }
+ } // End of reverseList
+
+
+
+ /**
+ * Reverse the order of all lists. If your polygons are formatted with
+ * clockwise winding, you will always see the back and never the front.
+ * (Java 3D always wants vertices specified with a counter-clockwise
+ * winding.)
+ * This method will (in effect) reverse the winding of your data by
+ * inverting all of the index lists and the stripCounts
+ * and contourCounts lists.
+ * @throws IllegalArgumentException if coordinate data is missing,
+ * if the index lists aren't all the
+ * same length, if an index list is set and the corresponding data
+ * list isn't set, if a data list is set and the corresponding
+ * index list is unset (unless all index lists are unset or in
+ * USE_COORD_INDEX_ONLY format),
+ * if StripCounts or ContourCounts is inconsistent with the current
+ * primitive, if the sum of the contourCounts array doesn't equal
+ * the length of the StripCounts array, or if the number of vertices
+ * isn't a multiple of three (for triangles) or four (for quads).
+ */
+ public void reverse()
+ {
+ indexify();
+ reverseList(stripCounts);
+ reverseList(oldStripCounts);
+ reverseList(contourCounts);
+ reverseList(coordinateIndices);
+ reverseList(colorIndices);
+ reverseList(normalIndices);
+ for (int i = 0 ; i < texCoordSetCount ; i++)
+ reverseList(texCoordIndexSets[i]);
+ } // End of reverse
+
+
+
+ /**
+ * Returns true if the data in this GeometryInfo is currently
+ * formatted in the USE_COORD_INDEX_ONLY format where a single
+ * index list is used to index into all data lists.
+ * @see GeometryInfo#indexify(boolean)
+ * @see GeometryInfo#getIndexedGeometryArray(boolean, boolean, boolean,
+ * boolean, boolean)
+ */
+ public boolean getUseCoordIndexOnly()
+ {
+ return coordOnly;
+ } // End of getUseCoordIndexOnly
+
+
+
+ /**
+ * Tells the GeometryInfo that its data is formatted in the
+ * USE_COORD_INDEX_ONLY format with a single index list
+ * (the coordinate index list) that indexes into all data
+ * lists (coordinates, normals, colors, and texture
+ * coordinates). NOTE: this will not convert the data
+ * for you. This method is for when you are sending in
+ * data useng the setCoordinates, setNormals, setColors,
+ * and/or setTextureCoordinates methods, and you are only
+ * setting one index using setCoordinateIndices(). If
+ * you want GeometryInfo to convert your data to the
+ * USE_COORD_INDEX_ONLY format, use indexify(true) or
+ * getIndexedGeometryArray with the useCoordIndexOnly
+ * parameter set to true.
+ * @see GeometryInfo#indexify(boolean)
+ * @see GeometryInfo#getIndexedGeometryArray(boolean, boolean, boolean,
+ * boolean, boolean)
+ */
+ public void setUseCoordIndexOnly(boolean useCoordIndexOnly)
+ {
+ coordOnly = useCoordIndexOnly;
+ } // End of setUseCoordIndexOnly
+
+
+
+ /**
+ * Creates and returns a non-indexed Java 3D GeometryArray object
+ * based on the data in the GeometryInfo object. This object is
+ * suitable to be attached to a Shape3D node for rendering.
+ * @param byRef Use geometry BY_REFERENCE
+ * @param interleaved Use INTERLEAVED geometry. Implies byRef is
+ * true as well.
+ * @param nio Create GeometryArray using java.nio.Buffer for
+ * geometry arrays. Only usable on JDK 1.4 or higher. Implies
+ * byRef is true as well.
+ * @throws IllegalArgumentException if coordinate data is missing,
+ * if the index lists aren't all the
+ * same length, if an index list is set and the corresponding data
+ * list isn't set, if a data list is set and the corresponding
+ * index list is unset (unless all index lists are unset or in
+ * USE_COORD_INDEX_ONLY format),
+ * if StripCounts or ContourCounts is inconsistent with the current
+ * primitive, if the sum of the contourCounts array doesn't equal
+ * the length of the StripCounts array, or if the number of vertices
+ * isn't a multiple of three (for triangles) or four (for quads).
+ */
+ public GeometryArray getGeometryArray(boolean byRef, boolean interleaved,
+ boolean nio)
+ {
+ checkForBadData();
+
+ if (prim == POLYGON_ARRAY) {
+ if (tr == null) tr = new Triangulator();
+ tr.triangulate(this);
+ } else changeBackToOldPrim();
+
+ unindexify();
+
+ int vertexFormat = getVertexFormat();
+ if (nio) vertexFormat |= (GeometryArray.BY_REFERENCE |
+ GeometryArray.USE_NIO_BUFFER);
+ if (interleaved) vertexFormat |= (GeometryArray.BY_REFERENCE |
+ GeometryArray.INTERLEAVED);
+ if (byRef) vertexFormat |= GeometryArray.BY_REFERENCE;
+
+ int vertexCount = coordinates.length;
+
+ // If the texCoordSetMap hasn't been set, assume one set of
+ // texture coordinates only and one texture state unit
+ if ((texCoordSetCount > 0) && (texCoordSetMap == null)) {
+ texCoordSetCount = 1;
+ texCoordSetMap = new int[1];
+ texCoordSetMap[0] = 0;
+ }
+
+ // Create the GeometryArray object
+ GeometryArray ga = null;
+ switch (prim) {
+ case TRIANGLE_ARRAY:
+ TriangleArray ta = new TriangleArray(vertexCount, vertexFormat,
+ texCoordSetCount, texCoordSetMap);
+ ga = (GeometryArray)ta;
+ break;
+
+ case QUAD_ARRAY:
+ QuadArray qa = new QuadArray(vertexCount, vertexFormat,
+ texCoordSetCount, texCoordSetMap);
+ ga = (GeometryArray)qa;
+ break;
+
+ case TRIANGLE_STRIP_ARRAY:
+ TriangleStripArray tsa = new TriangleStripArray(vertexCount,
+ vertexFormat, texCoordSetCount, texCoordSetMap,
+ stripCounts);
+ ga = (GeometryArray)tsa;
+ break;
+
+ case TRIANGLE_FAN_ARRAY:
+ TriangleFanArray tfa = new TriangleFanArray(vertexCount,
+ vertexFormat, texCoordSetCount, texCoordSetMap,
+ stripCounts);
+ ga = (GeometryArray)tfa;
+ break;
+ }
+
+ fillIn(ga, byRef, interleaved, nio);
+
+ return ga;
+ } // End of getGeometryArray(int, int)
+
+
+
+ /**
+ * Creates and returns a non-indexed Java 3D GeometryArray object
+ * based on the data in the GeometryInfo object. This object is
+ * suitable to be attached to a Shape3D node for rendering.
+ * The geometry is not created using data BY_REFERENCE,
+ * INTERLEAVED, or USE_NIO_BUFFER.
+ * @throws IllegalArgumentException if coordinate data is missing,
+ * if the index lists aren't all the
+ * same length, if an index list is set and the corresponding data
+ * list isn't set, if a data list is set and the corresponding
+ * index list is unset (unless all index lists are unset or in
+ * USE_COORD_INDEX_ONLY format),
+ * if StripCounts or ContourCounts is inconsistent with the current
+ * primitive, if the sum of the contourCounts array doesn't equal
+ * the length of the StripCounts array, or if the number of vertices
+ * isn't a multiple of three (for triangles) or four (for quads).
+ */
+ public GeometryArray getGeometryArray()
+ {
+ return getGeometryArray(false, false, false);
+ } // End of getGeometryArray()
+
+
+
+ /**
+ * Creates and returns a IndexedGeometryArray
+ * based on the data in the GeometryInfo object. This object is
+ * suitable to be attached to a Shape3D node for rendering.
+ * @param compact Remove Coordinates, Colors, Normals, and
+ * TextureCoordinates that aren't referenced by any indices.
+ * @param byRef Create the IndexedGeometryArray using geometry
+ * BY_REFERENCE.
+ * @param interleaved Use INTERLEAVED geometry. Implies byRef is
+ * true as well.
+ * @param useCoordIndexOnly Create the IndexedGeometryArray using
+ * USE_COORD_INDEX_ONLY. Values from the coordinate index array
+ * are used as a single set of indices into all vertex
+ * component arrays (coord, color, normal, and texCoord).
+ * @param nio Create GeometryArray using java.nio.Buffer for
+ * geometry arrays. Only usable on JDK 1.4 or higher. Implies
+ * byRef is true as well.
+ * @throws IllegalArgumentException if coordinate data is missing,
+ * if the index lists aren't all the
+ * same length, if an index list is set and the corresponding data
+ * list isn't set, if a data list is set and the corresponding
+ * index list is unset (unless all index lists are unset or in
+ * USE_COORD_INDEX_ONLY format),
+ * if StripCounts or ContourCounts is inconsistent with the current
+ * primitive, if the sum of the contourCounts array doesn't equal
+ * the length of the StripCounts array, or if the number of vertices
+ * isn't a multiple of three (for triangles) or four (for quads).
+ */
+ public IndexedGeometryArray getIndexedGeometryArray(boolean compact,
+ boolean byRef,
+ boolean interleaved,
+ boolean useCoordIndexOnly,
+ boolean nio)
+ {
+ indexify(useCoordIndexOnly);
+
+ if (compact) compact();
+
+ if (prim == POLYGON_ARRAY) {
+ if (tr == null) tr = new Triangulator();
+ tr.triangulate(this);
+ } else changeBackToOldPrim();
+
+ if (useCoordIndexOnly && coordOnly == false) {
+ // Check to see if we can optimize for USE_COORD_INDEX_ONLY
+ int i, j;
+ boolean canUseCoordIndexOnly = true;
+
+ if (coordinateIndices != null) {
+ // See if all the array lengths are the same
+ if (colorIndices != null &&
+ colorIndices.length != coordinateIndices.length) {
+ canUseCoordIndexOnly = false;
+ }
+ if (normalIndices != null &&
+ normalIndices.length != coordinateIndices.length) {
+ canUseCoordIndexOnly = false;
+ }
+ for (i = 0 ; i < texCoordSetCount ; i++) {
+ if (texCoordIndexSets[i] != null &&
+ texCoordIndexSets[i].length != coordinateIndices.length) {
+ canUseCoordIndexOnly = false;
+ break;
+ }
+ }
+ if (canUseCoordIndexOnly &&
+ ((colorIndices != null) ||
+ (normalIndices != null) ||
+ (texCoordSetCount > 0))) {
+ // All array lengths are the same. Check their contents
+
+ for (i=0; igetIndexedGeometryArray(compact, false,
+ * false, false, false)
.
+ * @param compact Remove Coordinates, Colors, Normals, and
+ * TextureCoordinates that aren't referenced by any indices.
+ * @throws IllegalArgumentException if coordinate data is missing,
+ * if the index lists aren't all the
+ * same length, if an index list is set and the corresponding data
+ * list isn't set, if a data list is set and the corresponding
+ * index list is unset (unless all index lists are unset or in
+ * USE_COORD_INDEX_ONLY format),
+ * if StripCounts or ContourCounts is inconsistent with the current
+ * primitive, if the sum of the contourCounts array doesn't equal
+ * the length of the StripCounts array, or if the number of vertices
+ * isn't a multiple of three (for triangles) or four (for quads).
+ */
+ public IndexedGeometryArray getIndexedGeometryArray(boolean compact)
+ {
+ return getIndexedGeometryArray(compact, false, false, false, false);
+ } // End of getIndexedGeometryArray(boolean)
+
+
+
+ /**
+ * Creates and returns an IndexedGeometryArray
+ * based on the data in the GeometryInfo object. This object is
+ * suitable to be attached to a Shape3D node for rendering.
+ * Equivalent to getIndexedGeometryArray(false, false,
+ * false, false, false)
.
+ * @throws IllegalArgumentException if coordinate data is missing,
+ * if the index lists aren't all the
+ * same length, if an index list is set and the corresponding data
+ * list isn't set, if a data list is set and the corresponding
+ * index list is unset (unless all index lists are unset or in
+ * USE_COORD_INDEX_ONLY format),
+ * if StripCounts or ContourCounts is inconsistent with the current
+ * primitive, if the sum of the contourCounts array doesn't equal
+ * the length of the StripCounts array, or if the number of vertices
+ * isn't a multiple of three (for triangles) or four (for quads).
+ */
+ public IndexedGeometryArray getIndexedGeometryArray()
+ {
+ return getIndexedGeometryArray(false, false, false, false, false);
+ } // End of getIndexedGeometryArray()
+
+} // End of class GeometryInfo
+
+// End of file GeometryInfo.java
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/GeometryInfoGenerator.java b/src/classes/share/org/jogamp/java3d/utils/geometry/GeometryInfoGenerator.java
new file mode 100644
index 0000000..7a9100e
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/GeometryInfoGenerator.java
@@ -0,0 +1,862 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry;
+
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.GeometryStripArray;
+import org.jogamp.java3d.IndexedGeometryArray;
+import org.jogamp.java3d.IndexedGeometryStripArray;
+import org.jogamp.java3d.IndexedQuadArray;
+import org.jogamp.java3d.IndexedTriangleArray;
+import org.jogamp.java3d.IndexedTriangleFanArray;
+import org.jogamp.java3d.IndexedTriangleStripArray;
+import org.jogamp.java3d.J3DBuffer;
+import org.jogamp.java3d.QuadArray;
+import org.jogamp.java3d.TriangleArray;
+import org.jogamp.java3d.TriangleFanArray;
+import org.jogamp.java3d.TriangleStripArray;
+import org.jogamp.vecmath.Color3b;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4b;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.TexCoord2f;
+import org.jogamp.vecmath.TexCoord3f;
+import org.jogamp.vecmath.TexCoord4f;
+import org.jogamp.vecmath.Vector3f;
+
+import org.jogamp.java3d.internal.BufferWrapper;
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+
+
+/**
+ * Populate a GeometryInfo object from the Geometry provided. Used
+ * by GeometryInfo.
+ */
+class GeometryInfoGenerator extends Object {
+
+ public static void create(GeometryInfo geomInfo, GeometryArray geomArray)
+ {
+ if (geomArray instanceof GeometryStripArray)
+ create(geomInfo, (GeometryStripArray)geomArray);
+ else if (geomArray instanceof TriangleArray) {
+ geomInfo.reset(GeometryInfo.TRIANGLE_ARRAY);
+ processGeometryArray(geomInfo, geomArray);
+ } else if (geomArray instanceof QuadArray) {
+ geomInfo.reset(GeometryInfo.QUAD_ARRAY);
+ processGeometryArray(geomInfo, geomArray);
+ } else if (geomArray instanceof IndexedGeometryArray)
+ create(geomInfo, (IndexedGeometryArray)geomArray);
+ else throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfoGenerator0"));
+ } // End of create(GeometryInfo, GeometryArray)
+
+
+
+ private static void create(GeometryInfo geomInfo,
+ GeometryStripArray geomArray)
+ {
+ if (geomArray instanceof TriangleFanArray) {
+ geomInfo.reset(GeometryInfo.TRIANGLE_FAN_ARRAY);
+ } else if (geomArray instanceof TriangleStripArray) {
+ geomInfo.reset(GeometryInfo.TRIANGLE_STRIP_ARRAY);
+ } else throw new IllegalArgumentException(
+ J3dUtilsI18N.getString("GeometryInfoGenerator0"));
+
+ processGeometryArray(geomInfo, geomArray);
+ processStripArray(geomInfo, geomArray);
+ } // End of create(GeometryInfo, GeometryStripArray)
+
+
+
+ private static void create(GeometryInfo geomInfo,
+ IndexedGeometryArray geomArray)
+ {
+ if (geomArray instanceof IndexedQuadArray) {
+ geomInfo.reset(GeometryInfo.QUAD_ARRAY);
+ } else if (geomArray instanceof IndexedTriangleArray) {
+ geomInfo.reset(GeometryInfo.TRIANGLE_ARRAY);
+ } else if (geomArray instanceof IndexedTriangleFanArray) {
+ geomInfo.reset(GeometryInfo.TRIANGLE_FAN_ARRAY);
+ processIndexStripArray(geomInfo, (IndexedGeometryStripArray)geomArray);
+ } else if (geomArray instanceof IndexedTriangleStripArray) {
+ geomInfo.reset(GeometryInfo.TRIANGLE_STRIP_ARRAY);
+ processIndexStripArray(geomInfo, (IndexedGeometryStripArray)geomArray);
+ }
+
+ processGeometryArray(geomInfo, geomArray);
+ processIndexedArray(geomInfo, geomArray);
+ } // End of create(GeometryInfo, IndexedGeometryArray)
+
+
+
+ private static void processGeometryArray(GeometryInfo geomInfo,
+ GeometryArray geomArray)
+ {
+ int i, j;
+ int vertexFormat = geomArray.getVertexFormat();
+ int texSets = geomArray.getTexCoordSetCount();
+ int valid;
+
+ // Calculate validVertexCount
+ if (geomArray instanceof GeometryStripArray) {
+ // Does not include IndexedGeometryStripArray
+ GeometryStripArray gsa = (GeometryStripArray)geomArray;
+ int[] strips = new int[gsa.getNumStrips()];
+ gsa.getStripVertexCounts(strips);
+ valid = 0;
+ for (i = 0 ; i < strips.length ; i++) {
+ valid += strips[i];
+ }
+ } else if (geomArray instanceof IndexedGeometryArray) {
+ valid = geomArray.getVertexCount();
+ } else valid = geomArray.getValidVertexCount();
+
+ if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+
+ // Calculate words_per_vertex (wpv)
+ int wpv = 3; // Always have coordinate data
+ if ((vertexFormat & GeometryArray.NORMALS) != 0) wpv += 3;
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4)
+ wpv += 4;
+ else if ((vertexFormat & GeometryArray.COLOR_3) != 0) wpv += 3;
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0)
+ wpv += 2 * texSets;
+ else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0)
+ wpv += 3 * texSets;
+ else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0)
+ wpv += 4 * texSets;
+
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialVertexIndex();
+ } else initial = 0;
+
+ float[] d;
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) {
+ J3DBuffer b = geomArray.getInterleavedVertexBuffer();
+ FloatBuffer w = (FloatBuffer)b.getBuffer();
+ d = new float[w.limit()];
+ w.position( 0 );
+ w.get(d);
+ } else d = geomArray.getInterleavedVertices();
+
+ int offset = 0;
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
+ geomInfo.setTextureCoordinateParams(texSets, 2);
+ int[] map = new int[geomArray.getTexCoordSetMapLength()];
+ geomArray.getTexCoordSetMap(map);
+ geomInfo.setTexCoordSetMap(map);
+ for (i = 0 ; i < texSets ; i++) {
+ TexCoord2f[] tex = new TexCoord2f[valid];
+ for (j = 0 ; j < valid ; j++) {
+ tex[j] = new TexCoord2f(d[wpv * (j + initial) + offset],
+ d[wpv * (j + initial) + offset + 1]);
+ }
+ geomInfo.setTextureCoordinates(i, tex);
+ offset += 2;
+ }
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ geomInfo.setTextureCoordinateParams(texSets, 3);
+ int[] map = new int[geomArray.getTexCoordSetMapLength()];
+ geomArray.getTexCoordSetMap(map);
+ geomInfo.setTexCoordSetMap(map);
+ for (i = 0 ; i < texSets ; i++) {
+ TexCoord3f[] tex = new TexCoord3f[valid];
+ for (j = 0 ; j < valid ; j++) {
+ tex[j] = new TexCoord3f(d[wpv * (j + initial) + offset],
+ d[wpv * (j + initial) + offset + 1],
+ d[wpv * (j + initial) + offset + 2]);
+ }
+ geomInfo.setTextureCoordinates(i, tex);
+ offset += 3;
+ }
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ geomInfo.setTextureCoordinateParams(texSets, 4);
+ int[] map = new int[geomArray.getTexCoordSetMapLength()];
+ geomArray.getTexCoordSetMap(map);
+ geomInfo.setTexCoordSetMap(map);
+ for (i = 0 ; i < texSets ; i++) {
+ TexCoord4f[] tex = new TexCoord4f[valid];
+ for (j = 0 ; j < valid ; j++) {
+ tex[j] = new TexCoord4f(d[wpv * (j + initial) + offset],
+ d[wpv * (j + initial) + offset + 1],
+ d[wpv * (j + initial) + offset + 2],
+ d[wpv * (j + initial) + offset + 3]);
+ }
+ geomInfo.setTextureCoordinates(i, tex);
+ offset += 4;
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
+ Color4f[] color = new Color4f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ color[i] = new Color4f(d[wpv * (i + initial) + offset],
+ d[wpv * (i + initial) + offset + 1],
+ d[wpv * (i + initial) + offset + 2],
+ d[wpv * (i + initial) + offset + 3]);
+ }
+ geomInfo.setColors(color);
+ offset += 4;
+ } else if ((vertexFormat & GeometryArray.COLOR_3) != 0) {
+ Color3f[] color = new Color3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ color[i] = new Color3f(d[wpv * (i + initial) + offset],
+ d[wpv * (i + initial) + offset + 1],
+ d[wpv * (i + initial) + offset + 2]);
+ }
+ geomInfo.setColors(color);
+ offset += 3;
+ }
+
+ if ((vertexFormat & GeometryArray.NORMALS) != 0) {
+ Vector3f[] normals = new Vector3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ normals[i] = new Vector3f(d[wpv * (i + initial) + offset],
+ d[wpv * (i + initial) + offset + 1],
+ d[wpv * (i + initial) + offset + 2]);
+ }
+ geomInfo.setNormals(normals);
+ offset += 3;
+ }
+
+ Point3f[] coords = new Point3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ coords[i] = new Point3f(d[wpv * (i + initial) + offset],
+ d[wpv * (i + initial) + offset + 1],
+ d[wpv * (i + initial) + offset + 2]);
+ }
+ geomInfo.setCoordinates(coords);
+ } else {
+ // Data is not INTERLEAVED
+ boolean byRef = ((vertexFormat & GeometryArray.BY_REFERENCE) != 0 );
+ boolean nio = ((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 );
+
+ Point3f[] coords = null;
+ if (byRef) {
+
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialCoordIndex();
+ } else initial = 0;
+
+ if ( nio ) {
+ J3DBuffer buf = geomArray.getCoordRefBuffer();
+
+ switch (BufferWrapper.getBufferType(buf)) {
+
+ case BufferWrapper.TYPE_FLOAT: {
+ FloatBuffer bb = (FloatBuffer)buf.getBuffer();
+ float[] c = new float[valid * 3];
+ bb.position(initial * 3);
+ bb.get(c, 0, valid * 3);
+ coords = new Point3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ coords[i] = new Point3f(c[i * 3 + 0],
+ c[i * 3 + 1],
+ c[i * 3 + 2]);
+ }
+ }
+ break;
+
+ case BufferWrapper.TYPE_DOUBLE: {
+ DoubleBuffer bb = (DoubleBuffer)buf.getBuffer();
+ double[] c = new double[valid * 3];
+ bb.position(initial * 3);
+ bb.get(c, 0, valid * 3);
+ coords = new Point3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ coords[i] = new Point3f((float)(c[i * 3 + 0]),
+ (float)(c[i * 3 + 1]),
+ (float)(c[i * 3 + 2]));
+ }
+ }
+ break;
+ }
+ } else if (geomArray.getCoordRef3f() != null) {
+ if (initial != 0) {
+ Point3f[] c = geomArray.getCoordRef3f();
+ coords = new Point3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ coords[i] = new Point3f(c[i + initial]);
+ }
+ } else coords = geomArray.getCoordRef3f();
+ } else if (geomArray.getCoordRef3d() != null) {
+ Point3d[] c = geomArray.getCoordRef3d();
+ coords = new Point3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ coords[i] = new Point3f(c[i + initial]);
+ }
+ } else if (geomArray.getCoordRefFloat() != null) {
+ float[] c = geomArray.getCoordRefFloat();
+ coords = new Point3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ coords[i] = new Point3f(c[(i + initial) * 3],
+ c[(i + initial) * 3 + 1],
+ c[(i + initial) * 3 + 2]);
+ }
+ } else if (geomArray.getCoordRefDouble() != null) {
+ double[] c = geomArray.getCoordRefDouble();
+ coords = new Point3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ coords[i] = new Point3f((float)(c[(i + initial) * 3]),
+ (float)(c[(i + initial) * 3 + 1]),
+ (float)(c[(i + initial) * 3 + 2]));
+ }
+ }
+ // No coordinate data - let GeometryInfo handle this.
+ } else {
+ // Not BY_REFERENCE
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialVertexIndex();
+ } else initial = 0;
+ coords = new Point3f[valid];
+ for (i = 0 ; i < valid ; i++) coords[i] = new Point3f();
+ geomArray.getCoordinates(initial, coords);
+ }
+ geomInfo.setCoordinates(coords);
+
+ if ((vertexFormat & GeometryArray.NORMALS) != 0) {
+ Vector3f[] normals = null;
+ if (byRef) {
+
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialNormalIndex();
+ } else initial = 0;
+
+ if ( nio ) {
+ J3DBuffer buf = geomArray.getNormalRefBuffer();
+
+ if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) {
+ FloatBuffer bb = (FloatBuffer)buf.getBuffer();
+ float[] c = new float[valid * 3];
+ bb.position(initial * 3);
+ bb.get(c, 0, valid * 3);
+ normals = new Vector3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ normals[i] = new Vector3f(c[i * 3 + 0],
+ c[i * 3 + 1],
+ c[i * 3 + 2]);
+ }
+ }
+ // Normals were set in vertexFormat but none were set - OK
+ } else if (geomArray.getNormalRef3f() != null) {
+ if (initial != 0) {
+ Vector3f[] n = geomArray.getNormalRef3f();
+ normals = new Vector3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ normals[i] = new Vector3f(n[i + initial]);
+ }
+ } else normals = geomArray.getNormalRef3f();
+ } else if (geomArray.getNormalRefFloat() != null) {
+ float[] n = geomArray.getNormalRefFloat();
+ normals = new Vector3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ normals[i] = new Vector3f(n[(i + initial) * 3],
+ n[(i + initial) * 3 + 1],
+ n[(i + initial) * 3 + 2]);
+ }
+ }
+ // Normals were set in vertexFormat but none were set - OK
+ } else {
+ // Not BY_REFERENCE
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialVertexIndex();
+ } else initial = 0;
+ normals = new Vector3f[valid];
+ for (i = 0 ; i < valid ; i++) normals[i] = new Vector3f();
+ geomArray.getNormals(initial, normals);
+ }
+ geomInfo.setNormals(normals);
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
+ Color4f[] colors = null;
+ if (byRef) {
+
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialColorIndex();
+ } else initial = 0;
+
+ if ( nio ) {
+ J3DBuffer buf = geomArray.getColorRefBuffer();
+
+ switch (BufferWrapper.getBufferType(buf)) {
+
+ case BufferWrapper.TYPE_FLOAT: {
+ FloatBuffer bb = (FloatBuffer)buf.getBuffer();
+ float[] c = new float[valid * 4];
+ bb.position(initial * 4);
+ bb.get(c, 0, valid * 4);
+ colors = new Color4f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color4f(c[i * 4 + 0],
+ c[i * 4 + 1],
+ c[i * 4 + 2],
+ c[i * 4 + 3]);
+ }
+ }
+ break;
+
+ case BufferWrapper.TYPE_BYTE: {
+ ByteBuffer bb = (ByteBuffer)buf.getBuffer();
+ byte[] c = new byte[valid * 4];
+ bb.position(initial * 4);
+ bb.get(c, 0, valid * 4);
+ colors = new Color4f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color4f((float)(c[i * 4 + 0] & 0xff) / 255.0f,
+ (float)(c[i * 4 + 1] & 0xff) / 255.0f,
+ (float)(c[i * 4 + 2] & 0xff) / 255.0f,
+ (float)(c[i * 4 + 3] & 0xff) / 255.0f);
+ }
+ }
+ break;
+ }
+ } else if (geomArray.getColorRef4f() != null) {
+ if (initial != 0) {
+ Color4f[] c = geomArray.getColorRef4f();
+ colors = new Color4f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color4f(c[i + initial]);
+ }
+ } else colors = geomArray.getColorRef4f();
+ } else if (geomArray.getColorRefFloat() != null) {
+ float[] c = geomArray.getColorRefFloat();
+ colors = new Color4f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color4f(c[(i + initial) * 4 + 0],
+ c[(i + initial) * 4 + 1],
+ c[(i + initial) * 4 + 2],
+ c[(i + initial) * 4 + 3]);
+ }
+ } else if (geomArray.getColorRefByte() != null) {
+ byte[] c = geomArray.getColorRefByte();
+ colors = new Color4f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color4f((float)(c[(i + initial) * 4 + 0] & 0xff) / 255.0f,
+ (float)(c[(i + initial) * 4 + 1] & 0xff) / 255.0f,
+ (float)(c[(i + initial) * 4 + 2] & 0xff) / 255.0f,
+ (float)(c[(i + initial) * 4 + 3] & 0xff) / 255.0f);
+ }
+ } else if (geomArray.getColorRef4b() != null) {
+ Color4b[] c = geomArray.getColorRef4b();
+ colors = new Color4f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color4f((float)(c[i + initial].x & 0xff) / 255.0f,
+ (float)(c[i + initial].y & 0xff) / 255.0f,
+ (float)(c[i + initial].z & 0xff) / 255.0f,
+ (float)(c[i + initial].w & 0xff) / 255.0f);
+ }
+ }
+ // Colors4 were set in vertexFormat but none were set - OK
+ } else {
+ // Not BY_REFERENCE
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialVertexIndex();
+ } else initial = 0;
+ colors = new Color4f[valid];
+ for (i = 0 ; i < valid ; i++) colors[i] = new Color4f();
+ geomArray.getColors(initial, colors);
+ }
+ geomInfo.setColors(colors);
+ } else if ((vertexFormat & GeometryArray.COLOR_3) != 0) {
+ Color3f[] colors = null;
+ if (byRef) {
+
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialColorIndex();
+ } else initial = 0;
+
+ if ( nio ) {
+ J3DBuffer buf = geomArray.getColorRefBuffer();
+
+ switch (BufferWrapper.getBufferType(buf)) {
+
+ case BufferWrapper.TYPE_FLOAT: {
+ FloatBuffer bb = (FloatBuffer)buf.getBuffer();
+ float[] c = new float[valid * 3];
+ bb.position(initial * 3);
+ bb.get(c, 0, valid * 3);
+ colors = new Color3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color3f(c[i * 3 + 0],
+ c[i * 3 + 1],
+ c[i * 3 + 2]);
+ }
+ }
+ break;
+
+ case BufferWrapper.TYPE_BYTE: {
+ ByteBuffer bb = (ByteBuffer)buf.getBuffer();
+ byte[] c = new byte[valid * 3];
+ bb.position(initial * 3);
+ bb.get(c, 0, valid * 3);
+ colors = new Color3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color3f((float)(c[i * 3 + 0] & 0xff) / 255.0f,
+ (float)(c[i * 3 + 1] & 0xff) / 255.0f,
+ (float)(c[i * 3 + 2] & 0xff) / 255.0f);
+ }
+ }
+ break;
+ }
+ } else if (geomArray.getColorRef3f() != null) {
+ if (initial != 0) {
+ Color3f[] c = geomArray.getColorRef3f();
+ colors = new Color3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color3f(c[i + initial]);
+ }
+ } else colors = geomArray.getColorRef3f();
+ } else if (geomArray.getColorRefFloat() != null) {
+ float[] c = geomArray.getColorRefFloat();
+ colors = new Color3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color3f(c[(i + initial) * 3 + 0],
+ c[(i + initial) * 3 + 1],
+ c[(i + initial) * 3 + 2]);
+ }
+ } else if (geomArray.getColorRefByte() != null) {
+ byte[] c = geomArray.getColorRefByte();
+ colors = new Color3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color3f((float)(c[(i + initial) * 3 + 0] & 0xff) / 255.0f,
+ (float)(c[(i + initial) * 3 + 1] & 0xff) / 255.0f,
+ (float)(c[(i + initial) * 3 + 2] & 0xff) / 255.0f);
+ }
+ } else if (geomArray.getColorRef3b() != null) {
+ Color3b[] c = geomArray.getColorRef3b();
+ colors = new Color3f[valid];
+ for (i = 0 ; i < valid ; i++) {
+ colors[i] = new Color3f((float)(c[i + initial].x & 0xff) / 255.0f,
+ (float)(c[i + initial].y & 0xff) / 255.0f,
+ (float)(c[i + initial].z & 0xff) / 255.0f);
+ }
+ }
+ // Colors3 were set in vertexFormat but none were set - OK
+ } else {
+ // Not BY_REFERENCE
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialVertexIndex();
+ } else initial = 0;
+ colors = new Color3f[valid];
+ for (i = 0 ; i < valid ; i++) colors[i] = new Color3f();
+ geomArray.getColors(initial, colors);
+ }
+ geomInfo.setColors(colors);
+ }
+
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ geomInfo.setTextureCoordinateParams(texSets, 4);
+ for (i = 0 ; i < texSets ; i++) {
+ TexCoord4f[] tex = null;
+ if (byRef) {
+
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialTexCoordIndex(i);
+ } else initial = 0;
+
+ if (nio) {
+ J3DBuffer buf = geomArray.getTexCoordRefBuffer(i);
+
+ if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) {
+ FloatBuffer bb = (FloatBuffer)buf.getBuffer();
+ float[] c = new float[valid * 4];
+ bb.position(initial * 4);
+ bb.get(c, 0, valid * 4);
+ tex = new TexCoord4f[valid];
+ for (j = 0 ; j < valid ; j++) {
+ tex[j] = new TexCoord4f(c[j * 4 + 0],
+ c[j * 4 + 1],
+ c[j * 4 + 2],
+ c[j * 4 + 3]);
+ }
+ }
+ // TexCoords4 were set in vertexFormat but none were set - OK
+ } else {
+ // There if no TexCoordRef4f, so we know it's float
+ float[] t = geomArray.getTexCoordRefFloat(i);
+ tex = new TexCoord4f[valid];
+ for (j = 0 ; j < valid ; j++) {
+ tex[j] = new TexCoord4f(t[(j + initial) * 4],
+ t[(j + initial) * 4 + 1],
+ t[(j + initial) * 4 + 2],
+ t[(j + initial) * 4 + 3]);
+ }
+ }
+ } else {
+ // Not BY_REFERENCE
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialVertexIndex();
+ } else initial = 0;
+ tex = new TexCoord4f[valid];
+ for (j = 0 ; j < valid ; j++) tex[j] = new TexCoord4f();
+ geomArray.getTextureCoordinates(i, initial, tex);
+ }
+ geomInfo.setTextureCoordinates(i, tex);
+ }
+ int[] map = new int[geomArray.getTexCoordSetMapLength()];
+ geomArray.getTexCoordSetMap(map);
+ geomInfo.setTexCoordSetMap(map);
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ geomInfo.setTextureCoordinateParams(texSets, 3);
+ for (i = 0 ; i < texSets ; i++) {
+ TexCoord3f[] tex = null;
+ if (byRef) {
+
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialTexCoordIndex(i);
+ } else initial = 0;
+
+ if (nio) {
+ J3DBuffer buf = geomArray.getTexCoordRefBuffer(i);
+
+ if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) {
+ FloatBuffer bb = (FloatBuffer)buf.getBuffer();
+ float[] c = new float[valid * 3];
+ bb.position(initial * 3);
+ bb.get(c, 0, valid * 3);
+ tex = new TexCoord3f[valid];
+ for (j = 0 ; j < valid ; j++) {
+ tex[j] = new TexCoord3f(c[j * 3 + 0],
+ c[j * 3 + 1],
+ c[j * 3 + 2]);
+ }
+ }
+ // TexCoords3 were set in vertexFormat but none were set - OK
+ } else if (geomArray.getTexCoordRef3f(i) != null) {
+ if (initial != 0) {
+ TexCoord3f[] t = geomArray.getTexCoordRef3f(i);
+ tex = new TexCoord3f[valid];
+ for (j = 0 ; j < valid ; j++) {
+ tex[j] = new TexCoord3f(t[j + initial]);
+ }
+ } else tex = geomArray.getTexCoordRef3f(i);
+ } else if (geomArray.getTexCoordRefFloat(i) != null) {
+ float[] t = geomArray.getTexCoordRefFloat(i);
+ tex = new TexCoord3f[valid];
+ for (j = 0 ; j < valid ; j++) {
+ tex[j] = new TexCoord3f(t[(j + initial) * 3],
+ t[(j + initial) * 3 + 1],
+ t[(j + initial) * 3 + 2]);
+ }
+ }
+ // TexCoords3 were set in vertexFormat but none were set - OK
+ } else {
+ // Not BY_REFERENCE
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialVertexIndex();
+ } else initial = 0;
+ tex = new TexCoord3f[valid];
+ for (j = 0 ; j < valid ; j++) tex[j] = new TexCoord3f();
+ geomArray.getTextureCoordinates(i, initial, tex);
+ }
+ geomInfo.setTextureCoordinates(i, tex);
+ }
+ int[] map = new int[geomArray.getTexCoordSetMapLength()];
+ geomArray.getTexCoordSetMap(map);
+ geomInfo.setTexCoordSetMap(map);
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0 ) {
+ geomInfo.setTextureCoordinateParams(texSets, 2);
+ for (i = 0 ; i < texSets ; i++) {
+ TexCoord2f[] tex = null;
+ if (byRef) {
+
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialTexCoordIndex(i);
+ } else initial = 0;
+
+ if (nio) {
+ J3DBuffer buf = geomArray.getTexCoordRefBuffer(i);
+
+ if (BufferWrapper.getBufferType(buf) == BufferWrapper.TYPE_FLOAT) {
+ FloatBuffer bb = (FloatBuffer)buf.getBuffer();
+ float[] c = new float[valid * 2];
+ bb.position(initial * 2);
+ bb.get(c, 0, valid * 2);
+ tex = new TexCoord2f[valid];
+ for (j = 0 ; j < valid ; j++) {
+ tex[j] = new TexCoord2f(c[j * 2 + 0],
+ c[j * 2 + 1]);
+ }
+ }
+ // TexCoords2 were set in vertexFormat but none were set - OK
+ } else if (geomArray.getTexCoordRefFloat(i) != null) {
+ float[] t = geomArray.getTexCoordRefFloat(i);
+ tex = new TexCoord2f[valid];
+ for (j = 0 ; j < valid ; j++) {
+ tex[j] = new TexCoord2f(t[(j + initial) * 2 + 0],
+ t[(j + initial) * 2 + 1]);
+ }
+ } else if (geomArray.getTexCoordRef2f(i) != null) {
+ if (initial != 0) {
+ TexCoord2f[] t = geomArray.getTexCoordRef2f(i);
+ tex = new TexCoord2f[valid];
+ for (j = 0 ; j < valid ; j++) {
+ tex[j] = new TexCoord2f(t[j + initial]);
+ }
+ } else tex = geomArray.getTexCoordRef2f(i);
+ }
+ // TexCoords2 were set in vertexFormat but none were set - OK
+ } else {
+ // Not BY_REFERENCE
+ int initial;
+ if (!(geomArray instanceof IndexedGeometryArray)) {
+ initial = geomArray.getInitialVertexIndex();
+ } else initial = 0;
+ tex = new TexCoord2f[valid];
+ for (j = 0 ; j < valid ; j++) tex[j] = new TexCoord2f();
+ geomArray.getTextureCoordinates(i, initial, tex);
+ }
+ geomInfo.setTextureCoordinates(i, tex);
+ }
+ int[] map = new int[geomArray.getTexCoordSetMapLength()];
+ geomArray.getTexCoordSetMap(map);
+ geomInfo.setTexCoordSetMap(map);
+ }
+ }
+ } // End of processGeometryArray
+
+
+
+ private static void processIndexedArray(GeometryInfo geomInfo,
+ IndexedGeometryArray geomArray)
+ {
+ int initial = geomArray.getInitialIndexIndex();
+ int vertexFormat = geomArray.getVertexFormat();
+ int texSets = geomArray.getTexCoordSetCount();
+
+ int valid;
+ if (geomArray instanceof IndexedGeometryStripArray) {
+ IndexedGeometryStripArray igsa = (IndexedGeometryStripArray)geomArray;
+ int[] strips = new int[igsa.getNumStrips()];
+ igsa.getStripIndexCounts(strips);
+ valid = 0;
+ for (int i = 0 ; i < strips.length ; i++) {
+ valid += strips[i];
+ }
+ } else {
+ valid = geomArray.getValidIndexCount();
+ }
+
+ int[] coordI = new int[valid];
+ geomArray.getCoordinateIndices(initial, coordI);
+ geomInfo.setCoordinateIndices(coordI);
+
+ if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) {
+ if ((vertexFormat & GeometryArray.NORMALS) != 0)
+ geomInfo.setNormalIndices(coordI);
+ if (((vertexFormat & GeometryArray.COLOR_3) != 0) ||
+ ((vertexFormat & GeometryArray.COLOR_4) != 0))
+ geomInfo.setColorIndices(coordI);
+ if (((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) ||
+ ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) ||
+ ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0)) {
+ for (int i = 0 ; i < texSets ; i++) {
+ geomInfo.setTextureCoordinateIndices(i, coordI);
+ }
+ }
+ } else {
+ if ((vertexFormat & GeometryArray.NORMALS) != 0) {
+ int[] normalI = new int[valid];
+ geomArray.getNormalIndices(initial, normalI);
+ geomInfo.setNormalIndices(normalI);
+ }
+
+ if (((vertexFormat & GeometryArray.COLOR_3) != 0) ||
+ ((vertexFormat & GeometryArray.COLOR_4) != 0)) {
+ int[] colorI = new int[valid];
+ geomArray.getColorIndices(initial, colorI);
+ geomInfo.setColorIndices(colorI);
+ }
+
+ if (((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) ||
+ ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) ||
+ ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0)) {
+ for (int i = 0 ; i < texSets ; i++) {
+ int[] texI = new int[valid];
+ geomArray.getTextureCoordinateIndices(i, initial, texI);
+ geomInfo.setTextureCoordinateIndices(i, texI);
+ }
+ }
+ }
+ } // End of processIndexedArray
+
+
+
+ private static void processStripArray(GeometryInfo geomInfo,
+ GeometryStripArray geomArray)
+ {
+ int[] strips = new int[geomArray.getNumStrips()];
+ geomArray.getStripVertexCounts(strips);
+ geomInfo.setStripCounts(strips);
+ } // End of processStripArray
+
+
+
+ private static void processIndexStripArray(
+ GeometryInfo geomInfo, IndexedGeometryStripArray geomArray)
+ {
+ int[] strips = new int[geomArray.getNumStrips()];
+ geomArray.getStripIndexCounts(strips);
+ geomInfo.setStripCounts(strips);
+ } // End of processIndexStripArray
+
+} // End of class GeometryInfoGenerator
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/GeometryServiceImpl.java b/src/classes/share/org/jogamp/java3d/utils/geometry/GeometryServiceImpl.java
new file mode 100644
index 0000000..d80a607
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/GeometryServiceImpl.java
@@ -0,0 +1,38 @@
+
+package org.jogamp.java3d.utils.geometry;
+
+import java.util.ArrayList;
+
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.GeometryService;
+import org.jogamp.vecmath.Point3f;
+
+/**
+ * Default implementation of the {@link GeometryService} service interface.
+ */
+public class GeometryServiceImpl implements GeometryService {
+
+ @Override
+ public int triangulateIslands(final int[][] islandCounts,
+ final Point3f[][] outVerts, final int[] contourCounts,
+ final ArrayList+ *
+ * If two (or more) triangles in the model share the same coordinate + * index then the normal generator will attempt to generate one normal + * for the vertex, resulting in a "smooth" looking surface. If two + * coordinates don't have the same index then they will have two + * separate normals, even if they have the same position. This will + * result in a "crease" in your object. If you suspect that your + * data isn't properly indexed, call GeometryInfo.recomputeIndexes().
+ *
+ * Of course, sometimes your model *has* a crease in it. That's what
+ * creaseAngle is. If two triangles' normals differ by more than
+ * creaseAngle, then the vertex will get two separate normals, creating a
+ * discontinuous crease in the model. This is perfect for the edge
+ * of a table or the corner of a cube, for instance.
+ */
+
+public class NormalGenerator {
+
+ private double creaseAngle;
+ private ArrayList
+ * When a texture is applied to a Sphere, it is mapped CCW from the back
+ * of the sphere.
+ *
+ * By default all primitives with the same parameters share their
+ * geometry (e.g., you can have 50 shperes in your scene, but the
+ * geometry is stored only once). A change to one primitive will
+ * effect all shared nodes. Another implication of this
+ * implementation is that the capabilities of the geometry are shared,
+ * and once one of the shared nodes is live, the capabilities cannot
+ * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to
+ * share geometry among primitives with the same parameters.
+ */
+
+public class Sphere extends Primitive {
+
+ /**
+ * Sphere shape identifier, used by
+ * If the appearance is null, the sphere defaults to a white appearance.
+ */
+ public Sphere(float radius, int primflags, int divisions, Appearance ap) {
+ super();
+
+ int sign;
+ int n, nstep;
+
+ this.radius = radius;
+ this.divisions = divisions;
+
+ /*
+ * The sphere algorithm evaluates spherical angles along regular
+ * units. For each spherical coordinate, (theta, rho), a (x,y,z) is
+ * evaluated (along with the normals and texture coordinates).
+ *
+ * The spherical angles theta varies from 0 to 2pi and rho from 0
+ * to pi. Sample points depends on the number of divisions.
+ */
+
+ flags = primflags;
+ boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0;
+
+ //Depending on whether normal inward bit is set.
+ if ((flags & GENERATE_NORMALS_INWARD) != 0) {
+ sign = -1;
+ } else {
+ sign = 1;
+ }
+
+ if (divisions < 4) {
+ nstep = 1;
+ n = 4;
+ } else {
+ int mod = divisions % 4;
+ if (mod == 0) {
+ n = divisions;
+ } else {
+ n = divisions + (4 - mod);
+ }
+ nstep = n/4;
+ }
+
+
+ GeomBuffer cache = getCachedGeometry(Primitive.SPHERE,
+ radius, 0.0f, 0.0f,
+ divisions, 0, primflags);
+
+ Shape3D shape;
+
+ if (cache != null) {
+ shape = new Shape3D(cache.getComputedGeometry());
+ numVerts += cache.getNumVerts();
+ numTris += cache.getNumTris();
+ } else {
+ // buffer size = 8*(1 + 2E{i} + (nstep+1))
+ // where E{i} = sum of i = 2 ... nstep
+ GeomBuffer gbuf = new GeomBuffer(8*nstep*(nstep+2));
+
+ for (int i=0; i < 4; i++) {
+ buildQuadrant(gbuf, i*Math.PI/2, (i+1)*Math.PI/2, sign, nstep, n, true);
+ buildQuadrant(gbuf, i*Math.PI/2, (i+1)*Math.PI/2, sign, nstep, n, false);
+ }
+
+ // Fix to Issue 411. Java 3D prefers images used for texture mapping to be Y-up
+ if (texCoordYUp) {
+ TexCoord2f[] texCoords = gbuf.getTexCoords();
+ if (texCoords != null) {
+ for (int ii=0; ii
+ * For any NodeComponent objects
+ * contained by the object being duplicated, each NodeComponent
+ * object's
+ *
+ * Normal Generation should be performed on the GeometryInfo object
+ * before Stripification, for best results. Example:
+ *
+ *
+ *
+ *
+ * A compression command includes an 8-bit header and can range up to 72
+ * bits in length. The command with the maximum length is a 2-bit color
+ * command with a 6-bit tag in the header, followed by four 16-bit color
+ * components of data.
+ *
+ * A subcommand is either a position, normal, or color, though in practice
+ * a position subcommand can only be part of a vertex command. Normal and
+ * color subcommands can be parts of separate global normal and color
+ * commands as well as parts of a vertex command.
+ *
+ * A subcommand includes a 6-bit header. Its length is 2 bits less than
+ * the length of the corresponding command.
+ *
+ * @param header contains compression command header bits, right-justified
+ * within the bits of the int
+ * @param headerLength number of bits in header, either 8 for commands or
+ * 6 for subcommands
+ * @param body contains the body of the compression command,
+ * right-justified within the bits of the long
+ * @param bodyLength number of bits in the body
+ */
+ void addCommand(int header, int headerLength, long body, int bodyLength) {
+ addByte(header, headerLength) ;
+ addLong(lastBody, lastBodyLength) ;
+
+ lastBody = body ;
+ lastBodyLength = bodyLength ;
+ }
+
+ //
+ // Add the rightmost bitCount bits of b to the end of the command stream.
+ //
+ private void addByte(int b, int bitCount) {
+ int bitsEmpty = 8 - bitOffset ;
+ b &= (int)CompressionStreamElement.lengthMask[bitCount] ;
+
+ if (bitCount <= bitsEmpty) {
+ bytes[byteOffset] |= (b << (bitsEmpty - bitCount)) ;
+ bitOffset += bitCount ;
+ return ;
+ }
+
+ if (bytes.length == byteOffset + 1) {
+ byte newBytes[] = new byte[bytes.length * 2] ;
+ System.arraycopy(bytes, 0, newBytes, 0, bytes.length) ;
+ bytes = newBytes ;
+ }
+
+ bitOffset = bitCount - bitsEmpty ;
+ bytes[byteOffset] |= (b >>> bitOffset) ;
+
+ byteOffset++ ;
+ bytes[byteOffset] = (byte)(b << (8 - bitOffset)) ;
+ }
+
+ //
+ // Add the rightmost bitCount bits of l to the end of the command stream.
+ //
+ private void addLong(long l, int bitCount) {
+ int byteCount = bitCount / 8 ;
+ int excessBits = bitCount - byteCount * 8 ;
+
+ if (excessBits > 0)
+ addByte((int)(l >>> (byteCount * 8)), excessBits) ;
+
+ while (byteCount > 0) {
+ addByte((int)((l >>> ((byteCount - 1) * 8)) & 0xff), 8) ;
+ byteCount-- ;
+ }
+ }
+
+ /**
+ * Add a no-op and the last command body. Pad out with additional no-ops
+ * to a 64-bit boundary if necessary. A call to this method is required
+ * in order to create a valid compression command stream.
+ */
+ void end() {
+ int excessBytes, padBits ;
+
+ // Add the 1st no-op and the last body.
+ addByte(V_NO_OP, 8) ;
+ addLong(lastBody, lastBodyLength) ;
+
+ excessBytes = (byteOffset + 1) % 8 ;
+ if (excessBytes == 0 && bitOffset == 8)
+ // No padding necessary.
+ return ;
+
+ // Need to add padding with a 2nd no-op.
+ addByte(V_NO_OP, 8) ;
+ excessBytes = (byteOffset + 1) % 8 ;
+
+ if (excessBytes == 0)
+ padBits = 8 - bitOffset ;
+ else {
+ int fillBytes = 8 - excessBytes ;
+ padBits = (8 * fillBytes) + (8 - bitOffset) ;
+ }
+
+ // The minimum length for a no-op command body is 5 bits.
+ if (padBits < 5)
+ // Have to cross the next 64-bit boundary.
+ padBits += 64 ;
+
+ // The maximum length of a no-op body is a 5-bit length + 31 bits of
+ // fill for a total of 36.
+ if (padBits < 37) {
+ // Pad with the body of the 1st no-op.
+ addLong((padBits - 5) << (padBits - 5), padBits) ;
+ return ;
+ }
+
+ // The number of bits to pad at this point is [37..68]. Knock off 24
+ // bits with the body of the 1st no-op to reduce the number of pad
+ // bits to [13..44], which can be filled with 1 more no-op.
+ addLong(19 << 19, 24) ;
+ padBits -= 24 ;
+
+ // Add a 3rd no-op.
+ addByte(V_NO_OP, 8) ;
+ padBits -= 8 ;
+
+ // Complete padding with the body of the 2nd no-op.
+ addLong((padBits - 5) << (padBits - 5), padBits) ;
+ }
+
+ /**
+ * Get the number of bytes in the compression command stream.
+ *
+ * @return size of compressed data in bytes
+ */
+ int getByteCount() {
+ if (byteOffset + bitOffset == 0)
+ return 0 ;
+ else
+ return byteOffset + 1 ;
+ }
+
+ /**
+ * Get the bytes composing the compression command stream.
+ *
+ * @return reference to array of bytes containing the compressed data
+ */
+ byte[] getBytes() {
+ return bytes ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressedGeometryData.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressedGeometryData.java
new file mode 100644
index 0000000..1e0fa09
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressedGeometryData.java
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.J3DBuffer;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.vecmath.Point3d;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+/**
+ * The compressed geometry object is used to store geometry in a
+ * compressed format. Using compressed geometry may increase the speed
+ * objects can be sent over the network. Note that the geometry will
+ * be decompressed in memory, so the application will not see any
+ * memory savings.
+ *
+ * Compressed geometry may be passed to this CompressedGeometryData object
+ * in one of two ways: by copying the data into this object using the
+ * existing constructor, or by passing a reference to the data.
+ *
+ *
+ * All instance data is declared public and no get or set methods are
+ * provided.
+ *
+ * @since Java 3D 1.5
+ */
+ public static class Header extends Object {
+
+ /**
+ * bufferType: compressed geometry is made up of individual points.
+ */
+ public static final int POINT_BUFFER = 0;
+
+ /**
+ * bufferType: compressed geometry is made up of line segments.
+ */
+ public static final int LINE_BUFFER = 1;
+
+ /**
+ * bufferType: compressed geometry is made up of triangles.
+ */
+ public static final int TRIANGLE_BUFFER = 2;
+
+ // Valid values for the bufferDataPresent field.
+
+ /**
+ * bufferDataPresent: bit indicating that normal information is
+ * bundled with the vertices in the compressed geometry buffer.
+ */
+ public static final int NORMAL_IN_BUFFER = 1;
+
+ /**
+ * bufferDataPresent: bit indicating that RGB color information is
+ * bundled with the vertices in the compressed geometry buffer.
+ */
+ public static final int COLOR_IN_BUFFER = 2;
+
+ /**
+ * bufferDataPresent: bit indicating that alpha information is
+ * bundled with the vertices in the compressed geometry buffer.
+ */
+ public static final int ALPHA_IN_BUFFER = 4;
+
+ /**
+ * The major version number for the compressed geometry format that
+ * was used to compress the geometry.
+ * If the version number of compressed geometry is incompatible
+ * with the supported version of compressed geometry in the
+ * current version of Java 3D, the compressed geometry obejct will
+ * not be rendered.
+ *
+ * @see Canvas3D#queryProperties
+ */
+ public int majorVersionNumber;
+
+ /**
+ * The minor version number for the compressed geometry format that
+ * was used to compress the geometry.
+ * If the version number of compressed geometry is incompatible
+ * with the supported version of compressed geometry in the
+ * current version of Java 3D, the compressed geometry obejct will
+ * not be rendered.
+ *
+ * @see Canvas3D#queryProperties
+ */
+ public int minorVersionNumber;
+
+ /**
+ * The minor-minor version number for the compressed geometry format
+ * that was used to compress the geometry.
+ * If the version number of compressed geometry is incompatible
+ * with the supported version of compressed geometry in the
+ * current version of Java 3D, the compressed geometry obejct will
+ * not be rendered.
+ *
+ * @see Canvas3D#queryProperties
+ */
+ public int minorMinorVersionNumber;
+
+ /**
+ * Describes the type of data in the compressed geometry buffer.
+ * Only one type may be present in any given compressed geometry
+ * buffer.
+ */
+ public int bufferType;
+
+ /**
+ * Contains bits indicating what data is bundled with the vertices in the
+ * compressed geometry buffer. If this data is not present (e.g. color)
+ * then this info will be inherited from the Appearance node.
+ */
+ public int bufferDataPresent;
+
+ /**
+ * Size of the compressed geometry in bytes.
+ */
+ public int size;
+
+ /**
+ * Offset in bytes of the start of the compressed geometry from the
+ * beginning of the compressed geometry byte array passed to the
+ * CompressedGeometryData constructor.
+ *
+ * If the CompressedGeometryData is created with reference access semantics,
+ * then this allow external compressors or file readers to embed several
+ * blocks of compressed geometry in a single large byte array, possibly
+ * interspersed with metadata that is not specific to Java 3D, without
+ * having to copy each block to a separate byte array.
+ *
+ * If the CompressedGeometryData is created with copy access semantics, then
+ *
+ *
+ * At 1 bit of quantization it is not possible to express positive
+ * absolute or delta positions.
+ */
+ int positionQuant ;
+
+ /**
+ * Current color component (R, G, B, A) quantization value. This can
+ * range from 2 to 16 bits and has a default of 9.
+ *
+ * A color component is represented with a signed fixed-point value in
+ * order to be able express negative deltas; the default of 9 bits
+ * corresponds to the 8-bit color component range of the graphics hardware
+ * commonly available. Colors must be non-negative, so the lower limit of
+ * quantization is 2 bits.
+ */
+ int colorQuant ;
+
+ /**
+ * Current normal component (U and V) quantization value. This can range
+ * from 0 to 6 bits and has a default of 6.
+ *
+ * At 0 bits of quantization normals are represented only as 6 bit
+ * sextant/octant pairs and 14 specially encoded normals (the 6 axis
+ * normals and the 8 octant midpoint normals); since U and V can only be 0
+ * at the minimum quantization, the totally number of unique normals is
+ * 12 + 14 = 26.
+ */
+ int normalQuant ;
+
+ /**
+ * Flag indicating position quantization change.
+ */
+ boolean positionQuantChanged ;
+
+ /**
+ * Flag indicating color quantization change.
+ */
+ boolean colorQuantChanged ;
+
+ /**
+ * Flag indicating normal quantization change.
+ */
+ boolean normalQuantChanged ;
+
+ /**
+ * Last quantized position.
+ */
+ int lastPosition[] = new int[3] ;
+
+ /**
+ * Last quantized color.
+ */
+ int lastColor[] = new int[4] ;
+
+ /**
+ * Last quantized normal's sextant.
+ */
+ int lastSextant ;
+
+ /**
+ * Last quantized normal's octant.
+ */
+ int lastOctant ;
+
+ /**
+ * Last quantized normal's U encoding parameter.
+ */
+ int lastU ;
+
+ /**
+ * Last quantized normal's V encoding parameter.
+ */
+ int lastV ;
+
+ /**
+ * Flag indicating last normal used a special encoding.
+ */
+ boolean lastSpecialNormal ;
+
+ /**
+ * Flag indicating the first position in this stream.
+ */
+ boolean firstPosition ;
+
+ /**
+ * Flag indicating the first color in this stream.
+ */
+ boolean firstColor ;
+
+ /**
+ * Flag indicating the first normal in this stream.
+ */
+ boolean firstNormal ;
+
+ /**
+ * The total number of bytes used to create the uncompressed geometric
+ * elements in this stream, useful for performance analysis. This
+ * excludes mesh buffer references.
+ */
+ int byteCount ;
+
+ /**
+ * The number of vertices created for this stream, excluding mesh buffer
+ * references.
+ */
+ int vertexCount ;
+
+ /**
+ * The number of mesh buffer references created for this stream.
+ */
+ int meshReferenceCount ;
+
+ /**
+ * Mesh buffer mirror used for computing deltas during quantization pass
+ * and a limited meshing algorithm for unstripped data.
+ */
+ MeshBuffer meshBuffer = new MeshBuffer() ;
+
+
+ // Collection which holds the elements of this stream.
+ private Collection stream ;
+
+ // True if preceding stream elements were colors or normals. Used to flag
+ // color and normal mesh buffer substitution when computing deltas during
+ // quantization pass.
+ private boolean lastElementColor = false ;
+ private boolean lastLastElementColor = false ;
+ private boolean lastElementNormal = false ;
+ private boolean lastLastElementNormal = false ;
+
+ // Some convenient temporary holding variables.
+ private Point3f p3f = new Point3f() ;
+ private Color3f c3f = new Color3f() ;
+ private Color4f c4f = new Color4f() ;
+ private Vector3f n3f = new Vector3f() ;
+
+
+ // Private constructor for common initializations.
+ private CompressionStream() {
+ this.stream = new LinkedList() ;
+
+ byteCount = 0 ;
+ vertexCount = 0 ;
+ meshReferenceCount = 0 ;
+
+ mcBounds[0] = new Point3d(Double.POSITIVE_INFINITY,
+ Double.POSITIVE_INFINITY,
+ Double.POSITIVE_INFINITY) ;
+ mcBounds[1] = new Point3d(Double.NEGATIVE_INFINITY,
+ Double.NEGATIVE_INFINITY,
+ Double.NEGATIVE_INFINITY) ;
+
+ qcBounds[0] = new Point3i(Integer.MAX_VALUE,
+ Integer.MAX_VALUE,
+ Integer.MAX_VALUE) ;
+ qcBounds[1] = new Point3i(Integer.MIN_VALUE,
+ Integer.MIN_VALUE,
+ Integer.MIN_VALUE) ;
+
+ /* normalized bounds computed from quantized bounds */
+ ncBounds[0] = new Point3d() ;
+ ncBounds[1] = new Point3d() ;
+ }
+
+ /**
+ * Creates a new CompressionStream for the specified geometry type and
+ * vertex format.
+ *
+ * @param streamType type of data in this stream, either
+ * CompressedGeometryData.Header.POINT_BUFFER,
+ * CompressedGeometryData.Header.LINE_BUFFER, or
+ * CompressedGeometryData.Header.TRIANGLE_BUFFER
+ * @param vertexComponents a mask indicating which components are present
+ * in each vertex, as defined by GeometryArray: COORDINATES, NORMALS, and
+ * COLOR_3 or COLOR_4.
+ * @see GeometryCompressor
+ * @see GeometryArray
+ */
+ CompressionStream(int streamType, int vertexComponents) {
+ this() ;
+ this.streamType = streamType ;
+ this.vertexComponents = getVertexComponents(vertexComponents) ;
+ }
+
+ // See what vertex geometry components are present. The byReference,
+ // interleaved, useNIOBuffer, and useCoordIndexOnly flags are not
+ // examined.
+ private int getVertexComponents(int vertexFormat) {
+ int components = 0 ;
+
+ vertexColors = vertexColor3 = vertexColor4 = vertexNormals =
+ vertexTextures = vertexTexture2 = vertexTexture3 = vertexTexture4 =
+ false ;
+
+ if ((vertexFormat & GeometryArray.NORMALS) != 0) {
+ vertexNormals = true ;
+ components &= GeometryArray.NORMALS ;
+ if (debug) System.out.println("vertexNormals") ;
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR_3) != 0) {
+ vertexColors = true ;
+
+ if ((vertexFormat & GeometryArray.COLOR_4) != 0) {
+ vertexColor4 = true ;
+ components &= GeometryArray.COLOR_4 ;
+ if (debug) System.out.println("vertexColor4") ;
+ }
+ else {
+ vertexColor3 = true ;
+ components &= GeometryArray.COLOR_3 ;
+ if (debug) System.out.println("vertexColor3") ;
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
+ vertexTextures = true ;
+ vertexTexture2 = true ;
+ components &= GeometryArray.TEXTURE_COORDINATE_2 ;
+ if (debug) System.out.println("vertexTexture2") ;
+ }
+ else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ vertexTextures = true ;
+ vertexTexture3 = true ;
+ components &= GeometryArray.TEXTURE_COORDINATE_3 ;
+ if (debug) System.out.println("vertexTexture3") ;
+ }
+ else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ vertexTextures = true ;
+ vertexTexture4 = true ;
+ components &= GeometryArray.TEXTURE_COORDINATE_4 ;
+ if (debug) System.out.println("vertexTexture4") ;
+ }
+
+ if (vertexTextures)
+ // Throw exception for now until texture is supported.
+ throw new UnsupportedOperationException
+ ("\ncompression of texture coordinates is not supported") ;
+
+ return components ;
+ }
+
+ // Get the streamType associated with a GeometryArray instance.
+ private int getStreamType(GeometryArray ga) {
+ if (ga instanceof TriangleStripArray ||
+ ga instanceof IndexedTriangleStripArray ||
+ ga instanceof TriangleFanArray ||
+ ga instanceof IndexedTriangleFanArray ||
+ ga instanceof TriangleArray ||
+ ga instanceof IndexedTriangleArray ||
+ ga instanceof QuadArray ||
+ ga instanceof IndexedQuadArray)
+
+ return CompressedGeometryData.Header.TRIANGLE_BUFFER ;
+
+ else if (ga instanceof LineArray ||
+ ga instanceof IndexedLineArray ||
+ ga instanceof LineStripArray ||
+ ga instanceof IndexedLineStripArray)
+
+ return CompressedGeometryData.Header.LINE_BUFFER ;
+
+ else
+ return CompressedGeometryData.Header.POINT_BUFFER ;
+ }
+
+ /**
+ * Iterates across all compression stream elements and applies
+ * quantization parameters, encoding consecutive vertices as delta values
+ * whenever possible. Each geometric element is mapped to a HuffmanNode
+ * object containing its resulting bit length, right shift (trailing 0
+ * count), and absolute or relative status.
+ *
+ * Positions are normalized to span a unit cube via an offset and a
+ * uniform scale factor that maps the midpoint of the object extents along
+ * each dimension to the origin, and the longest dimension of the object to
+ * the open interval (-1.0 .. +1.0). The geometric endpoints along that
+ * dimension are both one quantum away from unity; for example, at a
+ * position quantization of 6 bits, an object would be normalized so that
+ * its most negative dimension is at (-1 + 1/64) and the most positive is
+ * at (1 - 1/64).
+ *
+ * Normals are assumed to be of unit length. Color components are clamped
+ * to the [0..1) range, where the right endpoint is one quantum less
+ * than 1.0.
+ *
+ * @param huffmanTable Table which will map geometric compression stream
+ * elements to HuffmanNode objects describing each element's data
+ * representation. This table can then be processed with Huffman's
+ * algorithm to optimize the bit length of descriptor tags according to
+ * the number of geometric elements mapped to each tag.
+ */
+ void quantize(HuffmanTable huffmanTable) {
+ // Set up default initial quantization parameters. The position and
+ // color parameters specify the number of bits for each X, Y, Z, R, G,
+ // B, or A component. The normal quantization parameter specifies the
+ // number of bits for each U and V component.
+ positionQuant = 16 ;
+ colorQuant = 9 ;
+ normalQuant = 6 ;
+
+ // Compute position center and scaling for normalization to the unit
+ // cube. This is a volume bounded by the open intervals (-1..1) on
+ // each axis.
+ center[0] = (mcBounds[1].x + mcBounds[0].x) / 2.0 ;
+ center[1] = (mcBounds[1].y + mcBounds[0].y) / 2.0 ;
+ center[2] = (mcBounds[1].z + mcBounds[0].z) / 2.0 ;
+
+ double xRange = mcBounds[1].x - mcBounds[0].x ;
+ double yRange = mcBounds[1].y - mcBounds[0].y ;
+ double zRange = mcBounds[1].z - mcBounds[0].z ;
+
+ if (xRange > yRange)
+ positionRangeMaximum = xRange ;
+ else
+ positionRangeMaximum = yRange ;
+
+ if (zRange > positionRangeMaximum)
+ positionRangeMaximum = zRange ;
+
+ // Adjust the range of the unit cube to match the default
+ // quantization.
+ //
+ // This scale factor along with the center values computed above will
+ // produce 16-bit integer representations of the floating point
+ // position coordinates ranging symmetrically about 0 from -32767 to
+ // +32767. -32768 is not used and the normalized floating point
+ // position coordinates of -1.0 as well as +1.0 will not be
+ // represented.
+ //
+ // Applications which wish to seamlessly stitch together compressed
+ // objects will need to be aware that the range of normalized
+ // positions will be one quantum away from the [-1..1] endpoints of
+ // the unit cube and should adjust scale factors accordingly.
+ scale = (2.0 / positionRangeMaximum) * (32767.0 / 32768.0) ;
+
+ // Flag quantization change.
+ positionQuantChanged = colorQuantChanged = normalQuantChanged = true ;
+
+ // Flag first position, color, and normal.
+ firstPosition = firstColor = firstNormal = true ;
+
+ // Apply quantization.
+ Iterator i = stream.iterator() ;
+ while (i.hasNext()) {
+ Object o = i.next() ;
+
+ if (o instanceof CompressionStreamElement) {
+ ((CompressionStreamElement)o).quantize(this, huffmanTable) ;
+
+ // Keep track of whether last two elements were colors or
+ // normals for mesh buffer component substitution semantics.
+ lastLastElementColor = lastElementColor ;
+ lastLastElementNormal = lastElementNormal ;
+ lastElementColor = lastElementNormal = false ;
+
+ if (o instanceof CompressionStreamColor)
+ lastElementColor = true ;
+ else if (o instanceof CompressionStreamNormal)
+ lastElementNormal = true ;
+ }
+ }
+
+ // Compute the bounds in normalized coordinates.
+ ncBounds[0].x = (double)qcBounds[0].x / 32768.0 ;
+ ncBounds[0].y = (double)qcBounds[0].y / 32768.0 ;
+ ncBounds[0].z = (double)qcBounds[0].z / 32768.0 ;
+
+ ncBounds[1].x = (double)qcBounds[1].x / 32768.0 ;
+ ncBounds[1].y = (double)qcBounds[1].y / 32768.0 ;
+ ncBounds[1].z = (double)qcBounds[1].z / 32768.0 ;
+ }
+
+ /**
+ * Iterates across all compression stream elements and builds the
+ * compressed geometry command stream output.
+ *
+ * @param huffmanTable Table which maps geometric elements in this stream
+ * to tags describing the encoding parameters (length, shift, and
+ * absolute/relative status) to be used for their representations in the
+ * compressed output. All tags must be 6 bits or less in length, and the
+ * sum of the number of bits in the tag plus the number of bits in the
+ * data it describes must be at least 6 bits in length.
+ *
+ * @param outputBuffer CommandStream to use for collecting the compressed
+ * bits.
+ */
+ void outputCommands(HuffmanTable huffmanTable, CommandStream outputBuffer) {
+ //
+ // The first command output is setState to indicate what data is
+ // bundled with each vertex. Although the semantics of geometry
+ // decompression allow setState to appear anywhere in the stream, this
+ // cannot be handled by the current Java 3D software decompressor,
+ // which internally decompresses an entire compressed buffer into a
+ // single retained object sharing a single consistent vertex format.
+ // This limitation may be removed in subsequent releases of Java 3D.
+ //
+ int bnv = (vertexNormals? 1 : 0) ;
+ int bcv = ((vertexColor3 || vertexColor4)? 1 : 0) ;
+ int cap = (vertexColor4? 1 : 0) ;
+
+ int command = CommandStream.SET_STATE | bnv ;
+ long data = (bcv << 2) | (cap << 1) ;
+
+ // Output the setState command.
+ outputBuffer.addCommand(command, 8, data, 3) ;
+
+ // Output the Huffman table commands.
+ huffmanTable.outputCommands(outputBuffer) ;
+
+ // Output each compression stream element's data.
+ Iterator i = stream.iterator() ;
+ while (i.hasNext()) {
+ Object o = i.next() ;
+ if (o instanceof CompressionStreamElement)
+ ((CompressionStreamElement)o).outputCommand(huffmanTable,
+ outputBuffer) ;
+ }
+
+ // Finish the header-forwarding interleave and long-word align.
+ outputBuffer.end() ;
+ }
+
+ /**
+ * Retrieve the total size of the uncompressed geometric data in bytes,
+ * excluding mesh buffer references.
+ * @return uncompressed byte count
+ */
+ int getByteCount() {
+ return byteCount ;
+ }
+
+ /**
+ * Retrieve the the number of vertices created for this stream, excluding
+ * mesh buffer references.
+ * @return vertex count
+ */
+ int getVertexCount() {
+ return vertexCount ;
+ }
+
+ /**
+ * Retrieve the number of mesh buffer references created for this stream.
+ * @return mesh buffer reference count
+ */
+ int getMeshReferenceCount() {
+ return meshReferenceCount ;
+ }
+
+ /**
+ * Stream element that sets position quantization during quantize pass.
+ */
+ private class PositionQuant extends CompressionStreamElement {
+ int value ;
+
+ PositionQuant(int value) {
+ this.value = value ;
+ }
+
+ @Override
+ void quantize(CompressionStream s, HuffmanTable t) {
+ positionQuant = value ;
+ positionQuantChanged = true ;
+
+ // Adjust range of unit cube scaling to match quantization.
+ scale = (2.0 / positionRangeMaximum) *
+ (((double)((1 << (value-1)) - 1))/((double)(1 << (value-1)))) ;
+ }
+
+ @Override
+ public String toString() {
+ return "positionQuant: " + value ;
+ }
+ }
+
+ /**
+ * Stream element that sets normal quantization during quantize pass.
+ */
+ private class NormalQuant extends CompressionStreamElement {
+ int value ;
+
+ NormalQuant(int value) {
+ this.value = value ;
+ }
+
+ @Override
+ void quantize(CompressionStream s, HuffmanTable t) {
+ normalQuant = value ;
+ normalQuantChanged = true ;
+ }
+
+ @Override
+ public String toString() {
+ return "normalQuant: " + value ;
+ }
+ }
+
+ /**
+ * Stream element that sets color quantization during quantize pass.
+ */
+ private class ColorQuant extends CompressionStreamElement {
+ int value ;
+
+ ColorQuant(int value) {
+ this.value = value ;
+ }
+
+ @Override
+ void quantize(CompressionStream s, HuffmanTable t) {
+ colorQuant = value ;
+ colorQuantChanged = true ;
+ }
+
+ @Override
+ public String toString() {
+ return "colorQuant: " + value ;
+ }
+ }
+
+ /**
+ * Stream element that references the mesh buffer.
+ */
+ private class MeshReference extends CompressionStreamElement {
+ int stripFlag, meshIndex ;
+
+ MeshReference(int stripFlag, int meshIndex) {
+ this.stripFlag = stripFlag ;
+ this.meshIndex = meshIndex ;
+ meshReferenceCount++ ;
+ }
+
+ @Override
+ void quantize(CompressionStream s, HuffmanTable t) {
+ // Retrieve the vertex from the mesh buffer mirror and set up the
+ // data needed for the next stream element to compute its deltas.
+ CompressionStreamVertex v = meshBuffer.getVertex(meshIndex) ;
+ lastPosition[0] = v.xAbsolute ;
+ lastPosition[1] = v.yAbsolute ;
+ lastPosition[2] = v.zAbsolute ;
+
+ // Set up last color data if it exists and previous elements
+ // don't override it.
+ if (v.color != null && !lastElementColor &&
+ !(lastElementNormal && lastLastElementColor)) {
+ lastColor[0] = v.color.rAbsolute ;
+ lastColor[1] = v.color.gAbsolute ;
+ lastColor[2] = v.color.bAbsolute ;
+ lastColor[3] = v.color.aAbsolute ;
+ }
+
+ // Set up last normal data if it exists and previous element
+ // doesn't override it.
+ if (v.normal != null && !lastElementNormal &&
+ !(lastElementColor && lastLastElementNormal)) {
+ lastSextant = v.normal.sextant ;
+ lastOctant = v.normal.octant ;
+ lastU = v.normal.uAbsolute ;
+ lastV = v.normal.vAbsolute ;
+ lastSpecialNormal = v.normal.specialNormal ;
+ }
+ }
+
+ @Override
+ void outputCommand(HuffmanTable t, CommandStream outputBuffer) {
+ int command = CommandStream.MESH_B_R ;
+ long data = stripFlag & 0x1 ;
+
+ command |= (((meshIndex & 0xf) << 1) | (stripFlag >> 1)) ;
+ outputBuffer.addCommand(command, 8, data, 1) ;
+ }
+
+ @Override
+ public String toString() {
+ return
+ "meshReference: stripFlag " + stripFlag +
+ " meshIndex " + meshIndex ;
+ }
+ }
+
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, int stripFlag) {
+ stream.add(new CompressionStreamVertex(this, pos,
+ (Vector3f)null, (Color3f)null,
+ stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, Vector3f norm, int stripFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, (Color3f)null, stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, Color3f color, int stripFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, Color4f color, int stripFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, (Vector3f)null, color, stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, Vector3f norm, Color3f color,
+ int stripFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART,
+ * REPLACE_OLDEST, or REPLACE_MIDDLE
+ */
+ void addVertex(Point3f pos, Vector3f norm, Color4f color,
+ int stripFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, color, stripFlag, NO_MESH_PUSH)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, (Vector3f)null, (Color3f)null, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Vector3f norm,
+ int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, (Color3f)null, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Color3f color,
+ int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Color4f color,
+ int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, (Vector3f)null, color, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Vector3f norm, Color3f color,
+ int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, color, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param color color data
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Vector3f norm, Color4f color,
+ int stripFlag, int meshFlag) {
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, color, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Copy vertex data and add it to the end of this stream.
+ * @param pos position data
+ * @param norm normal data
+ * @param color color data, either Color3f or Color4f, determined by
+ * current vertex format
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
+ */
+ void addVertex(Point3f pos, Vector3f norm,
+ Object color, int stripFlag, int meshFlag) {
+
+ if (vertexColor3)
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, (Color3f)color, stripFlag, meshFlag)) ;
+ else
+ stream.add(new CompressionStreamVertex
+ (this, pos, norm, (Color4f)color, stripFlag, meshFlag)) ;
+ }
+
+ /**
+ * Add a mesh buffer reference to this stream.
+ * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
+ * or REPLACE_MIDDLE
+ * @param meshIndex index of vertex to retrieve from the mesh buffer
+ */
+ void addMeshReference(int stripFlag, int meshIndex) {
+ stream.add(new MeshReference(stripFlag, meshIndex)) ;
+ }
+
+ /**
+ * Copy the given color to the end of this stream and use it as a global
+ * state change that applies to all subsequent vertices.
+ */
+ void addColor(Color3f c3f) {
+ stream.add(new CompressionStreamColor(this, c3f)) ;
+ }
+
+ /**
+ * Copy the given color to the end of this stream and use it as a global
+ * state change that applies to all subsequent vertices.
+ */
+ void addColor(Color4f c4f) {
+ stream.add(new CompressionStreamColor(this, c4f)) ;
+ }
+
+ /**
+ * Copy the given normal to the end of this stream and use it as a global
+ * state change that applies to all subsequent vertices.
+ */
+ void addNormal(Vector3f n) {
+ stream.add(new CompressionStreamNormal(this, n)) ;
+ }
+
+ /**
+ * Add a new position quantization value to the end of this stream that
+ * will apply to all subsequent vertex positions.
+ *
+ * @param value number of bits to quantize each position's X, Y,
+ * and Z components, ranging from 1 to 16 with a default of 16
+ */
+ void addPositionQuantization(int value) {
+ stream.add(new PositionQuant(value)) ;
+ }
+
+ /**
+ * Add a new color quantization value to the end of this stream that will
+ * apply to all subsequent colors.
+ *
+ * @param value number of bits to quantize each color's R, G, B, and
+ * alpha components, ranging from 2 to 16 with a default of 9
+ */
+ void addColorQuantization(int value) {
+ stream.add(new ColorQuant(value)) ;
+ }
+
+ /**
+ * Add a new normal quantization value to the end of this stream that will
+ * apply to all subsequent normals. This value specifies the number of
+ * bits for each normal's U and V components.
+ *
+ * @param value number of bits for quantizing U and V, ranging from 0 to
+ * 6 with a default of 6
+ */
+ void addNormalQuantization(int value) {
+ stream.add(new NormalQuant(value)) ;
+ }
+
+ /**
+ * Interface to access GeometryArray vertex components and add them to the
+ * compression stream.
+ *
+ * A processVertex() implementation retrieves vertex components using the
+ * appropriate access semantics of a particular GeometryArray, and adds
+ * them to the compression stream.
+ *
+ * The implementation always pushes vertices into the mesh buffer unless
+ * they match ones already there; if they do, it generates mesh buffer
+ * references instead. This reduces the number of vertices when
+ * non-stripped abutting facets are added to the stream.
+ *
+ * Note: Level II geometry compression semantics allow the mesh buffer
+ * normals to be substituted with the value of an immediately
+ * preceding SetNormal command, but this is unavailable in Level I.
+ *
+ * @param index vertex offset from the beginning of its data array
+ * @param stripFlag RESTART, REPLACE_MIDDLE, or REPLACE_OLDEST
+ */
+ private interface GeometryAccessor {
+ void processVertex(int index, int stripFlag) ;
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for geometry
+ * arrays accessed with by-copy semantics.
+ */
+ private class ByCopyGeometry implements GeometryAccessor {
+ Point3f[] positions = null ;
+ Vector3f[] normals = null ;
+ Color3f[] colors3 = null ;
+ Color4f[] colors4 = null ;
+
+ ByCopyGeometry(GeometryArray ga) {
+ this(ga, ga.getInitialVertexIndex(), ga.getValidVertexCount()) ;
+ }
+
+ ByCopyGeometry(GeometryArray ga,
+ int firstVertex, int validVertexCount) {
+ int i ;
+ positions = new Point3f[validVertexCount] ;
+ for (i = 0 ; i < validVertexCount ; i++)
+ positions[i] = new Point3f() ;
+
+ ga.getCoordinates(firstVertex, positions) ;
+
+ if (vertexNormals) {
+ normals = new Vector3f[validVertexCount] ;
+ for (i = 0 ; i < validVertexCount ; i++)
+ normals[i] = new Vector3f() ;
+
+ ga.getNormals(firstVertex, normals) ;
+ }
+
+ if (vertexColor3) {
+ colors3 = new Color3f[validVertexCount] ;
+ for (i = 0 ; i < validVertexCount ; i++)
+ colors3[i] = new Color3f() ;
+
+ ga.getColors(firstVertex, colors3) ;
+ }
+ else if (vertexColor4) {
+ colors4 = new Color4f[validVertexCount] ;
+ for (i = 0 ; i < validVertexCount ; i++)
+ colors4[i] = new Color4f() ;
+
+ ga.getColors(firstVertex, colors4) ;
+ }
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ Point3f p = positions[v] ;
+ int r = meshBuffer.getMeshReference(p) ;
+
+ if ((r == meshBuffer.NOT_FOUND) ||
+ (vertexNormals && noMeshNormalSubstitution &&
+ (! normals[v].equals(meshBuffer.getNormal(r))))) {
+
+ Vector3f n = vertexNormals? normals[v] : null ;
+ Object c = vertexColor3? (Object)colors3[v] :
+ vertexColor4? (Object)colors4[v] : null ;
+
+ addVertex(p, n, c, stripFlag, MESH_PUSH) ;
+ meshBuffer.push(p, c, n) ;
+ }
+ else {
+ if (vertexNormals && !noMeshNormalSubstitution &&
+ (! normals[v].equals(meshBuffer.getNormal(r))))
+ addNormal(normals[v]) ;
+
+ if (vertexColor3 &&
+ (! colors3[v].equals(meshBuffer.getColor3(r))))
+ addColor(colors3[v]) ;
+
+ else if (vertexColor4 &&
+ (! colors4[v].equals(meshBuffer.getColor4(r))))
+ addColor(colors4[v]) ;
+
+ addMeshReference(stripFlag, r) ;
+ }
+ }
+ }
+
+ /**
+ * Class which holds index array references for a geometry array.
+ */
+ private static class IndexArrays {
+ int colorIndices[] = null ;
+ int normalIndices[] = null ;
+ int positionIndices[] = null ;
+ }
+
+ /**
+ * Retrieves index array references for the specified IndexedGeometryArray.
+ * Index arrays are copied starting from initialIndexIndex.
+ */
+ private void getIndexArrays(GeometryArray ga, IndexArrays ia) {
+ IndexedGeometryArray iga = (IndexedGeometryArray)ga ;
+
+ int initialIndexIndex = iga.getInitialIndexIndex() ;
+ int indexCount = iga.getValidIndexCount() ;
+ int vertexFormat = iga.getVertexFormat() ;
+
+ boolean useCoordIndexOnly = false ;
+ if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) {
+ if (debug) System.out.println("useCoordIndexOnly") ;
+ useCoordIndexOnly = true ;
+ }
+
+ ia.positionIndices = new int[indexCount] ;
+ iga.getCoordinateIndices(initialIndexIndex, ia.positionIndices) ;
+
+ if (vertexNormals) {
+ if (useCoordIndexOnly) {
+ ia.normalIndices = ia.positionIndices ;
+ }
+ else {
+ ia.normalIndices = new int[indexCount] ;
+ iga.getNormalIndices(initialIndexIndex, ia.normalIndices) ;
+ }
+ }
+ if (vertexColor3 || vertexColor4) {
+ if (useCoordIndexOnly) {
+ ia.colorIndices = ia.positionIndices ;
+ }
+ else {
+ ia.colorIndices = new int[indexCount] ;
+ iga.getColorIndices(initialIndexIndex, ia.colorIndices) ;
+ }
+ }
+ }
+
+ /**
+ * Class which holds indices for a specific vertex of an
+ * IndexedGeometryArray.
+ */
+ private static class VertexIndices {
+ int pi, ni, ci ;
+ }
+
+ /**
+ * Retrieves vertex indices for a specific vertex in an
+ * IndexedGeometryArray.
+ */
+ private void getVertexIndices(int v, IndexArrays ia, VertexIndices vi) {
+ vi.pi = ia.positionIndices[v] ;
+ if (vertexNormals)
+ vi.ni = ia.normalIndices[v] ;
+ if (vertexColors)
+ vi.ci = ia.colorIndices[v] ;
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for indexed
+ * geometry arrays accessed with by-copy semantics.
+ */
+ private class IndexedByCopyGeometry extends ByCopyGeometry {
+ IndexArrays ia = new IndexArrays() ;
+ VertexIndices vi = new VertexIndices() ;
+
+ IndexedByCopyGeometry(GeometryArray ga) {
+ super(ga, 0, ga.getVertexCount()) ;
+ getIndexArrays(ga, ia) ;
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ getVertexIndices(v, ia, vi) ;
+ int r = meshBuffer.getMeshReference(vi.pi) ;
+
+ if ((r == meshBuffer.NOT_FOUND) ||
+ (vertexNormals && noMeshNormalSubstitution &&
+ (vi.ni != meshBuffer.getNormalIndex(r)))) {
+
+ Point3f p = positions[vi.pi] ;
+ Vector3f n = vertexNormals? normals[vi.ni] : null ;
+ Object c = vertexColor3? (Object)colors3[vi.ci] :
+ vertexColor4? (Object)colors4[vi.ci] : null ;
+
+ addVertex(p, n, c, stripFlag, MESH_PUSH) ;
+ meshBuffer.push(vi.pi, vi.ci, vi.ni) ;
+ }
+ else {
+ if (vertexNormals && !noMeshNormalSubstitution &&
+ vi.ni != meshBuffer.getNormalIndex(r))
+ addNormal(normals[vi.ni]) ;
+
+ if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r))
+ addColor(colors3[vi.ci]) ;
+
+ else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r))
+ addColor(colors4[vi.ci]) ;
+
+ addMeshReference(stripFlag, r) ;
+ }
+ }
+ }
+
+ //
+ // NOTE: For now, copies are made of all GeometryArray vertex components
+ // even when by-reference access is available.
+ //
+ private static class VertexCopy {
+ Object c = null ;
+ Point3f p = null ;
+ Vector3f n = null ;
+ Color3f c3 = null ;
+ Color4f c4 = null ;
+ }
+
+ private void processVertexCopy(VertexCopy vc, int stripFlag) {
+ int r = meshBuffer.getMeshReference(vc.p) ;
+
+ if ((r == meshBuffer.NOT_FOUND) ||
+ (vertexNormals && noMeshNormalSubstitution &&
+ (! vc.n.equals(meshBuffer.getNormal(r))))) {
+
+ addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ;
+ meshBuffer.push(vc.p, vc.c, vc.n) ;
+ }
+ else {
+ if (vertexNormals && !noMeshNormalSubstitution &&
+ (! vc.n.equals(meshBuffer.getNormal(r))))
+ addNormal(vc.n) ;
+
+ if (vertexColor3 && (! vc.c3.equals(meshBuffer.getColor3(r))))
+ addColor(vc.c3) ;
+
+ else if (vertexColor4 && (! vc.c4.equals(meshBuffer.getColor4(r))))
+ addColor(vc.c4) ;
+
+ addMeshReference(stripFlag, r) ;
+ }
+ }
+
+ private void processIndexedVertexCopy(VertexCopy vc,
+ VertexIndices vi,
+ int stripFlag) {
+
+ int r = meshBuffer.getMeshReference(vi.pi) ;
+
+ if ((r == meshBuffer.NOT_FOUND) ||
+ (vertexNormals && noMeshNormalSubstitution &&
+ (vi.ni != meshBuffer.getNormalIndex(r)))) {
+
+ addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH) ;
+ meshBuffer.push(vi.pi, vi.ci, vi.ni) ;
+ }
+ else {
+ if (vertexNormals && !noMeshNormalSubstitution &&
+ vi.ni != meshBuffer.getNormalIndex(r))
+ addNormal(vc.n) ;
+
+ if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r))
+ addColor(vc.c3) ;
+
+ else if (vertexColor4 && vi.ci != meshBuffer.getColorIndex(r))
+ addColor(vc.c4) ;
+
+ addMeshReference(stripFlag, r) ;
+ }
+ }
+
+ /**
+ * This abstract class implements the GeometryAccessor interface for
+ * concrete subclasses which handle float and NIO interleaved geometry
+ * arrays.
+ */
+ private abstract class InterleavedGeometry implements GeometryAccessor {
+ VertexCopy vc = new VertexCopy() ;
+
+ int vstride = 0 ;
+ int coffset = 0 ;
+ int noffset = 0 ;
+ int poffset = 0 ;
+ int tstride = 0 ;
+ int tcount = 0 ;
+
+ InterleavedGeometry(GeometryArray ga) {
+ if (vertexTextures) {
+ if (vertexTexture2) tstride = 2 ;
+ else if (vertexTexture3) tstride = 3 ;
+ else if (vertexTexture4) tstride = 4 ;
+
+ tcount = ga.getTexCoordSetCount() ;
+ vstride += tcount * tstride ;
+ }
+
+ if (vertexColors) {
+ coffset = vstride ;
+ if (vertexColor3) vstride += 3 ;
+ else vstride += 4 ;
+ }
+
+ if (vertexNormals) {
+ noffset = vstride ;
+ vstride += 3 ;
+ }
+
+ poffset = vstride ;
+ vstride += 3 ;
+ }
+
+ abstract void copyVertex(int pi, int ni, int ci, VertexCopy vc) ;
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ copyVertex(v, v, v, vc) ;
+ processVertexCopy(vc, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for float
+ * interleaved geometry arrays.
+ */
+ private class InterleavedGeometryFloat extends InterleavedGeometry {
+ float[] vdata = null ;
+
+ InterleavedGeometryFloat(GeometryArray ga) {
+ super(ga) ;
+ vdata = ga.getInterleavedVertices() ;
+ }
+
+ @Override
+ void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
+ int voffset ;
+ voffset = pi * vstride ;
+ vc.p = new Point3f(vdata[voffset + poffset + 0],
+ vdata[voffset + poffset + 1],
+ vdata[voffset + poffset + 2]) ;
+
+ if (vertexNormals) {
+ voffset = ni * vstride ;
+ vc.n = new Vector3f(vdata[voffset + noffset + 0],
+ vdata[voffset + noffset + 1],
+ vdata[voffset + noffset + 2]) ;
+ }
+ if (vertexColor3) {
+ voffset = ci * vstride ;
+ vc.c3 = new Color3f(vdata[voffset + coffset + 0],
+ vdata[voffset + coffset + 1],
+ vdata[voffset + coffset + 2]) ;
+ vc.c = vc.c3 ;
+ }
+ else if (vertexColor4) {
+ voffset = ci * vstride ;
+ vc.c4 = new Color4f(vdata[voffset + coffset + 0],
+ vdata[voffset + coffset + 1],
+ vdata[voffset + coffset + 2],
+ vdata[voffset + coffset + 3]) ;
+ vc.c = vc.c4 ;
+ }
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for indexed
+ * interleaved geometry arrays.
+ */
+ private class IndexedInterleavedGeometryFloat
+ extends InterleavedGeometryFloat {
+
+ IndexArrays ia = new IndexArrays() ;
+ VertexIndices vi = new VertexIndices() ;
+
+ IndexedInterleavedGeometryFloat(GeometryArray ga) {
+ super(ga) ;
+ getIndexArrays(ga, ia) ;
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ getVertexIndices(v, ia, vi) ;
+ copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
+ processIndexedVertexCopy(vc, vi, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for
+ * interleaved NIO geometry arrays.
+ */
+ private class InterleavedGeometryNIO extends InterleavedGeometry {
+ FloatBuffer fbw = null ;
+
+ InterleavedGeometryNIO(GeometryArray ga) {
+ super(ga) ;
+ J3DBuffer buffer = ga.getInterleavedVertexBuffer() ;
+ if (BufferWrapper.getBufferType(buffer) ==
+ BufferWrapper.TYPE_FLOAT) {
+ fbw = (FloatBuffer)buffer.getBuffer();
+ }
+ else {
+ throw new IllegalArgumentException
+ ("\ninterleaved vertex buffer must be FloatBuffer") ;
+ }
+ }
+
+ @Override
+ void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
+ int voffset ;
+ voffset = pi * vstride ;
+ vc.p = new Point3f(fbw.get(voffset + poffset + 0),
+ fbw.get(voffset + poffset + 1),
+ fbw.get(voffset + poffset + 2)) ;
+
+ if (vertexNormals) {
+ voffset = ni * vstride ;
+ vc.n = new Vector3f(fbw.get(voffset + noffset + 0),
+ fbw.get(voffset + noffset + 1),
+ fbw.get(voffset + noffset + 2)) ;
+ }
+ if (vertexColor3) {
+ voffset = ci * vstride ;
+ vc.c3 = new Color3f(fbw.get(voffset + coffset + 0),
+ fbw.get(voffset + coffset + 1),
+ fbw.get(voffset + coffset + 2)) ;
+ vc.c = vc.c3 ;
+ }
+ else if (vertexColor4) {
+ voffset = ci * vstride ;
+ vc.c4 = new Color4f(fbw.get(voffset + coffset + 0),
+ fbw.get(voffset + coffset + 1),
+ fbw.get(voffset + coffset + 2),
+ fbw.get(voffset + coffset + 3)) ;
+ vc.c = vc.c4 ;
+ }
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for indexed
+ * interleaved NIO geometry arrays.
+ */
+ private class IndexedInterleavedGeometryNIO extends InterleavedGeometryNIO {
+ IndexArrays ia = new IndexArrays() ;
+ VertexIndices vi = new VertexIndices() ;
+
+ IndexedInterleavedGeometryNIO(GeometryArray ga) {
+ super(ga) ;
+ getIndexArrays(ga, ia) ;
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ getVertexIndices(v, ia, vi) ;
+ copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
+ processIndexedVertexCopy(vc, vi, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for
+ * non-interleaved geometry arrays accessed with by-reference semantics.
+ */
+ private class ByRefGeometry implements GeometryAccessor {
+ VertexCopy vc = new VertexCopy() ;
+
+ byte[] colorsB = null ;
+ float[] colorsF = null ;
+ float[] normals = null ;
+ float[] positionsF = null ;
+ double[] positionsD = null ;
+
+ int initialPositionIndex = 0 ;
+ int initialNormalIndex = 0 ;
+ int initialColorIndex = 0 ;
+
+ ByRefGeometry(GeometryArray ga) {
+ positionsF = ga.getCoordRefFloat() ;
+ if (debug && positionsF != null)
+ System.out.println("float positions") ;
+
+ positionsD = ga.getCoordRefDouble() ;
+ if (debug && positionsD != null)
+ System.out.println("double positions") ;
+
+ if (positionsF == null && positionsD == null)
+ throw new UnsupportedOperationException
+ ("\nby-reference access to Point3{d,f} arrays") ;
+
+ initialPositionIndex = ga.getInitialCoordIndex() ;
+
+ if (vertexColors) {
+ colorsB = ga.getColorRefByte() ;
+ if (debug && colorsB != null)
+ System.out.println("byte colors") ;
+
+ colorsF = ga.getColorRefFloat() ;
+ if (debug && colorsF != null)
+ System.out.println("float colors") ;
+
+ if (colorsB == null && colorsF == null)
+ throw new UnsupportedOperationException
+ ("\nby-reference access to Color{3b,3f,4b,4f} arrays") ;
+
+ initialColorIndex = ga.getInitialColorIndex() ;
+ }
+
+ if (vertexNormals) {
+ normals = ga.getNormalRefFloat() ;
+ if (debug && normals != null)
+ System.out.println("float normals") ;
+
+ if (normals == null)
+ throw new UnsupportedOperationException
+ ("\nby-reference access to Normal3f array") ;
+
+ initialNormalIndex = ga.getInitialNormalIndex() ;
+ }
+ }
+
+ void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
+ pi *= 3 ;
+ if (positionsF != null) {
+ vc.p = new Point3f(positionsF[pi + 0],
+ positionsF[pi + 1],
+ positionsF[pi + 2]) ;
+ }
+ else {
+ vc.p = new Point3f((float)positionsD[pi + 0],
+ (float)positionsD[pi + 1],
+ (float)positionsD[pi + 2]) ;
+ }
+
+ ni *= 3 ;
+ if (vertexNormals) {
+ vc.n = new Vector3f(normals[ni + 0],
+ normals[ni + 1],
+ normals[ni + 2]) ;
+ }
+
+ if (vertexColor3) {
+ ci *= 3 ;
+ if (colorsB != null) {
+ vc.c3 = new Color3f
+ ((colorsB[ci + 0] & 0xff) * ByteToFloatScale,
+ (colorsB[ci + 1] & 0xff) * ByteToFloatScale,
+ (colorsB[ci + 2] & 0xff) * ByteToFloatScale) ;
+ }
+ else {
+ vc.c3 = new Color3f(colorsF[ci + 0],
+ colorsF[ci + 1],
+ colorsF[ci + 2]) ;
+ }
+ vc.c = vc.c3 ;
+ }
+ else if (vertexColor4) {
+ ci *= 4 ;
+ if (colorsB != null) {
+ vc.c4 = new Color4f
+ ((colorsB[ci + 0] & 0xff) * ByteToFloatScale,
+ (colorsB[ci + 1] & 0xff) * ByteToFloatScale,
+ (colorsB[ci + 2] & 0xff) * ByteToFloatScale,
+ (colorsB[ci + 3] & 0xff) * ByteToFloatScale) ;
+ }
+ else {
+ vc.c4 = new Color4f(colorsF[ci + 0],
+ colorsF[ci + 1],
+ colorsF[ci + 2],
+ colorsF[ci + 3]) ;
+ }
+ vc.c = vc.c4 ;
+ }
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ copyVertex(v + initialPositionIndex,
+ v + initialNormalIndex,
+ v + initialColorIndex, vc) ;
+
+ processVertexCopy(vc, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for indexed
+ * non-interleaved geometry arrays accessed with by-reference semantics.
+ */
+ private class IndexedByRefGeometry extends ByRefGeometry {
+ IndexArrays ia = new IndexArrays() ;
+ VertexIndices vi = new VertexIndices() ;
+
+ IndexedByRefGeometry(GeometryArray ga) {
+ super(ga) ;
+ getIndexArrays(ga, ia) ;
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ getVertexIndices(v, ia, vi) ;
+ copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
+ processIndexedVertexCopy(vc, vi, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for
+ * non-interleaved geometry arrays accessed with NIO.
+ */
+ private class ByRefGeometryNIO implements GeometryAccessor {
+ VertexCopy vc = new VertexCopy() ;
+
+ ByteBuffer colorsB = null ;
+ FloatBuffer colorsF = null ;
+ FloatBuffer normals = null ;
+ FloatBuffer positionsF = null ;
+ DoubleBuffer positionsD = null ;
+
+ int initialPositionIndex = 0 ;
+ int initialNormalIndex = 0 ;
+ int initialColorIndex = 0 ;
+
+ ByRefGeometryNIO(GeometryArray ga) {
+ J3DBuffer buffer ;
+ buffer = ga.getCoordRefBuffer() ;
+ initialPositionIndex = ga.getInitialCoordIndex() ;
+
+ switch (BufferWrapper.getBufferType(buffer)) {
+ case BufferWrapper.TYPE_FLOAT:
+ positionsF = (FloatBuffer)buffer.getBuffer();
+ if (debug) System.out.println("float positions buffer") ;
+ break ;
+ case BufferWrapper.TYPE_DOUBLE:
+ positionsD = (DoubleBuffer)buffer.getBuffer();
+ if (debug) System.out.println("double positions buffer") ;
+ break ;
+ default:
+ throw new IllegalArgumentException
+ ("\nposition buffer must be FloatBuffer or DoubleBuffer") ;
+ }
+
+ if (vertexColors) {
+ buffer = ga.getColorRefBuffer() ;
+ initialColorIndex = ga.getInitialColorIndex() ;
+
+ switch (BufferWrapper.getBufferType(buffer)) {
+ case BufferWrapper.TYPE_BYTE:
+ colorsB = (ByteBuffer)buffer.getBuffer();
+ if (debug) System.out.println("byte colors buffer") ;
+ break ;
+ case BufferWrapper.TYPE_FLOAT:
+ colorsF = (FloatBuffer)buffer.getBuffer();
+ if (debug) System.out.println("float colors buffer") ;
+ break ;
+ default:
+ throw new IllegalArgumentException
+ ("\ncolor buffer must be ByteBuffer or FloatBuffer") ;
+ }
+ }
+
+ if (vertexNormals) {
+ buffer = ga.getNormalRefBuffer() ;
+ initialNormalIndex = ga.getInitialNormalIndex() ;
+
+ switch (BufferWrapper.getBufferType(buffer)) {
+ case BufferWrapper.TYPE_FLOAT:
+ normals = (FloatBuffer)buffer.getBuffer();
+ if (debug) System.out.println("float normals buffer") ;
+ break ;
+ default:
+ throw new IllegalArgumentException
+ ("\nnormal buffer must be FloatBuffer") ;
+ }
+ }
+ }
+
+ void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
+ pi *= 3 ;
+ if (positionsF != null) {
+ vc.p = new Point3f(positionsF.get(pi + 0),
+ positionsF.get(pi + 1),
+ positionsF.get(pi + 2)) ;
+ }
+ else {
+ vc.p = new Point3f((float)positionsD.get(pi + 0),
+ (float)positionsD.get(pi + 1),
+ (float)positionsD.get(pi + 2)) ;
+ }
+
+ ni *= 3 ;
+ if (vertexNormals) {
+ vc.n = new Vector3f(normals.get(ni + 0),
+ normals.get(ni + 1),
+ normals.get(ni + 2)) ;
+ }
+
+ if (vertexColor3) {
+ ci *= 3 ;
+ if (colorsB != null) {
+ vc.c3 = new Color3f
+ ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale,
+ (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale,
+ (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale) ;
+ }
+ else {
+ vc.c3 = new Color3f(colorsF.get(ci + 0),
+ colorsF.get(ci + 1),
+ colorsF.get(ci + 2)) ;
+ }
+ vc.c = vc.c3 ;
+ }
+ else if (vertexColor4) {
+ ci *= 4 ;
+ if (colorsB != null) {
+ vc.c4 = new Color4f
+ ((colorsB.get(ci + 0) & 0xff) * ByteToFloatScale,
+ (colorsB.get(ci + 1) & 0xff) * ByteToFloatScale,
+ (colorsB.get(ci + 2) & 0xff) * ByteToFloatScale,
+ (colorsB.get(ci + 3) & 0xff) * ByteToFloatScale) ;
+ }
+ else {
+ vc.c4 = new Color4f(colorsF.get(ci + 0),
+ colorsF.get(ci + 1),
+ colorsF.get(ci + 2),
+ colorsF.get(ci + 3)) ;
+ }
+ vc.c = vc.c4 ;
+ }
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ copyVertex(v + initialPositionIndex,
+ v + initialNormalIndex,
+ v + initialColorIndex, vc) ;
+
+ processVertexCopy(vc, stripFlag) ;
+ }
+ }
+
+ /**
+ * This class implements the GeometryAccessor interface for
+ * non-interleaved indexed geometry arrays accessed with NIO.
+ */
+ private class IndexedByRefGeometryNIO extends ByRefGeometryNIO {
+ IndexArrays ia = new IndexArrays() ;
+ VertexIndices vi = new VertexIndices() ;
+
+ IndexedByRefGeometryNIO(GeometryArray ga) {
+ super(ga) ;
+ getIndexArrays(ga, ia) ;
+ }
+
+ @Override
+ public void processVertex(int v, int stripFlag) {
+ getVertexIndices(v, ia, vi) ;
+ copyVertex(vi.pi, vi.ni, vi.ci, vc) ;
+ processIndexedVertexCopy(vc, vi, stripFlag) ;
+ }
+ }
+
+ /**
+ * Convert a GeometryArray to compression stream elements and add them to
+ * this stream.
+ *
+ * @param ga GeometryArray to convert
+ * @exception IllegalArgumentException if GeometryArray has a
+ * dimensionality or vertex format inconsistent with the CompressionStream
+ */
+ void addGeometryArray(GeometryArray ga) {
+ int firstVertex = 0 ;
+ int validVertexCount = 0 ;
+ int vertexFormat = ga.getVertexFormat() ;
+ GeometryAccessor geometryAccessor = null ;
+
+ if (streamType != getStreamType(ga))
+ throw new IllegalArgumentException
+ ("GeometryArray has inconsistent dimensionality") ;
+
+ if (vertexComponents != getVertexComponents(vertexFormat))
+ throw new IllegalArgumentException
+ ("GeometryArray has inconsistent vertex components") ;
+
+ // Set up for vertex data access semantics.
+ boolean NIO = (vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 ;
+ boolean byRef = (vertexFormat & GeometryArray.BY_REFERENCE) != 0 ;
+ boolean interleaved = (vertexFormat & GeometryArray.INTERLEAVED) != 0 ;
+ boolean indexedGeometry = ga instanceof IndexedGeometryArray ;
+
+ if (indexedGeometry) {
+ if (debug) System.out.println("indexed") ;
+ // Index arrays will be copied such that valid indices start at
+ // offset 0 in the copied arrays.
+ firstVertex = 0 ;
+ validVertexCount = ((IndexedGeometryArray)ga).getValidIndexCount() ;
+ }
+
+ if (!byRef) {
+ if (debug) System.out.println("by-copy") ;
+ if (indexedGeometry) {
+ geometryAccessor = new IndexedByCopyGeometry(ga) ;
+ }
+ else {
+ firstVertex = 0 ;
+ validVertexCount = ga.getValidVertexCount() ;
+ geometryAccessor = new ByCopyGeometry(ga) ;
+ }
+ }
+ else if (interleaved && NIO) {
+ if (debug) System.out.println("interleaved NIO") ;
+ if (indexedGeometry) {
+ geometryAccessor = new IndexedInterleavedGeometryNIO(ga) ;
+ }
+ else {
+ firstVertex = ga.getInitialVertexIndex() ;
+ validVertexCount = ga.getValidVertexCount() ;
+ geometryAccessor = new InterleavedGeometryNIO(ga) ;
+ }
+ }
+ else if (interleaved && !NIO) {
+ if (debug) System.out.println("interleaved") ;
+ if (indexedGeometry) {
+ geometryAccessor = new IndexedInterleavedGeometryFloat(ga) ;
+ }
+ else {
+ firstVertex = ga.getInitialVertexIndex() ;
+ validVertexCount = ga.getValidVertexCount() ;
+ geometryAccessor = new InterleavedGeometryFloat(ga) ;
+ }
+ }
+ else if (!interleaved && NIO) {
+ if (debug) System.out.println("non-interleaved NIO") ;
+ if (indexedGeometry) {
+ geometryAccessor = new IndexedByRefGeometryNIO(ga) ;
+ }
+ else {
+ firstVertex = 0 ;
+ validVertexCount = ga.getValidVertexCount() ;
+ geometryAccessor = new ByRefGeometryNIO(ga) ;
+ }
+ }
+ else if (!interleaved && !NIO) {
+ if (debug) System.out.println("non-interleaved by-ref") ;
+ if (indexedGeometry) {
+ geometryAccessor = new IndexedByRefGeometry(ga) ;
+ }
+ else {
+ firstVertex = 0 ;
+ validVertexCount = ga.getValidVertexCount() ;
+ geometryAccessor = new ByRefGeometry(ga) ;
+ }
+ }
+
+ // Set up for topology.
+ int stripCount = 0 ;
+ int stripCounts[] = null ;
+ int constantStripLength = 0 ;
+ int replaceCode = RESTART ;
+ boolean strips = false ;
+ boolean implicitStrips = false ;
+
+ if (ga instanceof TriangleStripArray ||
+ ga instanceof IndexedTriangleStripArray ||
+ ga instanceof LineStripArray ||
+ ga instanceof IndexedLineStripArray) {
+
+ strips = true ;
+ replaceCode = REPLACE_OLDEST ;
+ if (debug) System.out.println("strips") ;
+ }
+ else if (ga instanceof TriangleFanArray ||
+ ga instanceof IndexedTriangleFanArray) {
+
+ strips = true ;
+ replaceCode = REPLACE_MIDDLE ;
+ if (debug) System.out.println("fans") ;
+ }
+ else if (ga instanceof QuadArray ||
+ ga instanceof IndexedQuadArray) {
+
+ // Handled as fan arrays with 4 vertices per fan.
+ implicitStrips = true ;
+ constantStripLength = 4 ;
+ replaceCode = REPLACE_MIDDLE ;
+ if (debug) System.out.println("quads") ;
+ }
+
+ // Get strip counts.
+ if (strips) {
+ if (indexedGeometry) {
+ IndexedGeometryStripArray igsa ;
+ igsa = (IndexedGeometryStripArray)ga ;
+
+ stripCount = igsa.getNumStrips() ;
+ stripCounts = new int[stripCount] ;
+ igsa.getStripIndexCounts(stripCounts) ;
+
+ } else {
+ GeometryStripArray gsa ;
+ gsa = (GeometryStripArray)ga ;
+
+ stripCount = gsa.getNumStrips() ;
+ stripCounts = new int[stripCount] ;
+ gsa.getStripVertexCounts(stripCounts) ;
+ }
+ }
+
+ // Build the compression stream for this shape's geometry.
+ int v = firstVertex ;
+ if (strips) {
+ for (int i = 0 ; i < stripCount ; i++) {
+ geometryAccessor.processVertex(v++, RESTART) ;
+ for (int j = 1 ; j < stripCounts[i] ; j++) {
+ geometryAccessor.processVertex(v++, replaceCode) ;
+ }
+ }
+ }
+ else if (implicitStrips) {
+ while (v < firstVertex + validVertexCount) {
+ geometryAccessor.processVertex(v++, RESTART) ;
+ for (int j = 1 ; j < constantStripLength ; j++) {
+ geometryAccessor.processVertex(v++, replaceCode) ;
+ }
+ }
+ }
+ else {
+ while (v < firstVertex + validVertexCount) {
+ geometryAccessor.processVertex(v++, RESTART) ;
+ }
+ }
+ }
+
+ /**
+ * Print the stream to standard output.
+ */
+ void print() {
+ System.out.println("\nstream has " + stream.size() + " entries") ;
+ System.out.println("uncompressed size " + byteCount + " bytes") ;
+ System.out.println("upper position bound: " + mcBounds[1].toString()) ;
+ System.out.println("lower position bound: " + mcBounds[0].toString()) ;
+ System.out.println("X, Y, Z centers (" +
+ ((float)center[0]) + " " +
+ ((float)center[1]) + " " +
+ ((float)center[2]) + ")\n" +
+ "scale " + ((float)scale) + "\n") ;
+
+ Iterator i = stream.iterator() ;
+ while (i.hasNext()) {
+ System.out.println(i.next().toString() + "\n") ;
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ // //
+ // The following constructors and methods are currently the only public //
+ // members of this class. All other members are subject to revision. //
+ // //
+ ////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates a CompressionStream from an array of Shape3D scene graph
+ * objects. These Shape3D objects may only consist of a GeometryArray
+ * component and an optional Appearance component. The resulting stream
+ * may be used as input to the GeometryCompressor methods.
+ *
+ * Each Shape3D in the array must be of the same dimensionality (point,
+ * line, or surface) and have the same vertex format as the others.
+ * Texture coordinates are ignored.
+ *
+ * If a color is specified in the material attributes for a Shape3D then
+ * that color is added to the CompressionStream as the current global
+ * color. Subsequent colors as well as any colors bundled with vertices
+ * will override it. Only the material diffuse colors are used; all other
+ * appearance attributes are ignored.
+ *
+ * @param positionQuant
+ * number of bits to quantize each position's X, Y,
+ * and Z components, ranging from 1 to 16
+ *
+ * @param colorQuant
+ * number of bits to quantize each color's R, G, B, and
+ * alpha components, ranging from 2 to 16
+ *
+ * @param normalQuant
+ * number of bits for quantizing each normal's U and V components, ranging
+ * from 0 to 6
+ *
+ * @param shapes
+ * an array of Shape3D scene graph objects containing
+ * GeometryArray objects, all with the same vertex format and
+ * dimensionality
+ *
+ * @exception IllegalArgumentException if any Shape3D has an inconsistent
+ * dimensionality or vertex format, or if any Shape3D contains a geometry
+ * component that is not a GeometryArray
+ *
+ * @see Shape3D
+ * @see GeometryArray
+ * @see GeometryCompressor
+ */
+ public CompressionStream(int positionQuant, int colorQuant,
+ int normalQuant, Shape3D shapes[]) {
+ this() ;
+ if (debug) System.out.println("CompressionStream(Shape3D[]):") ;
+
+ if (shapes == null)
+ throw new IllegalArgumentException("null Shape3D array") ;
+
+ if (shapes.length == 0)
+ throw new IllegalArgumentException("zero-length Shape3D array") ;
+
+ if (shapes[0] == null)
+ throw new IllegalArgumentException("Shape3D at index 0 is null") ;
+
+ long startTime = 0 ;
+ if (benchmark) startTime = System.currentTimeMillis() ;
+
+ Geometry g = shapes[0].getGeometry() ;
+ if (! (g instanceof GeometryArray))
+ throw new IllegalArgumentException
+ ("Shape3D at index 0 is not a GeometryArray") ;
+
+ GeometryArray ga = (GeometryArray)g ;
+ this.streamType = getStreamType(ga) ;
+ this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ;
+
+ // Add global quantization parameters to the start of the stream.
+ addPositionQuantization(positionQuant) ;
+ addColorQuantization(colorQuant) ;
+ addNormalQuantization(normalQuant) ;
+
+ // Loop through all shapes.
+ for (int s = 0 ; s < shapes.length ; s++) {
+ if (debug) System.out.println("\nShape3D " + s + ":") ;
+
+ g = shapes[s].getGeometry() ;
+ if (! (g instanceof GeometryArray))
+ throw new IllegalArgumentException
+ ("Shape3D at index " + s + " is not a GeometryArray") ;
+
+ // Check for material color and add it to the stream if it exists.
+ Appearance a = shapes[s].getAppearance() ;
+ if (a != null) {
+ Material m = a.getMaterial() ;
+ if (m != null) {
+ m.getDiffuseColor(c3f) ;
+ if (vertexColor4) {
+ c4f.set(c3f.x, c3f.y, c3f.z, 1.0f) ;
+ addColor(c4f) ;
+ } else
+ addColor(c3f) ;
+ }
+ }
+
+ // Add the geometry array to the stream.
+ addGeometryArray((GeometryArray)g) ;
+ }
+
+ if (benchmark) {
+ long t = System.currentTimeMillis() - startTime ;
+ System.out.println
+ ("\nCompressionStream:\n" + shapes.length + " shapes in " +
+ (t / 1000f) + " sec") ;
+ }
+ }
+
+ /**
+ * Creates a CompressionStream from an array of Shape3D scene graph
+ * objects. These Shape3D objects may only consist of a GeometryArray
+ * component and an optional Appearance component. The resulting stream
+ * may be used as input to the GeometryCompressor methods.
+ *
+ * Each Shape3D in the array must be of the same dimensionality (point,
+ * line, or surface) and have the same vertex format as the others.
+ * Texture coordinates are ignored.
+ *
+ * If a color is specified in the material attributes for a Shape3D then
+ * that color is added to the CompressionStream as the current global
+ * color. Subsequent colors as well as any colors bundled with vertices
+ * will override it. Only the material diffuse colors are used; all other
+ * appearance attributes are ignored.
+ *
+ * Defaults of 16, 9, and 6 bits are used as the quantization values for
+ * positions, colors, and normals respectively. These are the maximum
+ * resolution values defined for positions and normals; the default of 9
+ * for color is the equivalent of the 8 bits of RGBA component resolution
+ * commonly available in graphics frame buffers.
+ *
+ * @param shapes
+ * an array of Shape3D scene graph objects containing
+ * GeometryArray objects, all with the same vertex format and
+ * dimensionality.
+ *
+ * @exception IllegalArgumentException if any Shape3D has an inconsistent
+ * dimensionality or vertex format, or if any Shape3D contains a geometry
+ * component that is not a GeometryArray
+ *
+ * @see Shape3D
+ * @see GeometryArray
+ * @see GeometryCompressor
+ */
+ public CompressionStream(Shape3D shapes[]) {
+ this(16, 9, 6, shapes) ;
+ }
+
+ /**
+ * Creates a CompressionStream from an array of GeometryInfo objects. The
+ * resulting stream may be used as input to the GeometryCompressor
+ * methods.
+ *
+ * Each GeometryInfo in the array must be of the same dimensionality
+ * (point, line, or surface) and have the same vertex format as the
+ * others. Texture coordinates are ignored.
+ *
+ * @param positionQuant
+ * number of bits to quantize each position's X, Y,
+ * and Z components, ranging from 1 to 16
+ *
+ * @param colorQuant
+ * number of bits to quantize each color's R, G, B, and
+ * alpha components, ranging from 2 to 16
+ *
+ * @param normalQuant
+ * number of bits for quantizing each normal's U and V components, ranging
+ * from 0 to 6
+ *
+ * @param geometry
+ * an array of GeometryInfo objects, all with the same
+ * vertex format and dimensionality
+ *
+ * @exception IllegalArgumentException if any GeometryInfo object has an
+ * inconsistent dimensionality or vertex format
+ *
+ * @see GeometryInfo
+ * @see GeometryCompressor
+ */
+ public CompressionStream(int positionQuant, int colorQuant,
+ int normalQuant, GeometryInfo geometry[]) {
+ this() ;
+ if (debug) System.out.println("CompressionStream(GeometryInfo[])") ;
+
+ if (geometry == null)
+ throw new IllegalArgumentException("null GeometryInfo array") ;
+
+ if (geometry.length == 0)
+ throw new IllegalArgumentException
+ ("zero-length GeometryInfo array") ;
+
+ if (geometry[0] == null)
+ throw new IllegalArgumentException
+ ("GeometryInfo at index 0 is null") ;
+
+ long startTime = 0 ;
+ if (benchmark) startTime = System.currentTimeMillis() ;
+
+ GeometryArray ga = geometry[0].getGeometryArray() ;
+ this.streamType = getStreamType(ga) ;
+ this.vertexComponents = getVertexComponents(ga.getVertexFormat()) ;
+
+ // Add global quantization parameters to the start of the stream.
+ addPositionQuantization(positionQuant) ;
+ addColorQuantization(colorQuant) ;
+ addNormalQuantization(normalQuant) ;
+
+ // Loop through all GeometryInfo objects and add them to the stream.
+ for (int i = 0 ; i < geometry.length ; i++) {
+ if (debug) System.out.println("\nGeometryInfo " + i + ":") ;
+ addGeometryArray(geometry[i].getGeometryArray()) ;
+ }
+
+ if (benchmark) {
+ long t = System.currentTimeMillis() - startTime ;
+ System.out.println
+ ("\nCompressionStream:\n" + geometry.length +
+ " GeometryInfo objects in " + (t / 1000f) + " sec") ;
+ }
+ }
+
+ /**
+ * Creates a CompressionStream from an array of GeometryInfo objects. The
+ * resulting stream may be used as input to the GeometryCompressor
+ * methods.
+ *
+ * Each GeometryInfo in the array must be of the same dimensionality
+ * (point, line, or surface) and have the same vertex format as the
+ * others. Texture coordinates are ignored.
+ *
+ * Defaults of 16, 9, and 6 bits are used as the quantization values for
+ * positions, colors, and normals respectively. These are the maximum
+ * resolution values defined for positions and normals; the default of 9
+ * for color is the equivalent of the 8 bits of RGBA component resolution
+ * commonly available in graphics frame buffers.
+ *
+ * @param geometry
+ * an array of GeometryInfo objects, all with the same
+ * vertex format and dimensionality
+ *
+ * @exception IllegalArgumentException if any GeometryInfo object has an
+ * inconsistent dimensionality or vertex format
+ *
+ * @see GeometryInfo
+ * @see GeometryCompressor
+ */
+ public CompressionStream(GeometryInfo geometry[]) {
+ this(16, 9, 6, geometry) ;
+ }
+
+ /**
+ * Get the original bounds of the coordinate data, in modeling coordinates.
+ * Coordinate data is positioned and scaled to a normalized cube after
+ * compression.
+ *
+ * @return Point3d array of length 2, where the 1st Point3d is the lower
+ * bounds and the 2nd Point3d is the upper bounds.
+ * @since Java 3D 1.3
+ */
+ public Point3d[] getModelBounds() {
+ Point3d[] bounds = new Point3d[2] ;
+ bounds[0] = new Point3d(mcBounds[0]) ;
+ bounds[1] = new Point3d(mcBounds[1]) ;
+ return bounds ;
+ }
+
+ /**
+ * Get the bounds of the compressed object in normalized coordinates.
+ * These have an maximum bounds by [-1.0 .. +1.0] across each axis.
+ *
+ * @return Point3d array of length 2, where the 1st Point3d is the lower
+ * bounds and the 2nd Point3d is the upper bounds.
+ * @since Java 3D 1.3
+ */
+ public Point3d[] getNormalizedBounds() {
+ Point3d[] bounds = new Point3d[2] ;
+ bounds[0] = new Point3d(ncBounds[0]) ;
+ bounds[1] = new Point3d(ncBounds[1]) ;
+ return bounds ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamColor.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamColor.java
new file mode 100644
index 0000000..bcdf5c9
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamColor.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4f;
+
+/**
+ * This class represents a color in a compression stream. It maintains both
+ * floating-point and quantized representations. This color may be bundled
+ * with a vertex or exist separately as a global color.
+ */
+class CompressionStreamColor extends CompressionStreamElement {
+ private int R, G, B, A ;
+ private boolean color3 ;
+ private boolean color4 ;
+ private float colorR, colorG, colorB, colorA ;
+
+ int rAbsolute, gAbsolute, bAbsolute, aAbsolute ;
+
+ /**
+ * Create a CompressionStreamColor.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param color3 floating-point representation to be encoded
+ */
+ CompressionStreamColor(CompressionStream stream, Color3f c3) {
+ this.color4 = false ;
+ this.color3 = true ;
+ colorR = c3.x ;
+ colorG = c3.y ;
+ colorB = c3.z ;
+ colorA = 0.0f ;
+ stream.byteCount += 12 ;
+ }
+
+ /**
+ * Create a CompressionStreamColor.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param color4 floating-point representation to be encoded
+ */
+ CompressionStreamColor(CompressionStream stream, Color4f c4) {
+ this.color3 = false ;
+ this.color4 = true ;
+ colorR = c4.x ;
+ colorG = c4.y ;
+ colorB = c4.z ;
+ colorA = c4.w ;
+ stream.byteCount += 16 ;
+ }
+
+ /**
+ * Quantize a floating point color to fixed point integer components of
+ * the specified number of bits. The bit length can range from a maximum
+ * of 16 to a minimum of 2 bits since negative colors are not defined.
+ *
+ * The bit length is the total number of bits in the signed version of the
+ * fixed point representation of the input color, which is assumed to
+ * be normalized into the [0..1) range. With the maximum bit length of
+ * 16, 15 bits of positive colors can be represented; a bit length of 9 is
+ * needed to get the 8 bit positive color size in common use.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param table HuffmanTable for collecting data about the quantized
+ * representation of this element
+ */
+ @Override
+ void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
+ // Clamp quantization.
+ int quant =
+ (stream.colorQuant < 2? 2 :
+ (stream.colorQuant > 16? 16 : stream.colorQuant)) ;
+
+ absolute = false ;
+ if (stream.firstColor || stream.colorQuantChanged) {
+ absolute = true ;
+ stream.lastColor[0] = 0 ;
+ stream.lastColor[1] = 0 ;
+ stream.lastColor[2] = 0 ;
+ stream.lastColor[3] = 0 ;
+ stream.firstColor = false ;
+ stream.colorQuantChanged = false ;
+ }
+
+ // Convert the floating point position to s.15 2's complement.
+ if (color3) {
+ R = (int)(colorR * 32768.0) ;
+ G = (int)(colorG * 32768.0) ;
+ B = (int)(colorB * 32768.0) ;
+ A = 0 ;
+ } else if (color4) {
+ R = (int)(colorR * 32768.0) ;
+ G = (int)(colorG * 32768.0) ;
+ B = (int)(colorB * 32768.0) ;
+ A = (int)(colorA * 32768.0) ;
+ }
+
+ // Clamp color components.
+ R = (R > 32767? 32767: (R < 0? 0: R)) ;
+ G = (G > 32767? 32767: (G < 0? 0: G)) ;
+ B = (B > 32767? 32767: (B < 0? 0: B)) ;
+ A = (A > 32767? 32767: (A < 0? 0: A)) ;
+
+ // Compute quantized values.
+ R &= quantizationMask[quant] ;
+ G &= quantizationMask[quant] ;
+ B &= quantizationMask[quant] ;
+ A &= quantizationMask[quant] ;
+
+ // Copy and retain absolute color for mesh buffer lookup.
+ rAbsolute = R ;
+ gAbsolute = G ;
+ bAbsolute = B ;
+ aAbsolute = A ;
+
+ // Compute deltas.
+ R -= stream.lastColor[0] ;
+ G -= stream.lastColor[1] ;
+ B -= stream.lastColor[2] ;
+ A -= stream.lastColor[3] ;
+
+ // Update last values.
+ stream.lastColor[0] += R ;
+ stream.lastColor[1] += G ;
+ stream.lastColor[2] += B ;
+ stream.lastColor[3] += A ;
+
+ // Compute length and shift common to all components.
+ if (color3)
+ computeLengthShift(R, G, B) ;
+
+ else if (color4)
+ computeLengthShift(R, G, B, A) ;
+
+ // 0-length components are allowed only for normals.
+ if (length == 0)
+ length = 1 ;
+
+ // Add this element to the Huffman table associated with this stream.
+ huffmanTable.addColorEntry(length, shift, absolute) ;
+ }
+
+ /**
+ * Output a setColor command.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ @Override
+ void outputCommand(HuffmanTable table, CommandStream output) {
+ outputColor(table, output, CommandStream.SET_COLOR, 8) ;
+ }
+
+ /**
+ * Output a color subcommand.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ void outputSubcommand(HuffmanTable table, CommandStream output) {
+
+ outputColor(table, output, 0, 6) ;
+ }
+
+ //
+ // Output the final compressed bits to the output command stream.
+ //
+ private void outputColor(HuffmanTable table, CommandStream output,
+ int header, int headerLength) {
+ HuffmanNode t ;
+
+ // Look up the Huffman token for this compression stream element.
+ t = table.getColorEntry(length, shift, absolute) ;
+
+ // Construct the color subcommand components. The maximum length of a
+ // color subcommand is 70 bits (a tag with a length of 6 followed by 4
+ // components of 16 bits each). The subcommand is therefore
+ // constructed initially using just the first 3 components, with the
+ // 4th component added later after the tag has been shifted into the
+ // subcommand header.
+ int componentLength = t.dataLength - t.shift ;
+ int subcommandLength = t.tagLength + (3 * componentLength) ;
+
+ R = (R >> t.shift) & (int)lengthMask[componentLength] ;
+ G = (G >> t.shift) & (int)lengthMask[componentLength] ;
+ B = (B >> t.shift) & (int)lengthMask[componentLength] ;
+
+ long colorSubcommand =
+ (((long)t.tag) << (3 * componentLength)) |
+ (((long)R) << (2 * componentLength)) |
+ (((long)G) << (1 * componentLength)) |
+ (((long)B) << (0 * componentLength)) ;
+
+ if (subcommandLength < 6) {
+ // The header will have some empty bits. The Huffman tag
+ // computation will prevent this if necessary.
+ header |= (int)(colorSubcommand << (6 - subcommandLength)) ;
+ subcommandLength = 0 ;
+ }
+ else {
+ // Move the 1st 6 bits of the subcommand into the header.
+ header |= (int)(colorSubcommand >>> (subcommandLength - 6)) ;
+ subcommandLength -= 6 ;
+ }
+
+ // Add alpha if present.
+ if (color4) {
+ A = (A >> t.shift) & (int)lengthMask[componentLength] ;
+ colorSubcommand = (colorSubcommand << componentLength) | A ;
+ subcommandLength += componentLength ;
+ }
+
+ // Add the header and body to the output buffer.
+ output.addCommand(header, headerLength,
+ colorSubcommand, subcommandLength) ;
+ }
+
+ @Override
+ public String toString() {
+ String d = absolute? "" : "delta " ;
+ String c = (colorR + " " + colorG + " " + colorB +
+ (color4? (" " + colorA): "")) ;
+
+ return
+ "color: " + c + "\n" +
+ " fixed point " + d + + R + " " + G + " " + B + "\n" +
+ " length " + length + " shift " + shift +
+ (absolute? " absolute" : " relative") ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamElement.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamElement.java
new file mode 100644
index 0000000..9f8914e
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamElement.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+/**
+ * Instances of this class are used as elements in a CompressionStream.
+ * @see CompressionStream
+ */
+abstract class CompressionStreamElement {
+ /**
+ * Bit length of quantized geometric components.
+ */
+ int length ;
+
+ /**
+ * Number of trailing zeros in quantized geometric components.
+ */
+ int shift ;
+
+ /**
+ * If false, geometric component values are represented as differences
+ * from those of the preceding element in the stream.
+ */
+ boolean absolute ;
+
+ /**
+ * Array with elements that can be used as masks to apply a quantization
+ * to the number of bits indicated by the referencing index [0..16].
+ */
+ static final int quantizationMask[] = {
+ 0xFFFF0000, 0xFFFF8000, 0xFFFFC000, 0xFFFFE000,
+ 0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00,
+ 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0,
+ 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE,
+ 0xFFFFFFFF
+ } ;
+
+ /**
+ * Array with elements that can be used as masks to retain the number of
+ * trailing bits of data indicated by the referencing index [0..64]. Used
+ * to clear the leading sign bits of fixed-point 2's complement numbers
+ * and in building the compressed output stream.
+ */
+ static final long lengthMask[] = {
+ 0x0000000000000000L, 0x0000000000000001L,
+ 0x0000000000000003L, 0x0000000000000007L,
+ 0x000000000000000FL, 0x000000000000001FL,
+ 0x000000000000003FL, 0x000000000000007FL,
+ 0x00000000000000FFL, 0x00000000000001FFL,
+ 0x00000000000003FFL, 0x00000000000007FFL,
+ 0x0000000000000FFFL, 0x0000000000001FFFL,
+ 0x0000000000003FFFL, 0x0000000000007FFFL,
+ 0x000000000000FFFFL, 0x000000000001FFFFL,
+ 0x000000000003FFFFL, 0x000000000007FFFFL,
+ 0x00000000000FFFFFL, 0x00000000001FFFFFL,
+ 0x00000000003FFFFFL, 0x00000000007FFFFFL,
+ 0x0000000000FFFFFFL, 0x0000000001FFFFFFL,
+ 0x0000000003FFFFFFL, 0x0000000007FFFFFFL,
+ 0x000000000FFFFFFFL, 0x000000001FFFFFFFL,
+ 0x000000003FFFFFFFL, 0x000000007FFFFFFFL,
+ 0x00000000FFFFFFFFL, 0x00000001FFFFFFFFL,
+ 0x00000003FFFFFFFFL, 0x00000007FFFFFFFFL,
+ 0x0000000FFFFFFFFFL, 0x0000001FFFFFFFFFL,
+ 0x0000003FFFFFFFFFL, 0x0000007FFFFFFFFFL,
+ 0x000000FFFFFFFFFFL, 0x000001FFFFFFFFFFL,
+ 0x000003FFFFFFFFFFL, 0x000007FFFFFFFFFFL,
+ 0x00000FFFFFFFFFFFL, 0x00001FFFFFFFFFFFL,
+ 0x00003FFFFFFFFFFFL, 0x00007FFFFFFFFFFFL,
+ 0x0000FFFFFFFFFFFFL, 0x0001FFFFFFFFFFFFL,
+ 0x0003FFFFFFFFFFFFL, 0x0007FFFFFFFFFFFFL,
+ 0x000FFFFFFFFFFFFFL, 0x001FFFFFFFFFFFFFL,
+ 0x003FFFFFFFFFFFFFL, 0x007FFFFFFFFFFFFFL,
+ 0x00FFFFFFFFFFFFFFL, 0x01FFFFFFFFFFFFFFL,
+ 0x03FFFFFFFFFFFFFFL, 0x07FFFFFFFFFFFFFFL,
+ 0x0FFFFFFFFFFFFFFFL, 0x1FFFFFFFFFFFFFFFL,
+ 0x3FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL,
+ 0xFFFFFFFFFFFFFFFFL
+ } ;
+
+
+ /**
+ * Computes the quantized representation of this stream element.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param table HuffmanTable for collecting data about the quantized
+ * representation of this element
+ */
+ abstract void quantize(CompressionStream stream, HuffmanTable table) ;
+
+ /**
+ * Outputs the compressed bits representing this stream element.
+ * Some instances of CompressionStreamElement don't require an
+ * implementation and will inherit the stub provided here.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ void outputCommand(HuffmanTable table, CommandStream output) {
+ }
+
+ /**
+ * Finds the minimum bits needed to represent the given 16-bit signed 2's
+ * complement integer. For positive integers, this include the first
+ * 1 starting from the left, plus a 0 sign bit; for negative integers,
+ * this includes the first 0 starting from the left, plus a 1 sign bit.
+ * 0 is a special case returning 0; however, 0-length components are valid
+ * ONLY for normals.
+ *
+ * The decompressor uses the data length to determine how many bits of
+ * sign extension to add to the data coming in from the compressed stream
+ * in order to create a 16-bit signed 2's complement integer. E.g., a data
+ * length of 12 indicates that 16-12=4 bits of sign are to be extended.
+ *
+ * @param number a signed 2's complement integer representable in 16 bits
+ * or less
+ * @return minimum number of bits to represent the number
+ */
+ private static final int getLength(int number) {
+ if (number == 0)
+ return 0 ;
+
+ else if ((number & 0x8000) > 0) {
+ // negative numbers
+ if ((number & 0x4000) == 0) return 16 ;
+ if ((number & 0x2000) == 0) return 15 ;
+ if ((number & 0x1000) == 0) return 14 ;
+ if ((number & 0x0800) == 0) return 13 ;
+ if ((number & 0x0400) == 0) return 12 ;
+ if ((number & 0x0200) == 0) return 11 ;
+ if ((number & 0x0100) == 0) return 10 ;
+ if ((number & 0x0080) == 0) return 9 ;
+ if ((number & 0x0040) == 0) return 8 ;
+ if ((number & 0x0020) == 0) return 7 ;
+ if ((number & 0x0010) == 0) return 6 ;
+ if ((number & 0x0008) == 0) return 5 ;
+ if ((number & 0x0004) == 0) return 4 ;
+ if ((number & 0x0002) == 0) return 3 ;
+ if ((number & 0x0001) == 0) return 2 ;
+
+ return 1 ;
+
+ } else {
+ // positive numbers
+ if ((number & 0x4000) > 0) return 16 ;
+ if ((number & 0x2000) > 0) return 15 ;
+ if ((number & 0x1000) > 0) return 14 ;
+ if ((number & 0x0800) > 0) return 13 ;
+ if ((number & 0x0400) > 0) return 12 ;
+ if ((number & 0x0200) > 0) return 11 ;
+ if ((number & 0x0100) > 0) return 10 ;
+ if ((number & 0x0080) > 0) return 9 ;
+ if ((number & 0x0040) > 0) return 8 ;
+ if ((number & 0x0020) > 0) return 7 ;
+ if ((number & 0x0010) > 0) return 6 ;
+ if ((number & 0x0008) > 0) return 5 ;
+ if ((number & 0x0004) > 0) return 4 ;
+ if ((number & 0x0002) > 0) return 3 ;
+
+ return 2 ;
+ }
+ }
+
+ /**
+ * Finds the rightmost 1 bit in the given 16-bit integer. This value is
+ * used by the decompressor to indicate the number of trailing zeros to be
+ * added to the end of the data coming in from the compressed stream,
+ * accomplished by left shifting the data by the indicated amount.
+ * 0 is a special case returning 0.
+ *
+ * @param number an integer representable in 16 bits or less
+ * @return number of trailing zeros
+ */
+ private static final int getShift(int number) {
+ if (number == 0) return 0 ;
+
+ if ((number & 0x0001) > 0) return 0 ;
+ if ((number & 0x0002) > 0) return 1 ;
+ if ((number & 0x0004) > 0) return 2 ;
+ if ((number & 0x0008) > 0) return 3 ;
+ if ((number & 0x0010) > 0) return 4 ;
+ if ((number & 0x0020) > 0) return 5 ;
+ if ((number & 0x0040) > 0) return 6 ;
+ if ((number & 0x0080) > 0) return 7 ;
+ if ((number & 0x0100) > 0) return 8 ;
+ if ((number & 0x0200) > 0) return 9 ;
+ if ((number & 0x0400) > 0) return 10 ;
+ if ((number & 0x0800) > 0) return 11 ;
+ if ((number & 0x1000) > 0) return 12 ;
+ if ((number & 0x2000) > 0) return 13 ;
+ if ((number & 0x4000) > 0) return 14 ;
+
+ return 15 ;
+ }
+
+ /**
+ * Computes common length and shift of 2 numbers.
+ */
+ final void computeLengthShift(int n0, int n1) {
+ int s0 = n0 & 0x8000 ;
+ int s1 = n1 & 0x8000 ;
+
+ // equal sign optimization
+ if (s0 == s1)
+ if (s0 == 0)
+ this.length = getLength(n0 | n1) ;
+ else
+ this.length = getLength(n0 & n1) ;
+ else
+ this.length = getMaximum(getLength(n0), getLength(n1)) ;
+
+ this.shift = getShift(n0 | n1) ;
+ }
+
+
+ /**
+ * Computes common length and shift of 3 numbers.
+ */
+ final void computeLengthShift(int n0, int n1, int n2) {
+ int s0 = n0 & 0x8000 ;
+ int s1 = n1 & 0x8000 ;
+ int s2 = n2 & 0x8000 ;
+
+ // equal sign optimization
+ if (s0 == s1)
+ if (s1 == s2)
+ if (s2 == 0)
+ this.length = getLength(n0 | n1 | n2) ;
+ else
+ this.length = getLength(n0 & n1 & n2) ;
+ else
+ if (s1 == 0)
+ this.length = getMaximum(getLength(n0 | n1),
+ getLength(n2)) ;
+ else
+ this.length = getMaximum(getLength(n0 & n1),
+ getLength(n2)) ;
+ else
+ if (s1 == s2)
+ if (s2 == 0)
+ this.length = getMaximum(getLength(n1 | n2),
+ getLength(n0)) ;
+ else
+ this.length = getMaximum(getLength(n1 & n2),
+ getLength(n0)) ;
+ else
+ if (s0 == 0)
+ this.length = getMaximum(getLength(n0 | n2),
+ getLength(n1)) ;
+ else
+ this.length = getMaximum(getLength(n0 & n2),
+ getLength(n1)) ;
+
+ this.shift = getShift(n0 | n1 | n2) ;
+ }
+
+
+ /**
+ * Computes common length and shift of 4 numbers.
+ */
+ final void computeLengthShift(int n0, int n1, int n2, int n3) {
+ this.length = getMaximum(getLength(n0), getLength(n1),
+ getLength(n2), getLength(n3)) ;
+
+ this.shift = getShift(n0 | n1 | n2 | n3) ;
+ }
+
+
+ /**
+ * Finds the maximum of two integers.
+ */
+ private static final int getMaximum(int x, int y) {
+ if (x > y)
+ return x ;
+ else
+ return y ;
+ }
+
+ /**
+ * Finds the maximum of three integers.
+ */
+ private static final int getMaximum(int x, int y, int z) {
+ if (x > y)
+ if (x > z)
+ return x ;
+ else
+ return z ;
+ else
+ if (y > z)
+ return y ;
+ else
+ return z ;
+ }
+
+ /**
+ * Finds the maximum of four integers.
+ */
+ private static final int getMaximum(int x, int y, int z, int w) {
+ int n0, n1 ;
+
+ if (x > y)
+ n0 = x ;
+ else
+ n0 = y ;
+
+ if (z > w)
+ n1 = z ;
+ else
+ n1 = w ;
+
+ if (n0 > n1)
+ return n0 ;
+ else
+ return n1 ;
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamNormal.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamNormal.java
new file mode 100644
index 0000000..b34e27d
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamNormal.java
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * This class represents a normal in a compression stream. It maintains both
+ * floating-point and quantized representations. This normal may be bundled
+ * with a vertex or exist separately as a global normal.
+ */
+class CompressionStreamNormal extends CompressionStreamElement {
+ private int u, v ;
+ private int specialOctant, specialSextant ;
+ private float normalX, normalY, normalZ ;
+
+ int octant, sextant ;
+ boolean specialNormal ;
+ int uAbsolute, vAbsolute ;
+
+ /**
+ * Create a CompressionStreamNormal.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param normal floating-point representation to be encoded
+ */
+ CompressionStreamNormal(CompressionStream stream, Vector3f normal) {
+ this.normalX = normal.x ;
+ this.normalY = normal.y ;
+ this.normalZ = normal.z ;
+ stream.byteCount += 12 ;
+ }
+
+ //
+ // Normal Encoding Parameterization
+ //
+ // A floating point normal is quantized to a desired number of bits by
+ // comparing it to candidate entries in a table of every possible normal
+ // at that quantization and finding the closest match. This table of
+ // normals is indexed by the following encoding:
+ //
+ // First, points on a unit radius sphere are parameterized by two angles,
+ // th and psi, using usual spherical coordinates. th is the angle about
+ // the y axis, psi is the inclination to the plane containing the point.
+ // The mapping between rectangular and spherical coordinates is:
+ //
+ // x = cos(th)*cos(psi)
+ // y = sin(psi)
+ // z = sin(th)*cos(psi)
+ //
+ // Points on sphere are folded first by octant, and then by sort order
+ // of xyz into one of six sextants. All the table encoding takes place in
+ // the positive octant, in the region bounded by the half spaces:
+ //
+ // x >= z
+ // z >= y
+ // y >= 0
+ //
+ // This triangular shaped patch runs from 0 to 45 degrees in th, and
+ // from 0 to as much as 0.615479709 (MAX_Y_ANG) in psi. The xyz bounds
+ // of the patch is:
+ //
+ // (1, 0, 0) (1/sqrt(2), 0, 1/sqrt(2)) (1/sqrt(3), 1/sqrt(3), 1/sqrt(3))
+ //
+ // When dicing this space up into discrete points, the choice for y is
+ // linear quantization in psi. This means that if the y range is to be
+ // divided up into n segments, the angle of segment j is:
+ //
+ // psi(j) = MAX_Y_ANG*(j/n)
+ //
+ // The y height of the patch (in arc length) is *not* the same as the xz
+ // dimension. However, the subdivision quantization needs to treat xz and
+ // y equally. To achieve this, the th angles are re-parameterized as
+ // reflected psi angles. That is, the i-th point's th is:
+ //
+ // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*(i/n)))
+ //
+ // To go the other direction, the angle th corresponds to the real index r
+ // (in the same 0-n range as i):
+ //
+ // r(th) = n*atan(sin(th))/MAX_Y_ANG
+ //
+ // Rounded to the nearest integer, this gives the closest integer index i
+ // to the xz angle th. Because the triangle has a straight edge on the
+ // line x=z, it is more intuitive to index the xz angles in reverse
+ // order. Thus the two equations above are replaced by:
+ //
+ // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*((n-i)/n)))
+ //
+ // r(th) = n*(1 - atan(sin(th))/MAX_Y_ANG)
+ //
+ // Each level of quantization subdivides the triangular patch twice as
+ // densely. The case in which only the three vertices of the triangle are
+ // present is the first logical stage of representation, but because of
+ // how the table is encoded the first usable case starts one level of
+ // sub-division later. This three point level has an n of 2 by the above
+ // conventions.
+ //
+ private static final int MAX_UV_BITS = 6 ;
+ private static final int MAX_UV_ENTRIES = 64 ;
+
+ private static final double cgNormals[][][][] =
+ new double[MAX_UV_BITS+1][MAX_UV_ENTRIES+1][MAX_UV_ENTRIES+1][3] ;
+
+ private static final double MAX_Y_ANG = 0.615479709 ;
+ private static final double UNITY_14 = 16384.0 ;
+
+ private static void computeNormals() {
+ int inx, iny, inz, n ;
+ double th, psi, qnx, qny, qnz ;
+
+ for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) {
+ n = 1 << quant ;
+
+ for (int j = 0 ; j <= n ; j++) {
+ for (int i = 0 ; i <= n ; i++) {
+ if (i+j > n) continue ;
+
+ psi = MAX_Y_ANG*(j/((double) n)) ;
+ th = Math.asin(Math.tan(MAX_Y_ANG*((n-i)/((double) n)))) ;
+
+ qnx = Math.cos(th)*Math.cos(psi) ;
+ qny = Math.sin(psi) ;
+ qnz = Math.sin(th)*Math.cos(psi) ;
+
+ // The normal table uses 16-bit components and must be
+ // able to represent both +1.0 and -1.0, so convert the
+ // floating point normal components to fixed point with 14
+ // fractional bits, a unity bit, and a sign bit (s1.14).
+ // Set them back to get the float equivalent.
+ qnx = qnx*UNITY_14 ; inx = (int)qnx ;
+ qnx = inx ; qnx = qnx/UNITY_14 ;
+
+ qny = qny*UNITY_14 ; iny = (int)qny ;
+ qny = iny ; qny = qny/UNITY_14 ;
+
+ qnz = qnz*UNITY_14 ; inz = (int)qnz ;
+ qnz = inz ; qnz = qnz/UNITY_14 ;
+
+ cgNormals[quant][j][i][0] = qnx ;
+ cgNormals[quant][j][i][1] = qny ;
+ cgNormals[quant][j][i][2] = qnz ;
+ }
+ }
+ }
+ }
+
+ //
+ // An inverse sine table is used for each quantization level to take the Y
+ // component of a normal (which is the sine of the inclination angle) and
+ // obtain the closest quantized Y angle.
+ //
+ // At any level of compression, there are a fixed number of different Y
+ // angles (between 0 and MAX_Y_ANG). The inverse table is built to have
+ // slightly more than twice as many entries as y angles at any particular
+ // level; this ensures that the inverse look-up will get within one angle
+ // of the right one. The size of the table should be as small as
+ // possible, but with its delta sine still smaller than the delta sine
+ // between the last two angles to be encoded.
+ //
+ // Example: the inverse sine table has a maximum angle of 0.615479709. At
+ // the maximum resolution of 6 bits there are 65 discrete angles used,
+ // but twice as many are needed for thresholding between angles, so the
+ // delta angle is 0.615479709/128. The difference then between the last
+ // two angles to be encoded is:
+ // sin(0.615479709*128.0/128.0) - sin(0.615479709*127.0/128.0) = 0.003932730
+ //
+ // Using 8 significent bits below the binary point, fixed point can
+ // represent sines in increments of 0.003906250, just slightly smaller.
+ // However, because the maximum Y angle sine is 0.577350269, only 148
+ // instead of 256 table entries are needed.
+ //
+ private static final short inverseSine[][] = new short[MAX_UV_BITS+1][] ;
+
+ // UNITY_14 * sin(MAX_Y_ANGLE)
+ private static final short MAX_SIN_14BIT = 9459 ;
+
+ private static void computeInverseSineTables() {
+ int intSin, deltaSin, intAngle ;
+ double floatSin, floatAngle ;
+ short sin14[] = new short[MAX_UV_ENTRIES+1] ;
+
+ // Build table of sines in s1.14 fixed point for each of the
+ // discrete angles used at maximum resolution.
+ for (int i = 0 ; i <= MAX_UV_ENTRIES ; i++) {
+ sin14[i] = (short)(UNITY_14*Math.sin(i*MAX_Y_ANG/MAX_UV_ENTRIES)) ;
+ }
+
+ for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) {
+ switch (quant) {
+ default:
+ case 6:
+ // Delta angle: MAX_Y_ANGLE/128.0
+ // Bits below binary point for fixed point delta sine: 8
+ // Integer delta sine: 64
+ // Inverse sine table size: 148 entries
+ deltaSin = 1 << (14 - 8) ;
+ break ;
+ case 5:
+ // Delta angle: MAX_Y_ANGLE/64.0
+ // Bits below binary point for fixed point delta sine: 7
+ // Integer delta sine: 128
+ // Inverse sine table size: 74 entries
+ deltaSin = 1 << (14 - 7) ;
+ break ;
+ case 4:
+ // Delta angle: MAX_Y_ANGLE/32.0
+ // Bits below binary point for fixed point delta sine: 6
+ // Integer delta sine: 256
+ // Inverse sine table size: 37 entries
+ deltaSin = 1 << (14 - 6) ;
+ break ;
+ case 3:
+ // Delta angle: MAX_Y_ANGLE/16.0
+ // Bits below binary point for fixed point delta sine: 5
+ // Integer delta sine: 512
+ // Inverse sine table size: 19 entries
+ deltaSin = 1 << (14 - 5) ;
+ break ;
+ case 2:
+ // Delta angle: MAX_Y_ANGLE/8.0
+ // Bits below binary point for fixed point delta sine: 4
+ // Integer delta sine: 1024
+ // Inverse sine table size: 10 entries
+ deltaSin = 1 << (14 - 4) ;
+ break ;
+ case 1:
+ // Delta angle: MAX_Y_ANGLE/4.0
+ // Bits below binary point for fixed point delta sine: 3
+ // Integer delta sine: 2048
+ // Inverse sine table size: 5 entries
+ deltaSin = 1 << (14 - 3) ;
+ break ;
+ case 0:
+ // Delta angle: MAX_Y_ANGLE/2.0
+ // Bits below binary point for fixed point delta sine: 2
+ // Integer delta sine: 4096
+ // Inverse sine table size: 3 entries
+ deltaSin = 1 << (14 - 2) ;
+ break ;
+ }
+
+ inverseSine[quant] = new short[(MAX_SIN_14BIT/deltaSin) + 1] ;
+
+ intSin = 0 ;
+ for (int i = 0 ; i < inverseSine[quant].length ; i++) {
+ // Compute float representation of integer sine with desired
+ // number of fractional bits by effectively right shifting 14.
+ floatSin = intSin/UNITY_14 ;
+
+ // Compute the angle with this sine value and quantize it.
+ floatAngle = Math.asin(floatSin) ;
+ intAngle = (int)((floatAngle/MAX_Y_ANG) * (1 << quant)) ;
+
+ // Choose the closest of the three nearest quantized values
+ // intAngle-1, intAngle, and intAngle+1.
+ if (intAngle > 0) {
+ if (Math.abs(sin14[intAngle << (6-quant)] - intSin) >
+ Math.abs(sin14[(intAngle-1) << (6-quant)] - intSin))
+ intAngle = intAngle-1 ;
+ }
+
+ if (intAngle < (1 << quant)) {
+ if (Math.abs(sin14[intAngle << (6-quant)] - intSin) >
+ Math.abs(sin14[(intAngle+1) << (6-quant)] - intSin))
+ intAngle = intAngle+1 ;
+ }
+
+ inverseSine[quant][i] = (short)intAngle ;
+ intSin += deltaSin ;
+ }
+ }
+ }
+
+ /**
+ * Compute static tables needed for normal quantization.
+ */
+ static {
+ computeNormals() ;
+ computeInverseSineTables() ;
+ }
+
+ /**
+ * Quantize the floating point normal to a 6-bit octant/sextant plus u,v
+ * components of [0..6] bits. Full resolution is 18 bits and the minimum
+ * is 6 bits.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param table HuffmanTable for collecting data about the quantized
+ * representation of this element
+ */
+ @Override
+ void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
+ double nx, ny, nz, t ;
+
+ // Clamp UV quantization.
+ int quant =
+ (stream.normalQuant < 0? 0 :
+ (stream.normalQuant > 6? 6 : stream.normalQuant)) ;
+
+ nx = normalX ;
+ ny = normalY ;
+ nz = normalZ ;
+
+ octant = 0 ;
+ sextant = 0 ;
+ u = 0 ;
+ v = 0 ;
+
+ // Normalize the fixed point normal to the positive signed octant.
+ if (nx < 0.0) {
+ octant |= 4 ;
+ nx = -nx ;
+ }
+ if (ny < 0.0) {
+ octant |= 2 ;
+ ny = -ny ;
+ }
+ if (nz < 0.0) {
+ octant |= 1 ;
+ nz = -nz ;
+ }
+
+ // Normalize the fixed point normal to the proper sextant of the octant.
+ if (nx < ny) {
+ sextant |= 1 ;
+ t = nx ;
+ nx = ny ;
+ ny = t ;
+ }
+ if (nz < ny) {
+ sextant |= 2 ;
+ t = ny ;
+ ny = nz ;
+ nz = t ;
+ }
+ if (nx < nz) {
+ sextant |= 4 ;
+ t = nx ;
+ nx = nz ;
+ nz = t ;
+ }
+
+ // Convert the floating point y component to s1.14 fixed point.
+ int yInt = (int)(ny * UNITY_14) ;
+
+ // The y component of the normal is the sine of the y angle. Quantize
+ // the y angle by using the fixed point y component as an index into
+ // the inverse sine table of the correct size for the quantization
+ // level. (12 - quant) bits of the s1.14 y normal component are
+ // rolled off with a right shift; the remaining bits then match the
+ // number of bits used to represent the delta sine of the table.
+ int yIndex = inverseSine[quant][yInt >> (12-quant)] ;
+
+ // Search the two xz rows near y for the best match.
+ int ii = 0 ;
+ int jj = 0 ;
+ int n = 1 << quant ;
+ double dot, bestDot = -1 ;
+
+ for (int j = yIndex-1 ; j < yIndex+1 && j <= n ; j++) {
+ if (j < 0)
+ continue ;
+
+ for (int i = 0 ; i <= n ; i++) {
+ if (i+j > n)
+ continue ;
+
+ dot = nx * cgNormals[quant][j][i][0] +
+ ny * cgNormals[quant][j][i][1] +
+ nz * cgNormals[quant][j][i][2] ;
+
+ if (dot > bestDot) {
+ bestDot = dot ;
+ ii = i ;
+ jj = j ;
+ }
+ }
+ }
+
+ // Convert u and v to standard grid form.
+ u = ii << (6 - quant) ;
+ v = jj << (6 - quant) ;
+
+ // Check for special normals and specially encode them.
+ specialNormal = false ;
+ if (u == 64 && v == 0) {
+ // six coordinate axes case
+ if (sextant == 0 || sextant == 2) {
+ // +/- x-axis
+ specialSextant = 0x6 ;
+ specialOctant = ((octant & 4) != 0)? 0x2 : 0 ;
+
+ } else if (sextant == 3 || sextant == 1) {
+ // +/- y-axis
+ specialSextant = 0x6 ;
+ specialOctant = 4 | (((octant & 2) != 0)? 0x2 : 0) ;
+
+ } else if (sextant == 5 || sextant == 4) {
+ // +/- z-axis
+ specialSextant = 0x7 ;
+ specialOctant = ((octant & 1) != 0)? 0x2 : 0 ;
+ }
+ specialNormal = true ;
+ u = v = 0 ;
+
+ } else if (u == 0 && v == 64) {
+ // eight mid point case
+ specialSextant = 6 | (octant >> 2) ;
+ specialOctant = ((octant & 0x3) << 1) | 1 ;
+ specialNormal = true ;
+ u = v = 0 ;
+ }
+
+ // Compute deltas if possible.
+ // Use the non-normalized ii and jj indices.
+ int du = 0 ;
+ int dv = 0 ;
+ int uv64 = 64 >> (6 - quant) ;
+
+ absolute = false ;
+ if (stream.firstNormal || stream.normalQuantChanged ||
+ stream.lastSpecialNormal || specialNormal) {
+ // The first normal by definition is absolute, and normals cannot
+ // be represented as deltas to or from special normals, nor from
+ // normals with a different quantization.
+ absolute = true ;
+ stream.firstNormal = false ;
+ stream.normalQuantChanged = false ;
+
+ } else if (stream.lastOctant == octant &&
+ stream.lastSextant == sextant) {
+ // Deltas are always allowed within the same sextant/octant.
+ du = ii - stream.lastU ;
+ dv = jj - stream.lastV ;
+
+ } else if (stream.lastOctant != octant &&
+ stream.lastSextant == sextant &&
+ (((sextant == 1 || sextant == 5) &&
+ (stream.lastOctant & 3) == (octant & 3)) ||
+ ((sextant == 0 || sextant == 4) &&
+ (stream.lastOctant & 5) == (octant & 5)) ||
+ ((sextant == 2 || sextant == 3) &&
+ (stream.lastOctant & 6) == (octant & 6)))) {
+ // If the sextants are the same, the octants can differ only when
+ // they are bordering each other on the same edge that the
+ // sextant has.
+ du = ii - stream.lastU ;
+ dv = -jj - stream.lastV ;
+
+ // Can't delta by less than -64.
+ if (dv < -uv64) absolute = true ;
+
+ // Can't delta doubly defined points.
+ if (jj == 0) absolute = true ;
+
+ } else if (stream.lastOctant == octant &&
+ stream.lastSextant != sextant &&
+ ((sextant == 0 && stream.lastSextant == 4) ||
+ (sextant == 4 && stream.lastSextant == 0) ||
+ (sextant == 1 && stream.lastSextant == 5) ||
+ (sextant == 5 && stream.lastSextant == 1) ||
+ (sextant == 2 && stream.lastSextant == 3) ||
+ (sextant == 3 && stream.lastSextant == 2))) {
+ // If the octants are the same, the sextants must border on
+ // the i side (this case) or the j side (next case).
+ du = -ii - stream.lastU ;
+ dv = jj - stream.lastV ;
+
+ // Can't delta by less than -64.
+ if (du < -uv64) absolute = true ;
+
+ // Can't delta doubly defined points.
+ if (ii == 0) absolute = true ;
+
+ } else if (stream.lastOctant == octant &&
+ stream.lastSextant != sextant &&
+ ((sextant == 0 && stream.lastSextant == 2) ||
+ (sextant == 2 && stream.lastSextant == 0) ||
+ (sextant == 1 && stream.lastSextant == 3) ||
+ (sextant == 3 && stream.lastSextant == 1) ||
+ (sextant == 4 && stream.lastSextant == 5) ||
+ (sextant == 5 && stream.lastSextant == 4))) {
+ // If the octants are the same, the sextants must border on
+ // the j side (this case) or the i side (previous case).
+ if (((ii + jj ) != uv64) && (ii != 0) && (jj != 0)) {
+ du = uv64 - ii - stream.lastU ;
+ dv = uv64 - jj - stream.lastV ;
+
+ // Can't delta by greater than +63.
+ if ((du >= uv64) || (dv >= uv64))
+ absolute = true ;
+ } else
+ // Can't delta doubly defined points.
+ absolute = true ;
+
+ } else
+ // Can't delta this normal.
+ absolute = true ;
+
+ if (absolute == false) {
+ // Convert du and dv to standard grid form.
+ u = du << (6 - quant) ;
+ v = dv << (6 - quant) ;
+ }
+
+ // Compute length and shift common to all components.
+ computeLengthShift(u, v) ;
+
+ if (absolute && length > 6) {
+ // Absolute normal u, v components are unsigned 6-bit integers, so
+ // truncate the 0 sign bit for values > 0x001f.
+ length = 6 ;
+ }
+
+ // Add this element to the Huffman table associated with this stream.
+ huffmanTable.addNormalEntry(length, shift, absolute) ;
+
+ // Save current normal as last.
+ stream.lastSextant = sextant ;
+ stream.lastOctant = octant ;
+ stream.lastU = ii ;
+ stream.lastV = jj ;
+ stream.lastSpecialNormal = specialNormal ;
+
+ // Copy and retain absolute normal for mesh buffer lookup.
+ uAbsolute = ii ;
+ vAbsolute = jj ;
+ }
+
+ /**
+ * Output a setNormal command.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ @Override
+ void outputCommand(HuffmanTable table, CommandStream output) {
+ outputNormal(table, output, CommandStream.SET_NORM, 8) ;
+ }
+
+ /**
+ * Output a normal subcommand.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ void outputSubcommand(HuffmanTable table, CommandStream output) {
+ outputNormal(table, output, 0, 6) ;
+ }
+
+ //
+ // Output the final compressed bits to the output command stream.
+ //
+ private void outputNormal(HuffmanTable table, CommandStream output,
+ int header, int headerLength) {
+
+ HuffmanNode t ;
+
+ // Look up the Huffman token for this compression stream element.
+ t = table.getNormalEntry(length, shift, absolute) ;
+
+ // Construct the normal subcommand.
+ int componentLength = t.dataLength - t.shift ;
+ int subcommandLength = 0 ;
+ long normalSubcommand = 0 ;
+
+ if (absolute) {
+ // A 3-bit sextant and a 3-bit octant are always present.
+ subcommandLength = t.tagLength + 6 ;
+
+ if (specialNormal)
+ // Use the specially-encoded sextant and octant.
+ normalSubcommand =
+ (t.tag << 6) | (specialSextant << 3) | specialOctant ;
+ else
+ // Use the general encoding rule.
+ normalSubcommand =
+ (t.tag << 6) | (sextant << 3) | octant ;
+ } else {
+ // The tag is immediately followed by the u and v delta components.
+ subcommandLength = t.tagLength ;
+ normalSubcommand = t.tag ;
+ }
+
+ // Add the u and v values to the subcommand.
+ subcommandLength += (2 * componentLength) ;
+
+ u = (u >> t.shift) & (int)lengthMask[componentLength] ;
+ v = (v >> t.shift) & (int)lengthMask[componentLength] ;
+
+ normalSubcommand =
+ (normalSubcommand << (2 * componentLength)) |
+ (u << (1 * componentLength)) |
+ (v << (0 * componentLength)) ;
+
+ if (subcommandLength < 6) {
+ // The header will have some empty bits. The Huffman tag
+ // computation will prevent this if necessary.
+ header |= (int)(normalSubcommand << (6 - subcommandLength)) ;
+ subcommandLength = 0 ;
+ }
+ else {
+ // Move the 1st 6 bits of the subcommand into the header.
+ header |= (int)(normalSubcommand >>> (subcommandLength - 6)) ;
+ subcommandLength -= 6 ;
+ }
+
+ // Add the header and body to the output buffer.
+ output.addCommand(header, headerLength,
+ normalSubcommand, subcommandLength) ;
+ }
+
+ @Override
+ public String toString() {
+ String fixed ;
+
+ if (specialNormal)
+ fixed = " special normal, sextant " + specialSextant +
+ " octant " + specialOctant ;
+
+ else if (absolute)
+ fixed = " sextant " + sextant + " octant " + octant +
+ " u " + u + " v " + v ;
+ else
+ fixed = " du " + u + " dv " + v ;
+
+ return
+ "normal: " + normalX + " " + normalY + " " + normalZ + "\n"
+ + fixed + "\n" + " length " + length + " shift " + shift +
+ (absolute? " absolute" : " relative") ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamVertex.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamVertex.java
new file mode 100644
index 0000000..5a66626
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStreamVertex.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * This class represents a vertex in a compression stream. It maintains both
+ * floating-point and quantized representations of the vertex position along
+ * with meshing and vertex replacement flags for line and surface
+ * primitives. If normals or colors are bundled with geometry vertices then
+ * instances of this class will also contain references to normal or color
+ * stream elements.
+ */
+class CompressionStreamVertex extends CompressionStreamElement {
+ private int X, Y, Z ;
+ private int meshFlag ;
+ private int stripFlag ;
+ private float floatX, floatY, floatZ ;
+
+ int xAbsolute, yAbsolute, zAbsolute ;
+ CompressionStreamColor color = null ;
+ CompressionStreamNormal normal = null ;
+
+ /**
+ * Create a CompressionStreamVertex with the given parameters.
+ *
+ * @param stream CompressionStream associated with this vertex
+ * @param p position
+ * @param n normal bundled with this vertex or null if not bundled
+ * @param c color bundled with this vertex or null if not bundled
+ * @param stripFlag CompressionStream.RESTART,
+ * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
+ * @param meshFlag CompressionStream.MESH_PUSH or
+ * CompressionStream.NO_MESH_PUSH
+ */
+ CompressionStreamVertex(CompressionStream stream,
+ Point3f p, Vector3f n, Color3f c,
+ int stripFlag, int meshFlag) {
+
+ this(stream, p, n, stripFlag, meshFlag) ;
+
+ if (stream.vertexColor3)
+ color = new CompressionStreamColor(stream, c) ;
+ }
+
+ /**
+ * Create a CompressionStreamVertex with the given parameters.
+ *
+ * @param stream CompressionStream associated with this vertex
+ * @param p position
+ * @param n normal bundled with this vertex or null if not bundled
+ * @param c color bundled with this vertex or null if not bundled
+ * @param stripFlag CompressionStream.RESTART,
+ * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
+ * @param meshFlag CompressionStream.MESH_PUSH or
+ * CompressionStream.NO_MESH_PUSH
+ */
+ CompressionStreamVertex(CompressionStream stream,
+ Point3f p, Vector3f n, Color4f c,
+ int stripFlag, int meshFlag) {
+
+ this(stream, p, n, stripFlag, meshFlag) ;
+
+ if (stream.vertexColor4)
+ color = new CompressionStreamColor(stream, c) ;
+ }
+
+ /**
+ * Create a CompressionStreamVertex with the given parameters.
+ *
+ * @param stream CompressionStream associated with this vertex
+ * @param p position
+ * @param n normal bundled with this vertex or null if not bundled
+ * @param stripFlag CompressionStream.RESTART,
+ * CompressionStream.REPLACE_OLDEST, or CompressionStream.REPLACE_MIDDLE
+ * @param meshFlag CompressionStream.MESH_PUSH or
+ * CompressionStream.NO_MESH_PUSH
+ */
+ CompressionStreamVertex(CompressionStream stream, Point3f p, Vector3f n,
+ int stripFlag, int meshFlag) {
+
+ this.stripFlag = stripFlag ;
+ this.meshFlag = meshFlag ;
+ this.floatX = p.x ;
+ this.floatY = p.y ;
+ this.floatZ = p.z ;
+
+ stream.byteCount += 12 ;
+ stream.vertexCount++ ;
+
+ if (p.x < stream.mcBounds[0].x) stream.mcBounds[0].x = p.x ;
+ if (p.y < stream.mcBounds[0].y) stream.mcBounds[0].y = p.y ;
+ if (p.z < stream.mcBounds[0].z) stream.mcBounds[0].z = p.z ;
+
+ if (p.x > stream.mcBounds[1].x) stream.mcBounds[1].x = p.x ;
+ if (p.y > stream.mcBounds[1].y) stream.mcBounds[1].y = p.y ;
+ if (p.z > stream.mcBounds[1].z) stream.mcBounds[1].z = p.z ;
+
+ if (stream.vertexNormals)
+ normal = new CompressionStreamNormal(stream, n) ;
+ }
+
+ /**
+ * Quantize the floating point position to fixed point integer components
+ * of the specified number of bits. The bit length can range from 1 to 16.
+ *
+ * @param stream CompressionStream associated with this element
+ * @param table HuffmanTable for collecting data about the quantized
+ * representation of this element
+ */
+ @Override
+ void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
+ double px, py, pz ;
+
+ // Clamp quantization.
+ int quant =
+ (stream.positionQuant < 1? 1 :
+ (stream.positionQuant > 16? 16 : stream.positionQuant)) ;
+
+ absolute = false ;
+ if (stream.firstPosition || stream.positionQuantChanged) {
+ absolute = true ;
+ stream.lastPosition[0] = 0 ;
+ stream.lastPosition[1] = 0 ;
+ stream.lastPosition[2] = 0 ;
+ stream.firstPosition = false ;
+ stream.positionQuantChanged = false ;
+ }
+
+ // Normalize position to the unit cube. This is bounded by the open
+ // intervals (-1..1) on each axis.
+ px = (floatX - stream.center[0]) * stream.scale ;
+ py = (floatY - stream.center[1]) * stream.scale ;
+ pz = (floatZ - stream.center[2]) * stream.scale ;
+
+ // Convert the floating point position to s.15 2's complement.
+ // ~1.0 -> 32767 (0x00007fff) [ ~1.0 = 32767.0/32768.0]
+ // ~-1.0 -> -32767 (0xffff8001) [~-1.0 = -32767.0/32768.0]
+ X = (int)(px * 32768.0) ;
+ Y = (int)(py * 32768.0) ;
+ Z = (int)(pz * 32768.0) ;
+
+ // Compute quantized values.
+ X &= quantizationMask[quant] ;
+ Y &= quantizationMask[quant] ;
+ Z &= quantizationMask[quant] ;
+
+ // Update quantized bounds.
+ if (X < stream.qcBounds[0].x) stream.qcBounds[0].x = X ;
+ if (Y < stream.qcBounds[0].y) stream.qcBounds[0].y = Y ;
+ if (Z < stream.qcBounds[0].z) stream.qcBounds[0].z = Z ;
+
+ if (X > stream.qcBounds[1].x) stream.qcBounds[1].x = X ;
+ if (Y > stream.qcBounds[1].y) stream.qcBounds[1].y = Y ;
+ if (Z > stream.qcBounds[1].z) stream.qcBounds[1].z = Z ;
+
+ // Copy and retain absolute position for mesh buffer lookup.
+ xAbsolute = X ;
+ yAbsolute = Y ;
+ zAbsolute = Z ;
+
+ // Compute deltas.
+ X -= stream.lastPosition[0] ;
+ Y -= stream.lastPosition[1] ;
+ Z -= stream.lastPosition[2] ;
+
+ // Update last values.
+ stream.lastPosition[0] += X ;
+ stream.lastPosition[1] += Y ;
+ stream.lastPosition[2] += Z ;
+
+ // Deltas which exceed the range of 16-bit signed 2's complement
+ // numbers are handled by sign-extension of the 16th bit in order to
+ // effect a 16-bit wrap-around.
+ X = (X << 16) >> 16 ;
+ Y = (Y << 16) >> 16 ;
+ Z = (Z << 16) >> 16 ;
+
+ // Compute length and shift common to all components.
+ computeLengthShift(X, Y, Z) ;
+
+ // 0-length components are allowed only for normals.
+ if (length == 0)
+ length = 1 ;
+
+ // Add this element to the Huffman table associated with this stream.
+ huffmanTable.addPositionEntry(length, shift, absolute) ;
+
+ // Quantize any bundled color or normal.
+ if (color != null)
+ color.quantize(stream, huffmanTable) ;
+
+ if (normal != null)
+ normal.quantize(stream, huffmanTable) ;
+
+ // Push this vertex into the mesh buffer mirror, if necessary, so it
+ // can be retrieved for computing deltas when mesh buffer references
+ // are subsequently encountered during the quantization pass.
+ if (meshFlag == stream.MESH_PUSH)
+ stream.meshBuffer.push(this) ;
+ }
+
+ /**
+ * Output the final compressed bits to the compression command stream.
+ *
+ * @param table HuffmanTable mapping quantized representations to
+ * compressed encodings
+ * @param output CommandStream for collecting compressed output
+ */
+ @Override
+ void outputCommand(HuffmanTable huffmanTable, CommandStream outputBuffer) {
+
+ HuffmanNode t ;
+ int command = CommandStream.VERTEX ;
+
+ // Look up the Huffman token for this compression stream element. The
+ // values of length and shift found there will override the
+ // corresponding fields in this element, which represent best-case
+ // compression without regard to tag length.
+ t = huffmanTable.getPositionEntry(length, shift, absolute) ;
+
+ // Construct the position subcommand.
+ int componentLength = t.dataLength - t.shift ;
+ int subcommandLength = t.tagLength + (3 * componentLength) ;
+
+ X = (X >> t.shift) & (int)lengthMask[componentLength] ;
+ Y = (Y >> t.shift) & (int)lengthMask[componentLength] ;
+ Z = (Z >> t.shift) & (int)lengthMask[componentLength] ;
+
+ long positionSubcommand =
+ (((long)t.tag) << (3 * componentLength)) |
+ (((long)X) << (2 * componentLength)) |
+ (((long)Y) << (1 * componentLength)) |
+ (((long)Z) << (0 * componentLength)) ;
+
+ if (subcommandLength < 6) {
+ // The header will have some empty bits. The Huffman tag
+ // computation will prevent this if necessary.
+ command |= (int)(positionSubcommand << (6 - subcommandLength)) ;
+ subcommandLength = 0 ;
+ }
+ else {
+ // Move the 1st 6 bits of the subcommand into the header.
+ command |= (int)(positionSubcommand >>> (subcommandLength - 6)) ;
+ subcommandLength -= 6 ;
+ }
+
+ // Construct the vertex command body.
+ long body =
+ (((long)stripFlag) << (subcommandLength + 1)) |
+ (((long)meshFlag) << (subcommandLength + 0)) |
+ (positionSubcommand & lengthMask[subcommandLength]) ;
+
+ // Add the vertex command to the output buffer.
+ outputBuffer.addCommand(command, 8, body, subcommandLength + 3) ;
+
+ // Output any normal and color subcommands.
+ if (normal != null)
+ normal.outputSubcommand(huffmanTable, outputBuffer) ;
+
+ if (color != null)
+ color.outputSubcommand(huffmanTable, outputBuffer) ;
+ }
+
+ @Override
+ public String toString() {
+ String d = absolute? "" : "delta " ;
+ String c = (color == null? "": "\n\n " + color.toString()) ;
+ String n = (normal == null? "": "\n\n " + normal.toString()) ;
+
+ return
+ "position: " + floatX + " " + floatY + " " + floatZ + "\n" +
+ "fixed point " + d + + X + " " + Y + " " + Z + "\n" +
+ "length " + length + " shift " + shift +
+ (absolute? " absolute" : " relative") + "\n" +
+ "strip flag " + stripFlag + " mesh flag " + meshFlag +
+ c + n ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeneralizedStrip.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeneralizedStrip.java
new file mode 100644
index 0000000..4e62bb3
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeneralizedStrip.java
@@ -0,0 +1,904 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+
+/**
+ * This class provides static methods to support topological
+ * transformations on generalized strips. This is used by the
+ * GeometryDecompressor. These methods only need to look at the
+ * vertex replacement flags to determine how the vertices in the strip
+ * are connected. The connections are rearranged in different ways to
+ * transform generalized strips to GeometryArray representations.
+ *
+ * @see GeneralizedStripFlags
+ * @see GeneralizedVertexList
+ * @see GeometryDecompressor
+ */
+class GeneralizedStrip {
+ private static final boolean debug = false ;
+
+ // Private convenience copies of various constants.
+ private static final int CW =
+ GeneralizedStripFlags.FRONTFACE_CW ;
+ private static final int CCW =
+ GeneralizedStripFlags.FRONTFACE_CCW ;
+ private static final int RESTART_CW =
+ GeneralizedStripFlags.RESTART_CW ;
+ private static final int RESTART_CCW =
+ GeneralizedStripFlags.RESTART_CCW ;
+ private static final int REPLACE_MIDDLE =
+ GeneralizedStripFlags.REPLACE_MIDDLE ;
+ private static final int REPLACE_OLDEST =
+ GeneralizedStripFlags.REPLACE_OLDEST ;
+
+ /**
+ * The IntList is like an ArrayList, but avoids the Integer
+ * object wrapper and accessor overhead for simple lists of ints.
+ */
+ static class IntList {
+ /**
+ * The array of ints.
+ */
+ int ints[] ;
+
+ /**
+ * The number of ints in this instance.
+ */
+ int count ;
+
+ /**
+ * Construct a new empty IntList of the given initial size.
+ * @param initialSize initial size of the backing array
+ */
+ IntList(int initialSize) {
+ ints = new int[initialSize] ;
+ count = 0 ;
+ }
+
+ /**
+ * Constructs an IntList with the given contents.
+ * @param ints the array of ints to use as the contents
+ */
+ IntList(int ints[]) {
+ this.ints = ints ;
+ this.count = ints.length ;
+ }
+
+ /**
+ * Add a new int to the end of this list.
+ * @param i the int to be appended to this list
+ */
+ void add(int i) {
+ if (count == ints.length) {
+ int newints[] = new int[2*count] ;
+ System.arraycopy(ints, 0, newints, 0, count) ;
+ ints = newints ;
+ if (debug)
+ System.out.println
+ ("GeneralizedStrip.IntList: reallocated " +
+ (2*count) + " ints") ;
+ }
+ ints[count++] = i ;
+ }
+
+ /**
+ * Trim the backing array to the current count and return the
+ * resulting backing array.
+ */
+ int[] trim() {
+ if (count != ints.length) {
+ int newints[] = new int[count] ;
+ System.arraycopy(ints, 0, newints, 0, count) ;
+ ints = newints ;
+ }
+ return ints ;
+ }
+
+ /**
+ * Fill the list with consecutive integers starting from 0.
+ */
+ void fillAscending() {
+ for (int i = 0 ; i < ints.length ; i++)
+ ints[i] = i ;
+
+ count = ints.length ;
+ }
+
+ @Override
+ public String toString() {
+ String s = new String("[") ;
+ for (int i = 0 ; i < count-1 ; i++)
+ s = s + Integer.toString(ints[i]) + ", " ;
+ return s + Integer.toString(ints[count-1]) + "]" ;
+ }
+ }
+
+ /**
+ * The StripArray class is used as the output of some conversion methods
+ * in the GeneralizedStrip class.
+ */
+ static class StripArray {
+ /**
+ * A list of indices into the vertices of the original generalized
+ * strip. It specifies the order in which vertices in the original
+ * strip should be followed to build GeometryArray objects.
+ */
+ IntList vertices ;
+
+ /**
+ * A list of strip counts.
+ */
+ IntList stripCounts ;
+
+ /**
+ * Creates a StripArray with the specified vertices and stripCounts.
+ * @param vertices IntList containing vertex indicies.
+ * @param stripCounts IntList containing strip lengths.
+ */
+ StripArray(IntList vertices, IntList stripCounts) {
+ this.vertices = vertices ;
+ this.stripCounts = stripCounts ;
+ }
+ }
+
+ /**
+ * Interprets the vertex flags associated with a class implementing
+ * GeneralizedStripFlags, constructing and returning a 2-element array of
+ * StripArray objects. The first StripArray will contain triangle strips
+ * and the second will contain triangle fans.
+ *
+ * @param vertices an object implementing GeneralizedStripFlags
+ * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
+ * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
+ * @return a 2-element array containing strips in 0 and fans in 1
+ */
+ static StripArray[] toStripsAndFans(GeneralizedStripFlags vertices,
+ int frontFace) {
+
+ int size = vertices.getFlagCount() ;
+
+ // Initialize IntLists to worst-case sizes.
+ IntList stripVerts = new IntList(size*3) ;
+ IntList fanVerts = new IntList(size*3) ;
+ IntList stripCounts = new IntList(size) ;
+ IntList fanCounts = new IntList(size) ;
+
+ toStripsAndFans(vertices, frontFace,
+ stripVerts, stripCounts, fanVerts, fanCounts) ;
+
+ // Construct the StripArray output.
+ StripArray sa[] = new StripArray[2] ;
+
+ if (stripCounts.count > 0)
+ sa[0] = new StripArray(stripVerts, stripCounts) ;
+
+ if (fanCounts.count > 0)
+ sa[1] = new StripArray(fanVerts, fanCounts) ;
+
+ return sa ;
+ }
+
+ private static void toStripsAndFans(GeneralizedStripFlags vertices,
+ int frontFace,
+ IntList stripVerts,
+ IntList stripCounts,
+ IntList fanVerts,
+ IntList fanCounts) {
+ int newFlag, curFlag, winding ;
+ int v, size, stripStart, stripLength ;
+ boolean transition = false ;
+
+ stripStart = 0 ;
+ stripLength = 3 ;
+ curFlag = vertices.getFlag(0) ;
+ winding = (curFlag == RESTART_CW ? CW : CCW) ;
+ size = vertices.getFlagCount() ;
+
+ // Vertex replace flags for the first 3 vertices are irrelevant since
+ // they can only define a single triangle. The first meaningful
+ // replace flag starts at the 4th vertex.
+ v = 3 ;
+ if (v < size)
+ curFlag = vertices.getFlag(v) ;
+
+ while (v < size) {
+ newFlag = vertices.getFlag(v) ;
+
+ if ((newFlag == curFlag) &&
+ (newFlag != RESTART_CW) && (newFlag != RESTART_CCW)) {
+ // The last flag was the same as this one, and it wasn't a
+ // restart: proceed to the next vertex.
+ stripLength++ ;
+ v++ ;
+
+ } else {
+ // Either this vertex flag changed from the last one, or
+ // the flag explicitly specifies a restart: process the
+ // last strip and start up a new one.
+ if (curFlag == REPLACE_MIDDLE)
+ addFan(fanVerts, fanCounts, stripStart, stripLength,
+ frontFace, winding, transition) ;
+ else
+ addStrip(stripVerts, stripCounts, stripStart, stripLength,
+ frontFace, winding) ;
+
+ // Restart: skip to the 4th vertex of the new strip.
+ if ((newFlag == RESTART_CW) || (newFlag == RESTART_CCW)) {
+ winding = (newFlag == RESTART_CW ? CW : CCW) ;
+ stripStart = v ;
+ stripLength = 3 ;
+ v += 3 ;
+ transition = false ;
+ if (v < size)
+ curFlag = vertices.getFlag(v) ;
+ }
+ // Strip/fan transition: decrement start of strip.
+ else {
+ if (newFlag == REPLACE_OLDEST) {
+ // Flip winding order when transitioning from fans
+ // to strips.
+ winding = (winding == CW ? CCW : CW) ;
+ stripStart = v-2 ;
+ stripLength = 3 ;
+ } else {
+ // Flip winding order when transitioning from
+ // strips to fans only if the preceding strip has
+ // an even number of vertices.
+ if ((stripLength & 0x01) == 0)
+ winding = (winding == CW ? CCW : CW) ;
+ stripStart = v-3 ;
+ stripLength = 4 ;
+ }
+ v++ ;
+ transition = true ;
+ curFlag = newFlag ;
+ }
+ }
+ }
+
+ // Finish off the last strip or fan.
+ // If v > size then the strip is degenerate.
+ if (v == size)
+ if (curFlag == REPLACE_MIDDLE)
+ addFan(fanVerts, fanCounts, stripStart, stripLength,
+ frontFace, winding, transition) ;
+ else
+ addStrip(stripVerts, stripCounts, stripStart, stripLength,
+ frontFace, winding) ;
+ else
+ throw new IllegalArgumentException
+ (J3dUtilsI18N.getString("GeneralizedStrip0")) ;
+
+ if (debug) {
+ System.out.println("GeneralizedStrip.toStripsAndFans") ;
+ if (v > size)
+ System.out.println(" ended with a degenerate triangle:" +
+ " number of vertices: " + (v-size)) ;
+
+ System.out.println("\n number of strips: " + stripCounts.count) ;
+ if (stripCounts.count > 0) {
+ System.out.println(" number of vertices: " + stripVerts.count) ;
+ System.out.println(" vertices/strip: " +
+ (float)stripVerts.count/stripCounts.count) ;
+ System.out.println(" strip counts: " + stripCounts.toString()) ;
+ // System.out.println(" indices: " + stripVerts.toString()) ;
+ }
+
+ System.out.println("\n number of fans: " + fanCounts.count) ;
+ if (fanCounts.count > 0) {
+ System.out.println(" number of vertices: " + fanVerts.count) ;
+ System.out.println(" vertices/strip: " +
+ (float)fanVerts.count/fanCounts.count) ;
+ System.out.println(" fan counts: " + fanCounts.toString()) ;
+ // System.out.println(" indices: " + fanVerts.toString()) ;
+ }
+ System.out.println("\n total vertices: " +
+ (stripVerts.count + fanVerts.count) +
+ "\n original number of vertices: " + size +
+ "\n") ;
+ }
+ }
+
+ //
+ // Java 3D specifies that the vertices of front-facing polygons
+ // have counter-clockwise (CCW) winding order when projected to
+ // the view surface. Polygons with clockwise (CW) vertex winding
+ // will be culled as back-facing by default.
+ //
+ // Generalized triangle strips can flip the orientation of their
+ // triangles with the RESTART_CW and RESTART_CCW vertex flags.
+ // Strips flagged with an orientation opposite to what has been
+ // specified as front-facing must have their windings reversed in
+ // order to have the correct face orientation when represented as
+ // GeometryArray objects.
+ //
+ private static void addStrip(IntList stripVerts,
+ IntList stripCounts,
+ int start, int length,
+ int frontFace, int winding) {
+ int vindex = start ;
+
+ if (winding == frontFace) {
+ // Maintain original order.
+ stripCounts.add(length) ;
+ while (vindex < start + length) {
+ stripVerts.add(vindex++) ;
+ }
+ } else if ((length & 0x1) == 1) {
+ // Reverse winding order if number of vertices is odd.
+ stripCounts.add(length) ;
+ vindex += length-1 ;
+ while (vindex >= start) {
+ stripVerts.add(vindex--) ;
+ }
+ } else if (length == 4) {
+ // Swap middle vertices.
+ stripCounts.add(4) ;
+ stripVerts.add(vindex) ;
+ stripVerts.add(vindex+2) ;
+ stripVerts.add(vindex+1) ;
+ stripVerts.add(vindex+3) ;
+ } else {
+ // Make the 1st triangle a singleton with reverse winding.
+ stripCounts.add(3) ;
+ stripVerts.add(vindex) ;
+ stripVerts.add(vindex+2) ;
+ stripVerts.add(vindex+1) ;
+ if (length > 3) {
+ // Copy the rest of the vertices in original order.
+ vindex++ ;
+ stripCounts.add(length-1) ;
+ while (vindex < start + length) {
+ stripVerts.add(vindex++) ;
+ }
+ }
+ }
+ }
+
+ private static void addFan(IntList fanVerts,
+ IntList fanCounts,
+ int start, int length,
+ int frontFace, int winding,
+ boolean transition) {
+ int vindex = start ;
+ fanVerts.add(vindex++) ;
+
+ if (winding == frontFace) {
+ if (transition) {
+ // Skip 1st triangle if this is the result of a transition.
+ fanCounts.add(length-1) ;
+ vindex++ ;
+ } else {
+ fanCounts.add(length) ;
+ fanVerts.add(vindex++) ;
+ }
+ while (vindex < start + length) {
+ fanVerts.add(vindex++) ;
+ }
+ } else {
+ // Reverse winding order.
+ vindex += length-2 ;
+ while (vindex > start+1) {
+ fanVerts.add(vindex--) ;
+ }
+ if (transition) {
+ // Skip 1st triangle if this is the result of a transition.
+ fanCounts.add(length-1) ;
+ } else {
+ fanCounts.add(length) ;
+ fanVerts.add(vindex) ;
+ }
+ }
+ }
+
+ /**
+ * Interprets the vertex flags associated with a class implementing
+ * GeneralizedStripFlags, constructing and returning a StripArray containing
+ * exclusively strips.
+ *
+ * @param vertices an object implementing GeneralizedStripFlags
+ * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
+ * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
+ * @return a StripArray containing the converted strips
+ */
+ static StripArray toTriangleStrips(GeneralizedStripFlags vertices,
+ int frontFace) {
+
+ int size = vertices.getFlagCount() ;
+
+ // initialize lists to worst-case sizes.
+ IntList stripVerts = new IntList(size*3) ;
+ IntList fanVerts = new IntList(size*3) ;
+ IntList stripCounts = new IntList(size) ;
+ IntList fanCounts = new IntList(size) ;
+
+ toStripsAndFans(vertices, frontFace,
+ stripVerts, stripCounts, fanVerts, fanCounts) ;
+
+ if (fanCounts.count == 0)
+ if (stripCounts.count > 0)
+ return new StripArray(stripVerts, stripCounts) ;
+ else
+ return null ;
+
+ // convert each fan to one or more strips
+ int i, v = 0 ;
+ for (i = 0 ; i < fanCounts.count ; i++) {
+ fanToStrips(v, fanCounts.ints[i], fanVerts.ints,
+ stripVerts, stripCounts, false) ;
+ v += fanCounts.ints[i] ;
+ }
+
+ // create the StripArray output
+ StripArray sa = new StripArray(stripVerts, stripCounts) ;
+
+ if (debug) {
+ System.out.println("GeneralizedStrip.toTriangleStrips" +
+ "\n number of strips: " +
+ sa.stripCounts.count) ;
+ if (sa.stripCounts.count > 0) {
+ System.out.println(" number of vertices: " +
+ sa.vertices.count +
+ "\n vertices/strip: " +
+ ((float)sa.vertices.count /
+ (float)sa.stripCounts.count)) ;
+ System.out.print(" strip counts: [") ;
+ for (i = 0 ; i < sa.stripCounts.count-1 ; i++)
+ System.out.print(sa.stripCounts.ints[i] + ", ") ;
+ System.out.println(sa.stripCounts.ints[i] + "]") ;
+ }
+ System.out.println() ;
+ }
+ return sa ;
+ }
+
+ private static void fanToStrips(int v, int length, int fans[],
+ IntList stripVerts,
+ IntList stripCounts,
+ boolean convexPlanar) {
+ if (convexPlanar) {
+ // Construct a strip by criss-crossing across the interior.
+ stripCounts.add(length) ;
+ stripVerts.add(fans[v]) ;
+
+ int j = v + 1 ;
+ int k = v + (length - 1) ;
+ while (j <= k) {
+ stripVerts.add(fans[j++]) ;
+ if (j > k) break ;
+ stripVerts.add(fans[k--]) ;
+ }
+ } else {
+ // Traverse non-convex or non-planar fan, biting off 3-triangle
+ // strips or less. First 5 vertices produce 1 strip of 3
+ // triangles, and every 4 vertices after that produce another
+ // strip of 3 triangles. Each remaining strip adds 2 vertices.
+ int fanStart = v ;
+ v++ ;
+ while (v+4 <= fanStart + length) {
+ stripVerts.add(fans[v]) ;
+ stripVerts.add(fans[v+1]) ;
+ stripVerts.add(fans[fanStart]) ;
+ stripVerts.add(fans[v+2]) ;
+ stripVerts.add(fans[v+3]) ;
+ stripCounts.add(5) ;
+ v += 3 ;
+ }
+
+ // Finish off the fan.
+ if (v+1 < fanStart + length) {
+ stripVerts.add(fans[v]) ;
+ stripVerts.add(fans[v+1]) ;
+ stripVerts.add(fans[fanStart]) ;
+ v++ ;
+
+ if (v+1 < fanStart + length) {
+ stripVerts.add(fans[v+1]) ;
+ stripCounts.add(4) ;
+ }
+ else
+ stripCounts.add(3) ;
+ }
+ }
+ }
+
+ /**
+ * Interprets the vertex flags associated with a class implementing
+ * GeneralizedStripFlags, constructing and returning an array of vertex
+ * references representing the original generalized strip as individual
+ * triangles. Each sequence of three consecutive vertex references in the
+ * output defines a single triangle.
+ *
+ * @param vertices an object implementing GeneralizedStripFlags
+ * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
+ * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
+ * @return an array of indices into the original vertex array
+ */
+ static int[] toTriangles(GeneralizedStripFlags vertices, int frontFace) {
+
+ int vertexCount = 0 ;
+ StripArray sa[] = toStripsAndFans(vertices, frontFace) ;
+
+ if (sa[0] != null)
+ vertexCount = 3 * getTriangleCount(sa[0].stripCounts) ;
+ if (sa[1] != null)
+ vertexCount += 3 * getTriangleCount(sa[1].stripCounts) ;
+
+ if (debug)
+ System.out.println("GeneralizedStrip.toTriangles\n" +
+ " number of triangles: " + vertexCount/3 + "\n" +
+ " number of vertices: " + vertexCount + "\n") ;
+ int t = 0 ;
+ int triangles[] = new int[vertexCount] ;
+
+ if (sa[0] != null)
+ t = stripsToTriangles(t, triangles,
+ 0, sa[0].vertices.ints,
+ 0, sa[0].stripCounts.ints,
+ sa[0].stripCounts.count) ;
+ if (sa[1] != null)
+ t = fansToTriangles(t, triangles,
+ 0, sa[1].vertices.ints,
+ 0, sa[1].stripCounts.ints,
+ sa[1].stripCounts.count) ;
+ return triangles ;
+ }
+
+ private static int stripsToTriangles(int tstart, int tbuff[],
+ int vstart, int vertices[],
+ int stripStart, int stripCounts[],
+ int stripCount) {
+ int t = tstart ;
+ int v = vstart ;
+ for (int i = 0 ; i < stripCount ; i++) {
+ for (int j = 0 ; j < stripCounts[i+stripStart] - 2 ; j++) {
+ if ((j & 0x01) == 0) {
+ // even-numbered triangles
+ tbuff[t*3 +0] = vertices[v+0] ;
+ tbuff[t*3 +1] = vertices[v+1] ;
+ tbuff[t*3 +2] = vertices[v+2] ;
+ } else {
+ // odd-numbered triangles
+ tbuff[t*3 +0] = vertices[v+1] ;
+ tbuff[t*3 +1] = vertices[v+0] ;
+ tbuff[t*3 +2] = vertices[v+2] ;
+ }
+ t++ ; v++ ;
+ }
+ v += 2 ;
+ }
+ return t ;
+ }
+
+ private static int fansToTriangles(int tstart, int tbuff[],
+ int vstart, int vertices[],
+ int stripStart, int stripCounts[],
+ int stripCount) {
+ int t = tstart ;
+ int v = vstart ;
+ for (int i = 0 ; i < stripCount ; i++) {
+ for (int j = 0 ; j < stripCounts[i+stripStart] - 2 ; j++) {
+ tbuff[t*3 +0] = vertices[v] ;
+ tbuff[t*3 +1] = vertices[v+j+1] ;
+ tbuff[t*3 +2] = vertices[v+j+2] ;
+ t++ ;
+ }
+ v += stripCounts[i+stripStart] ;
+ }
+ return t ;
+ }
+
+ /**
+ * Interprets the vertex flags associated with a class implementing
+ * GeneralizedStripFlags, constructing and returning a 2-element array of
+ * StripArray objects. The first StripArray will contain triangle strips
+ * and the second will contain individual triangles in the vertices
+ * field. Short strips will be converted to individual triangles.
+ *
+ * @param vertices an object implementing GeneralizedStripFlags
+ * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
+ * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
+ * @param shortStripSize strips this size or less will be converted to
+ * individual triangles if there are more than maxShortStrips of them
+ * @param maxShortStrips maximum number of short strips allowed before
+ * creating individual triangles
+ * @return a 2-element array containing strips in 0 and triangles in 1
+ */
+ static StripArray[] toStripsAndTriangles(GeneralizedStripFlags vertices,
+ int frontFace, int shortStripSize,
+ int maxShortStrips) {
+ int longStripCount = 0 ;
+ int longStripVertexCount = 0 ;
+ int shortStripCount = 0 ;
+ int triangleCount = 0 ;
+
+ StripArray sa[] = new StripArray[2] ;
+ StripArray ts = toTriangleStrips(vertices, frontFace) ;
+
+ for (int i = 0 ; i < ts.stripCounts.count ; i++)
+ if (ts.stripCounts.ints[i] <= shortStripSize) {
+ shortStripCount++ ;
+ triangleCount += ts.stripCounts.ints[i] - 2 ;
+ } else {
+ longStripCount++ ;
+ longStripVertexCount += ts.stripCounts.ints[i] ;
+ }
+
+ if (debug)
+ System.out.print("GeneralizedStrip.toStripsAndTriangles\n" +
+ " short strip size: " + shortStripSize +
+ " short strips tolerated: " + maxShortStrips +
+ " number of short strips: " + shortStripCount +
+ "\n\n") ;
+
+ if (shortStripCount <= maxShortStrips) {
+ sa[0] = ts ;
+ sa[1] = null ;
+ } else {
+ int si = 0 ; int newStripVerts[] = new int[longStripVertexCount] ;
+ int ci = 0 ; int newStripCounts[] = new int[longStripCount] ;
+ int ti = 0 ; int triangles[] = new int[3*triangleCount] ;
+ int vi = 0 ;
+
+ for (int i = 0 ; i < ts.stripCounts.count ; i++) {
+ if (ts.stripCounts.ints[i] <= shortStripSize) {
+ ti = stripsToTriangles(ti, triangles,
+ vi, ts.vertices.ints,
+ i, ts.stripCounts.ints, 1) ;
+ vi += ts.stripCounts.ints[i] ;
+ } else {
+ newStripCounts[ci++] = ts.stripCounts.ints[i] ;
+ for (int j = 0 ; j < ts.stripCounts.ints[i] ; j++)
+ newStripVerts[si++] = ts.vertices.ints[vi++] ;
+ }
+ }
+
+ if (longStripCount > 0)
+ sa[0] = new StripArray(new IntList(newStripVerts),
+ new IntList(newStripCounts)) ;
+ else
+ sa[0] = null ;
+
+ sa[1] = new StripArray(new IntList(triangles), null) ;
+
+ if (debug) {
+ System.out.println(" triangles separated: " + triangleCount) ;
+ if (longStripCount > 0) {
+ System.out.println
+ (" new vertices/strip: " +
+ ((float)longStripVertexCount/(float)longStripCount)) ;
+
+ System.out.print(" long strip counts: [") ;
+ for (int i = 0 ; i < longStripCount-1 ; i++)
+ System.out.print(newStripCounts[i++] + ", ") ;
+
+ System.out.println
+ (newStripCounts[longStripCount-1] + "]\n") ;
+ }
+ }
+ }
+ return sa ;
+ }
+
+ /**
+ * Interprets the vertex flags associated with a class implementing
+ * GeneralizedStripFlags, constructing and returning a StripArray.
+ *
+ * RESTART_CW and RESTART_CCW are treated as equivalent, as are
+ * REPLACE_MIDDLE and REPLACE_OLDEST.
+ *
+ * @param vertices an object implementing GeneralizedStripFlags
+ * @return a StripArray representing an array of line strips
+ */
+ static StripArray toLineStrips(GeneralizedStripFlags vertices) {
+ int v, size, stripStart, stripLength, flag ;
+
+ stripStart = 0 ;
+ stripLength = 2 ;
+ size = vertices.getFlagCount() ;
+
+ // Initialize IntLists to worst-case sizes.
+ IntList stripVerts = new IntList(size*2) ;
+ IntList stripCounts = new IntList(size) ;
+
+ // Vertex replace flags for the first two vertices are irrelevant.
+ v = 2 ;
+ while (v < size) {
+ flag = vertices.getFlag(v) ;
+
+ if ((flag != RESTART_CW) && (flag != RESTART_CCW)) {
+ // proceed to the next vertex.
+ stripLength++ ;
+ v++ ;
+
+ } else {
+ // Record the last strip.
+ stripCounts.add(stripLength) ;
+ for (int i = stripStart ; i < stripStart+stripLength ; i++)
+ stripVerts.add(i) ;
+
+ // Start a new strip and skip to its 3rd vertex.
+ stripStart = v ;
+ stripLength = 2 ;
+ v += 2 ;
+ }
+ }
+
+ // Finish off the last strip.
+ // If v > size then the strip is degenerate.
+ if (v == size) {
+ stripCounts.add(stripLength) ;
+ for (int i = stripStart ; i < stripStart+stripLength ; i++)
+ stripVerts.add(i) ;
+ } else
+ throw new IllegalArgumentException
+ (J3dUtilsI18N.getString("GeneralizedStrip0")) ;
+
+ if (debug) {
+ System.out.println("GeneralizedStrip.toLineStrips\n") ;
+ if (v > size)
+ System.out.println(" ended with a degenerate line") ;
+
+ System.out.println(" number of strips: " + stripCounts.count) ;
+ if (stripCounts.count > 0) {
+ System.out.println(" number of vertices: " + stripVerts.count) ;
+ System.out.println(" vertices/strip: " +
+ (float)stripVerts.count/stripCounts.count) ;
+ System.out.println(" strip counts: " + stripCounts.toString()) ;
+ // System.out.println(" indices: " + stripVerts.toString()) ;
+ }
+ System.out.println() ;
+ }
+
+ if (stripCounts.count > 0)
+ return new StripArray(stripVerts, stripCounts) ;
+ else
+ return null ;
+ }
+
+ /**
+ * Counts the number of lines defined by arrays of line strips.
+ *
+ * @param stripCounts array of strip counts, as used by the
+ * GeometryStripArray object
+ * @return number of lines in the strips
+ */
+ static int getLineCount(int stripCounts[]) {
+ int count = 0 ;
+ for (int i = 0 ; i < stripCounts.length ; i++)
+ count += (stripCounts[i] - 1) ;
+ return count ;
+ }
+
+ /**
+ * Counts the number of triangles defined by arrays of
+ * triangle strips or fans.
+ *
+ * @param stripCounts array of strip counts, as used by the
+ * GeometryStripArray object
+ * @return number of triangles in the strips or fans
+ */
+ static int getTriangleCount(int stripCounts[]) {
+ int count = 0 ;
+ for (int i = 0 ; i < stripCounts.length ; i++)
+ count += (stripCounts[i] - 2) ;
+ return count ;
+ }
+
+ /**
+ * Counts the number of triangles defined by arrays of
+ * triangle strips or fans.
+ *
+ * @param stripCounts IntList of strip counts
+ * @return number of triangles in the strips or fans
+ */
+ static int getTriangleCount(IntList stripCounts) {
+ int count = 0 ;
+ for (int i = 0 ; i < stripCounts.count ; i++)
+ count += (stripCounts.ints[i] - 2) ;
+ return count ;
+ }
+
+ /**
+ * Breaks up triangle strips into separate triangles.
+ *
+ * @param stripCounts array of strip counts, as used by the
+ * GeometryStripArray object
+ * @return array of ints which index into the original vertex array; each
+ * set of three consecutive vertex indices defines a single triangle
+ */
+ static int[] stripsToTriangles(int stripCounts[]) {
+ int triangleCount = getTriangleCount(stripCounts) ;
+ int tbuff[] = new int[3*triangleCount] ;
+ IntList vertices = new IntList(triangleCount + 2*stripCounts.length) ;
+
+ vertices.fillAscending() ;
+ stripsToTriangles(0, tbuff,
+ 0, vertices.ints,
+ 0, stripCounts,
+ stripCounts.length) ;
+ return tbuff ;
+ }
+
+ /**
+ * Breaks up triangle fans into separate triangles.
+ *
+ * @param stripCounts array of strip counts, as used by the
+ * GeometryStripArray object
+ * @return array of ints which index into the original vertex array; each
+ * set of three consecutive vertex indices defines a single triangle
+ */
+ static int[] fansToTriangles(int stripCounts[]) {
+ int triangleCount = getTriangleCount(stripCounts) ;
+ int tbuff[] = new int[3*triangleCount] ;
+ IntList vertices = new IntList(triangleCount + 2*stripCounts.length) ;
+
+ vertices.fillAscending() ;
+ fansToTriangles(0, tbuff,
+ 0, vertices.ints,
+ 0, stripCounts,
+ stripCounts.length) ;
+ return tbuff ;
+ }
+
+ /**
+ * Takes a fan and converts it to one or more strips.
+ *
+ * @param v index into the fans array of the first vertex in the fan
+ * @param length number of vertices in the fan
+ * @param fans array of vertex indices representing one or more fans
+ * @param convexPlanar if true indicates that the fan is convex and
+ * planar; such fans will always be converted into a single strip
+ * @return a StripArray containing the converted strips
+ */
+ static StripArray fanToStrips(int v, int length, int fans[],
+ boolean convexPlanar) {
+
+ // Initialize IntLists to worst-case sizes.
+ IntList stripVerts = new IntList(length*3) ;
+ IntList stripCounts = new IntList(length) ;
+
+ fanToStrips(v, length, fans, stripVerts, stripCounts, convexPlanar) ;
+ return new StripArray(stripVerts, stripCounts) ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeneralizedStripFlags.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeneralizedStripFlags.java
new file mode 100644
index 0000000..af4e1a7
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeneralizedStripFlags.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+/**
+ * A class which implements GeneralizedStripFlags provides the means to access
+ * the vertex replace code flags associated with each vertex of a generalized
+ * strip. This allows a flexible representation of generalized strips for
+ * various classes and makes it possible to provide a common subset of static
+ * methods which operate only on their topology.
+ *
+ * @see GeneralizedStrip
+ * @see GeneralizedVertexList
+ */
+interface GeneralizedStripFlags {
+
+ /**
+ * This flag indicates that a vertex starts a new strip with clockwise
+ * winding.
+ */
+ static final int RESTART_CW = 0 ;
+
+ /**
+ * This flag indicates that a vertex starts a new strip with
+ * counter-clockwise winding.
+ */
+ static final int RESTART_CCW = 1 ;
+
+ /**
+ * This flag indicates that the next triangle in the strip is defined by
+ * replacing the middle vertex of the previous triangle in the strip.
+ */
+ static final int REPLACE_MIDDLE = 2 ;
+
+ /**
+ * This flag indicates that the next triangle in the strip is defined by
+ * replacing the oldest vertex of the previous triangle in the strip.
+ */
+ static final int REPLACE_OLDEST = 3 ;
+
+ /**
+ * This constant is used to indicate that triangles with clockwise vertex
+ * winding are front facing.
+ */
+ static final int FRONTFACE_CW = 0 ;
+
+ /**
+ * This constant is used to indicate that triangles with counter-clockwise
+ * vertex winding are front facing.
+ */
+ static final int FRONTFACE_CCW = 1 ;
+
+ /**
+ * Return the number of flags. This should be the same as the number of
+ * vertices in the generalized strip.
+ */
+ int getFlagCount() ;
+
+ /**
+ * Return the flag associated with the vertex at the specified index.
+ */
+ int getFlag(int index) ;
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeneralizedVertexList.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeneralizedVertexList.java
new file mode 100644
index 0000000..5bd896b
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeneralizedVertexList.java
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import java.util.ArrayList;
+
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.GeometryStripArray;
+import org.jogamp.java3d.LineStripArray;
+import org.jogamp.java3d.PointArray;
+import org.jogamp.java3d.TriangleArray;
+import org.jogamp.java3d.TriangleFanArray;
+import org.jogamp.java3d.TriangleStripArray;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * The GeneralizedVertexList class is a variable-size list used to
+ * collect the vertices for a generalized strip of points, lines, or
+ * triangles. This is used by the GeometryDecompressor. This class
+ * implements the GeneralizedStripFlags interface and provides methods
+ * for copying instance vertex data into various fixed-size
+ * GeometryArray representations.
+ *
+ * @see GeneralizedStrip
+ * @see GeometryDecompressor
+ */
+class GeneralizedVertexList implements GeneralizedStripFlags {
+
+ // The ArrayList containing the vertices.
+ private ArrayList vertices ;
+
+ // Booleans for individual vertex components.
+ private boolean hasColor3 = false ;
+ private boolean hasColor4 = false ;
+ private boolean hasNormals = false ;
+
+ // Indicates the vertex winding of front-facing triangles in this strip.
+ private int frontFace ;
+
+ /**
+ * Count of number of strips generated after conversion to GeometryArray.
+ */
+ int stripCount ;
+
+ /**
+ * Count of number of vertices generated after conversion to GeometryArray.
+ */
+ int vertexCount ;
+
+ /**
+ * Count of number of triangles generated after conversion to GeometryArray.
+ */
+ int triangleCount ;
+
+ /**
+ * Bits describing the data bundled with each vertex. This is specified
+ * using the GeometryArray mask components.
+ */
+ int vertexFormat ;
+
+ /**
+ * Creates a new GeneralizedVertexList for the specified vertex format.
+ * @param vertexFormat a mask indicating which components are
+ * present in each vertex, as used by GeometryArray.
+ * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
+ * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
+ * @param initSize initial number of elements
+ * @see GeometryArray
+ */
+ GeneralizedVertexList(int vertexFormat, int frontFace, int initSize) {
+ this.frontFace = frontFace ;
+ setVertexFormat(vertexFormat) ;
+
+ if (initSize == 0)
+ vertices = new ArrayList() ;
+ else
+ vertices = new ArrayList(initSize) ;
+
+ stripCount = 0 ;
+ vertexCount = 0 ;
+ triangleCount = 0 ;
+ }
+
+ /**
+ * Creates a new GeneralizedVertexList for the specified vertex format.
+ * @param vertexFormat a mask indicating which components are
+ * present in each vertex, as used by GeometryArray.
+ * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
+ * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
+ * @see GeometryArray
+ */
+ GeneralizedVertexList(int vertexFormat, int frontFace) {
+ this(vertexFormat, frontFace, 0) ;
+ }
+
+ /**
+ * Sets the vertex format for this vertex list.
+ * @param vertexFormat a mask indicating which components are
+ * present in each vertex, as used by GeometryArray.
+ */
+ void setVertexFormat(int vertexFormat) {
+ this.vertexFormat = vertexFormat ;
+
+ if ((vertexFormat & GeometryArray.NORMALS) != 0)
+ hasNormals = true ;
+
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4)
+ hasColor4 = true ;
+ else if ((vertexFormat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3)
+ hasColor3 = true ;
+ }
+
+ /**
+ * A class with fields corresponding to all the data that can be bundled
+ * with the vertices of generalized strips.
+ */
+ class Vertex {
+ int flag ;
+ Point3f coord ;
+ Color3f color3 ;
+ Color4f color4 ;
+ Vector3f normal ;
+
+ Vertex(Point3f p, Vector3f n, Color4f c, int flag) {
+ this.flag = flag ;
+ coord = new Point3f(p) ;
+
+ if (hasNormals)
+ normal = new Vector3f(n) ;
+
+ if (hasColor3)
+ color3 = new Color3f(c.x, c.y, c.z) ;
+
+ else if (hasColor4)
+ color4 = new Color4f(c) ;
+ }
+ }
+
+ /**
+ * Copy vertex data to a new Vertex object and add it to this list.
+ */
+ void addVertex(Point3f pos, Vector3f norm, Color4f color, int flag) {
+ vertices.add(new Vertex(pos, norm, color, flag)) ;
+ }
+
+ /**
+ * Return the number of vertices in this list.
+ */
+ int size() {
+ return vertices.size() ;
+ }
+
+ // GeneralizedStripFlags interface implementation
+ @Override
+ public int getFlagCount() {
+ return vertices.size() ;
+ }
+
+ // GeneralizedStripFlags interface implementation
+ @Override
+ public int getFlag(int index) {
+ return ((Vertex)vertices.get(index)).flag ;
+ }
+
+ // Copy vertices in the given order to a fixed-length GeometryArray.
+ // Using the array versions of the GeometryArray set() methods results in
+ // a significant performance improvement despite needing to create
+ // fixed-length arrays to hold the vertex elements.
+ private void copyVertexData(GeometryArray ga,
+ GeneralizedStrip.IntList indices) {
+ Vertex v ;
+ Point3f p3f[] = new Point3f[indices.count] ;
+
+ if (hasNormals) {
+ Vector3f v3f[] = new Vector3f[indices.count] ;
+ if (hasColor3) {
+ Color3f c3f[] = new Color3f[indices.count] ;
+ for (int i = 0 ; i < indices.count ; i++) {
+ v = (Vertex)vertices.get(indices.ints[i]) ;
+ p3f[i] = v.coord ;
+ v3f[i] = v.normal ;
+ c3f[i] = v.color3 ;
+ }
+ ga.setColors(0, c3f) ;
+
+ } else if (hasColor4) {
+ Color4f c4f[] = new Color4f[indices.count] ;
+ for (int i = 0 ; i < indices.count ; i++) {
+ v = (Vertex)vertices.get(indices.ints[i]) ;
+ p3f[i] = v.coord ;
+ v3f[i] = v.normal ;
+ c4f[i] = v.color4 ;
+ }
+ ga.setColors(0, c4f) ;
+
+ } else {
+ for (int i = 0 ; i < indices.count ; i++) {
+ v = (Vertex)vertices.get(indices.ints[i]) ;
+ p3f[i] = v.coord ;
+ v3f[i] = v.normal ;
+ }
+ }
+ ga.setNormals(0, v3f) ;
+
+ } else {
+ if (hasColor3) {
+ Color3f c3f[] = new Color3f[indices.count] ;
+ for (int i = 0 ; i < indices.count ; i++) {
+ v = (Vertex)vertices.get(indices.ints[i]) ;
+ p3f[i] = v.coord ;
+ c3f[i] = v.color3 ;
+ }
+ ga.setColors(0, c3f) ;
+
+ } else if (hasColor4) {
+ Color4f c4f[] = new Color4f[indices.count] ;
+ for (int i = 0 ; i < indices.count ; i++) {
+ v = (Vertex)vertices.get(indices.ints[i]) ;
+ p3f[i] = v.coord ;
+ c4f[i] = v.color4 ;
+ }
+ ga.setColors(0, c4f) ;
+
+ } else {
+ for (int i = 0 ; i < indices.count ; i++) {
+ v = (Vertex)vertices.get(indices.ints[i]) ;
+ p3f[i] = v.coord ;
+ }
+ }
+ }
+ ga.setCoordinates(0, p3f) ;
+ }
+
+ /**
+ * Output a PointArray.
+ */
+ PointArray toPointArray() {
+ int size = vertices.size() ;
+
+ if (size > 0) {
+ PointArray pa = new PointArray(size, vertexFormat) ;
+ GeneralizedStrip.IntList il = new GeneralizedStrip.IntList(size) ;
+
+ il.fillAscending() ;
+ copyVertexData(pa, il) ;
+
+ vertexCount += size ;
+ return pa ;
+ }
+ else
+ return null ;
+ }
+
+ /**
+ * Output a TriangleArray.
+ */
+ TriangleArray toTriangleArray() {
+ int vertices[] = GeneralizedStrip.toTriangles(this, frontFace) ;
+
+ if (vertices != null) {
+ TriangleArray ta ;
+ GeneralizedStrip.IntList il ;
+
+ ta = new TriangleArray(vertices.length, vertexFormat) ;
+ il = new GeneralizedStrip.IntList(vertices) ;
+ copyVertexData(ta, il) ;
+
+ vertexCount += vertices.length ;
+ triangleCount += vertices.length/3 ;
+ return ta ;
+ } else
+ return null ;
+ }
+
+ /**
+ * Output a LineStripArray.
+ */
+ LineStripArray toLineStripArray() {
+ GeneralizedStrip.StripArray stripArray =
+ GeneralizedStrip.toLineStrips(this) ;
+
+ if (stripArray != null) {
+ LineStripArray lsa ;
+ lsa = new LineStripArray(stripArray.vertices.count,
+ vertexFormat,
+ stripArray.stripCounts.trim()) ;
+
+ copyVertexData(lsa, stripArray.vertices) ;
+
+ vertexCount += stripArray.vertices.count ;
+ stripCount += stripArray.stripCounts.count ;
+ return lsa ;
+ } else
+ return null ;
+ }
+
+ /**
+ * Output a TriangleStripArray.
+ */
+ TriangleStripArray toTriangleStripArray() {
+ GeneralizedStrip.StripArray stripArray =
+ GeneralizedStrip.toTriangleStrips(this, frontFace) ;
+
+ if (stripArray != null) {
+ TriangleStripArray tsa ;
+ tsa = new TriangleStripArray(stripArray.vertices.count,
+ vertexFormat,
+ stripArray.stripCounts.trim()) ;
+
+ copyVertexData(tsa, stripArray.vertices) ;
+
+ vertexCount += stripArray.vertices.count ;
+ stripCount += stripArray.stripCounts.count ;
+ return tsa ;
+ } else
+ return null ;
+ }
+
+ /**
+ * Output triangle strip and triangle fan arrays.
+ * @return a 2-element array of GeometryStripArray; element 0 if non-null
+ * will contain a TriangleStripArray, and element 1 if non-null will
+ * contain a TriangleFanArray.
+ */
+ GeometryStripArray[] toStripAndFanArrays() {
+ GeneralizedStrip.StripArray stripArray[] =
+ GeneralizedStrip.toStripsAndFans(this, frontFace) ;
+
+ GeometryStripArray gsa[] = new GeometryStripArray[2] ;
+
+ if (stripArray[0] != null) {
+ gsa[0] = new TriangleStripArray(stripArray[0].vertices.count,
+ vertexFormat,
+ stripArray[0].stripCounts.trim()) ;
+
+ copyVertexData(gsa[0], stripArray[0].vertices) ;
+
+ vertexCount += stripArray[0].vertices.count ;
+ stripCount += stripArray[0].stripCounts.count ;
+ }
+
+ if (stripArray[1] != null) {
+ gsa[1] = new TriangleFanArray(stripArray[1].vertices.count,
+ vertexFormat,
+ stripArray[1].stripCounts.trim()) ;
+
+ copyVertexData(gsa[1], stripArray[1].vertices) ;
+
+ vertexCount += stripArray[1].vertices.count ;
+ stripCount += stripArray[1].stripCounts.count ;
+ }
+ return gsa ;
+ }
+
+ /**
+ * Output triangle strip and and triangle arrays.
+ * @return a 2-element array of GeometryArray; element 0 if non-null
+ * will contain a TriangleStripArray, and element 1 if non-null will
+ * contain a TriangleArray.
+ */
+ GeometryArray[] toStripAndTriangleArrays() {
+ GeneralizedStrip.StripArray stripArray[] =
+ GeneralizedStrip.toStripsAndTriangles(this, frontFace, 4, 12) ;
+
+ GeometryArray ga[] = new GeometryArray[2] ;
+
+ if (stripArray[0] != null) {
+ ga[0] = new TriangleStripArray(stripArray[0].vertices.count,
+ vertexFormat,
+ stripArray[0].stripCounts.trim()) ;
+
+ copyVertexData(ga[0], stripArray[0].vertices) ;
+
+ vertexCount += stripArray[0].vertices.count ;
+ stripCount += stripArray[0].stripCounts.count ;
+ }
+
+ if (stripArray[1] != null) {
+ ga[1] = new TriangleArray(stripArray[1].vertices.count,
+ vertexFormat) ;
+
+ copyVertexData(ga[1], stripArray[1].vertices) ;
+ triangleCount += stripArray[1].vertices.count/3 ;
+ }
+ return ga ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeometryCompressor.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeometryCompressor.java
new file mode 100644
index 0000000..74bf39e
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeometryCompressor.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import java.io.IOException;
+
+import org.jogamp.vecmath.Point3d;
+
+/**
+ * A GeometryCompressor takes a stream of geometric elements and
+ * quantization parameters (the CompressionStream object) and
+ * compresses it into a stream of commands as defined by appendix B
+ * of the Java 3D specification. The resulting data may be output
+ * in the form of a CompressedGeometryData node component or appended
+ * to a CompressedGeometryFile.
+ *
+ * @see CompressionStream
+ * @see CompressedGeometryData
+ * @see CompressedGeometryFile
+ *
+ * @since Java 3D 1.5
+ */
+public class GeometryCompressor {
+ private static final boolean benchmark = false ;
+ private static final boolean printStream = false ;
+ private static final boolean printHuffman = false ;
+
+ private HuffmanTable huffmanTable ;
+ private CommandStream outputBuffer ;
+ private CompressedGeometryData.Header cgHeader ;
+ private long startTime ;
+
+ public GeometryCompressor() {
+ // Create a compressed geometry header.
+ cgHeader = new CompressedGeometryData.Header() ;
+
+ // v1.0.0 - pre-FCS
+ // v1.0.1 - fixed winding order, FCS version (J3D 1.1.2)
+ // v1.0.2 - normal component length maximum 6, LII hardware (J3D 1.2)
+ cgHeader.majorVersionNumber = 1 ;
+ cgHeader.minorVersionNumber = 0 ;
+ cgHeader.minorMinorVersionNumber = 2 ;
+ }
+
+ /**
+ * Compress a stream into a CompressedGeometryData node component.
+ *
+ *
+ * @param stream CompressionStream containing the geometry to be compressed
+ * @return a CompressedGeometryData node component
+ */
+ public CompressedGeometryData compress(CompressionStream stream) {
+ CompressedGeometryData cg ;
+
+ compressStream(stream) ;
+ cg = new CompressedGeometryData(cgHeader, outputBuffer.getBytes()) ;
+
+ outputBuffer.clear() ;
+ return cg ;
+ }
+
+ /**
+ * Compress a stream and append the output to a CompressedGeometryFile.
+ * The resource remains open for subsequent updates; its close() method
+ * must be called to create a valid compressed geometry resource file.
+ *
+ * @param stream CompressionStream containing the geometry to be compressed
+ * @param f a currently open CompressedGeometryFile with write access
+ * @exception IOException if write fails
+ */
+ public void compress(CompressionStream stream, CompressedGeometryFile f)
+ throws IOException {
+
+ compressStream(stream) ;
+ f.write(cgHeader, outputBuffer.getBytes()) ;
+
+ outputBuffer.clear() ;
+ }
+
+ //
+ // Compress the stream and put the results in the output buffer.
+ // Set up the CompressedGeometryData.Header object.
+ //
+ private void compressStream(CompressionStream stream) {
+ if (benchmark) startTime = System.currentTimeMillis() ;
+
+ // Create the Huffman table.
+ huffmanTable = new HuffmanTable() ;
+
+ // Quantize the stream, compute deltas between consecutive elements if
+ // possible, and histogram the data length distribution.
+ stream.quantize(huffmanTable) ;
+
+ // Compute tags for stream tokens.
+ huffmanTable.computeTags() ;
+
+ // Create the output buffer and assemble the compressed output.
+ outputBuffer = new CommandStream(stream.getByteCount() / 3) ;
+ stream.outputCommands(huffmanTable, outputBuffer) ;
+
+ // Print any desired info.
+ if (benchmark) printBench(stream) ;
+ if (printStream) stream.print() ;
+ if (printHuffman) huffmanTable.print() ;
+
+ // Set up the compressed geometry header object.
+ cgHeader.bufferType = stream.streamType ;
+ cgHeader.bufferDataPresent = 0 ;
+ cgHeader.lowerBound = new Point3d(stream.ncBounds[0]) ;
+ cgHeader.upperBound = new Point3d(stream.ncBounds[1]) ;
+
+ if (stream.vertexNormals)
+ cgHeader.bufferDataPresent |=
+ CompressedGeometryData.Header.NORMAL_IN_BUFFER ;
+
+ if (stream.vertexColor3 || stream.vertexColor4)
+ cgHeader.bufferDataPresent |=
+ CompressedGeometryData.Header.COLOR_IN_BUFFER ;
+
+ if (stream.vertexColor4)
+ cgHeader.bufferDataPresent |=
+ CompressedGeometryData.Header.ALPHA_IN_BUFFER ;
+
+ cgHeader.start = 0 ;
+ cgHeader.size = outputBuffer.getByteCount() ;
+
+ // Clear the huffman table for next use.
+ huffmanTable.clear() ;
+ }
+
+ private void printBench(CompressionStream stream) {
+ long t = System.currentTimeMillis() - startTime ;
+ int vertexCount = stream.getVertexCount() ;
+ int meshReferenceCount = stream.getMeshReferenceCount() ;
+ int totalVertices = meshReferenceCount + vertexCount ;
+ float meshPercent = 100f * meshReferenceCount/(float)totalVertices ;
+
+ float compressionRatio =
+ stream.getByteCount() / ((float)outputBuffer.getByteCount()) ;
+
+ int vertexBytes =
+ 12 + (stream.vertexColor3 ? 12 : 0) +
+ (stream.vertexColor4 ? 16 : 0) + (stream.vertexNormals ? 12 : 0) ;
+
+ float compressedVertexBytes =
+ outputBuffer.getByteCount() / (float)totalVertices ;
+
+ System.out.println
+ ("\nGeometryCompressor:\n" + totalVertices + " total vertices\n" +
+ vertexCount + " streamed vertices\n" + meshReferenceCount +
+ " mesh buffer references (" + meshPercent + "%)\n" +
+ stream.getByteCount() + " bytes streamed geometry compressed to " +
+ outputBuffer.getByteCount() + " in " + (t/1000f) + " sec\n" +
+ (stream.getByteCount()/(float)t) + " kbytes/sec, " +
+ "stream compression ratio " + compressionRatio + "\n\n" +
+ vertexBytes + " original bytes per vertex, " +
+ compressedVertexBytes + " compressed bytes per vertex\n" +
+ "total vertex compression ratio " +
+ (vertexBytes / (float)compressedVertexBytes) + "\n\n" +
+ "lower bound " + stream.ncBounds[0].toString() +"\n" +
+ "upper bound " + stream.ncBounds[1].toString()) ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeometryDecompressor.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeometryDecompressor.java
new file mode 100644
index 0000000..22b6449
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeometryDecompressor.java
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import org.jogamp.java3d.CompressedGeometryHeader;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3f;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+/**
+ * This abstract class provides the base methods needed to create a geometry
+ * decompressor. Subclasses must implement a backend to handle the output,
+ * consisting of a generalized triangle strip, line strip, or point array,
+ * along with possible global color and normal changes.
+ */
+abstract class GeometryDecompressor {
+ private static final boolean debug = false ;
+ private static final boolean benchmark = false ;
+
+ /**
+ * Compressed geometry format version supported.
+ */
+ static final int majorVersionNumber = 1 ;
+ static final int minorVersionNumber = 0 ;
+ static final int minorMinorVersionNumber = 2 ;
+
+ /**
+ * This method is called when a SetState command is encountered in the
+ * decompression stream.
+ *
+ * @param bundlingNorm true indicates normals are bundled with vertices
+ * @param bundlingColor true indicates colors are bundled with vertices
+ * @param doingAlpha true indicates alpha values are bundled with vertices
+ */
+ abstract void outputVertexFormat(boolean bundlingNorm,
+ boolean bundlingColor,
+ boolean doingAlpha) ;
+
+ /**
+ * This method captures the vertex output of the decompressor. The normal
+ * or color references may be null if the corresponding data is not
+ * bundled with the vertices in the compressed geometry buffer. Alpha
+ * values may be included in the color.
+ *
+ * @param position The coordinates of the vertex.
+ * @param normal The normal bundled with the vertex. May be null.
+ * @param color The color bundled with the vertex. May be null.
+ * Alpha may be present.
+ * @param vertexReplaceCode Specifies the generalized strip flag
+ * that is bundled with each vertex.
+ * @see GeneralizedStripFlags
+ * @see CompressedGeometryHeader
+ */
+ abstract void outputVertex(Point3f position, Vector3f normal,
+ Color4f color, int vertexReplaceCode) ;
+
+ /**
+ * This method captures the global color output of the decompressor. It
+ * is only invoked if colors are not bundled with the vertex data. The
+ * global color applies to all succeeding vertices until the next time the
+ * method is invoked.
+ *
+ * @param color The current global color.
+ */
+ abstract void outputColor(Color4f color) ;
+
+ /**
+ * This method captures the global normal output of the decompressor. It
+ * is only invoked if normals are not bundled with the vertex data. The
+ * global normal applies to all succeeding vertices until the next time the
+ * method is invoked.
+ *
+ * @param normal The current global normal.
+ */
+ abstract void outputNormal(Vector3f normal) ;
+
+ // Geometry compression opcodes.
+ private static final int GC_VERTEX = 0x40 ;
+ private static final int GC_SET_NORM = 0xC0 ;
+ private static final int GC_SET_COLOR = 0x80 ;
+ private static final int GC_MESH_B_R = 0x20 ;
+ private static final int GC_SET_STATE = 0x18 ;
+ private static final int GC_SET_TABLE = 0x10 ;
+ private static final int GC_PASS_THROUGH = 0x08 ;
+ private static final int GC_EOS = 0x00 ;
+ private static final int GC_V_NO_OP = 0x01 ;
+ private static final int GC_SKIP_8 = 0x07 ;
+
+ // Three 64-entry decompression tables are used: gctables[0] for
+ // positions, gctables[1] for colors, and gctables[2] for normals.
+ private HuffmanTableEntry gctables[][] ;
+
+ /**
+ * Decompression table entry.
+ */
+ static class HuffmanTableEntry {
+ int tagLength, dataLength ;
+ int rightShift, absolute ;
+
+ @Override
+ public String toString() {
+ return
+ " tag length: " + tagLength +
+ " data length: " + dataLength +
+ " shift: " + rightShift +
+ " abs/rel: " + absolute ;
+ }
+ }
+
+ // A 16-entry mesh buffer is used.
+ private MeshBufferEntry meshBuffer[] ;
+ private int meshIndex = 15 ;
+ private int meshState ;
+
+ // meshState values. These are needed to determine if colors and/or
+ // normals should come from meshBuffer or from SetColor or SetNormal.
+ private static final int USE_MESH_NORMAL = 0x1 ;
+ private static final int USE_MESH_COLOR = 0x2 ;
+
+ /**
+ * Mesh buffer entry containing position, normal, and color.
+ */
+ static class MeshBufferEntry {
+ short x, y, z ;
+ short octant, sextant, u, v ;
+ short r, g, b, a ;
+ }
+
+ // Geometry compression state variables.
+ private short curX, curY, curZ ;
+ private short curR, curG, curB, curA ;
+ private int curSex, curOct, curU, curV ;
+
+ // Current vertex data.
+ private Point3f curPos ;
+ private Vector3f curNorm ;
+ private Color4f curColor ;
+ private int repCode ;
+
+ // Flags indicating what data is bundled with the vertex.
+ private boolean bundlingNorm ;
+ private boolean bundlingColor ;
+ private boolean doingAlpha ;
+
+ // Internal decompression buffering variables.
+ private int currentHeader = 0 ;
+ private int nextHeader = 0 ;
+ private int bitBuffer = 0 ;
+ private int bitBufferCount = 32 ;
+
+ // Used for benchmarking if so configured.
+ private long startTime ;
+ private int vertexCount ;
+
+ // Bit-field masks: BMASK[i] = (1< 64) continue ;
+
+ psi = NORMAL_MAX_Y_ANG * (i / 64.0) ;
+ th = Math.asin(Math.tan(NORMAL_MAX_Y_ANG * ((64-j)/64.0))) ;
+
+ qnx = Math.cos(th) * Math.cos(psi) ;
+ qny = Math.sin(psi) ;
+ qnz = Math.sin(th) * Math.cos(psi) ;
+
+ // Convert the floating point normal to s1.14 bit notation,
+ // then back again.
+ qnx = qnx*16384.0 ; inx = (int)qnx ;
+ qnx = (double)inx ; qnx = qnx/16384.0 ;
+
+ qny = qny*16384.0 ; iny = (int)qny ;
+ qny = (double)iny ; qny = qny/16384.0 ;
+
+ qnz = qnz*16384.0 ; inz = (int)qnz ;
+ qnz = (double)inz ; qnz = qnz/16384.0 ;
+
+ gcNormals[i][j][0] = qnx ;
+ gcNormals[i][j][1] = qny ;
+ gcNormals[i][j][2] = qnz ;
+ }
+ }
+
+ if (printNormalTable) {
+ System.out.println("struct {") ;
+ System.out.println(" double nx, ny, nz ;") ;
+ System.out.println("} gcNormals[65][65] = {");
+ for (i = 0 ; i <= 64 ; i++) {
+ System.out.println("{") ;
+ for (j = 0 ; j <= 64 ; j++) {
+ if (j+i > 64) continue ;
+ System.out.println("{ " + gcNormals[i][j][0] +
+ ", " + gcNormals[i][j][1] +
+ ", " + gcNormals[i][j][2] + " }") ;
+ }
+ System.out.println("},") ;
+ }
+ System.out.println("}") ;
+ }
+ }
+
+ //
+ // The constructor.
+ //
+ GeometryDecompressor() {
+ curPos = new Point3f() ;
+ curNorm = new Vector3f() ;
+ curColor = new Color4f() ;
+ gctables = new HuffmanTableEntry[3][64] ;
+
+ for (int i = 0 ; i < 64 ; i++) {
+ gctables[0][i] = new HuffmanTableEntry() ;
+ gctables[1][i] = new HuffmanTableEntry() ;
+ gctables[2][i] = new HuffmanTableEntry() ;
+ }
+
+ meshBuffer = new MeshBufferEntry[16] ;
+ for (int i = 0 ; i < 16 ; i++)
+ meshBuffer[i] = new MeshBufferEntry() ;
+ }
+
+ /**
+ * Check version numbers and return true if compatible.
+ */
+ boolean checkVersion(int majorVersionNumber, int minorVersionNumber) {
+ return ((majorVersionNumber < this.majorVersionNumber) ||
+ ((majorVersionNumber == this.majorVersionNumber) &&
+ (minorVersionNumber <= this.minorVersionNumber))) ;
+ }
+
+ /**
+ * Decompress data and invoke abstract output methods.
+ *
+ * @param start byte offset to start of compressed geometry in data array
+ * @param length size of compressed geometry in bytes
+ * @param data array containing compressed geometry buffer of the
+ * specified length at the given offset from the start of the array
+ * @exception ArrayIndexOutOfBoundsException if start+length > data size
+ */
+ void decompress(int start, int length, byte data[]) {
+ if (debug)
+ System.out.println("GeometryDecompressor.decompress\n" +
+ " start: " + start +
+ " length: " + length +
+ " data array size: " + data.length) ;
+ if (benchmark)
+ benchmarkStart(length) ;
+
+ if (start+length > data.length)
+ throw new ArrayIndexOutOfBoundsException
+ (J3dUtilsI18N.getString("GeometryDecompressor0")) ;
+
+ // Set reference to compressed data and skip to start of data.
+ gcData = data ;
+ gcIndex = start ;
+
+ // Initialize state.
+ bitBufferCount = 0 ;
+ meshState = 0 ;
+ bundlingNorm = false ;
+ bundlingColor = false ;
+ doingAlpha = false ;
+ repCode = 0 ;
+
+ // Headers are interleaved for hardware implementations, so the
+ // first is always a nullop.
+ nextHeader = GC_V_NO_OP ;
+
+ // Enter decompression loop.
+ while (gcIndex < start+length)
+ processDecompression() ;
+
+ // Finish out any bits left in bitBuffer.
+ while (bitBufferCount > 0)
+ processDecompression() ;
+
+ if (benchmark)
+ benchmarkPrint(length) ;
+ }
+
+ //
+ // Return the next bitCount bits of compressed data.
+ //
+ private int getBits(int bitCount, String d) {
+ int bits ;
+
+ if (debug)
+ System.out.print(" getBits(" + bitCount + ") " + d + ", " +
+ bitBufferCount + " available at gcIndex " +
+ gcIndex) ;
+
+ if (bitCount == 0) {
+ if (debug) System.out.println(": got 0x0") ;
+ return 0 ;
+ }
+
+ if (bitBufferCount == 0) {
+ bitBuffer = (((gcData[gcIndex++] & 0xff) << 24) |
+ ((gcData[gcIndex++] & 0xff) << 16) |
+ ((gcData[gcIndex++] & 0xff) << 8) |
+ ((gcData[gcIndex++] & 0xff))) ;
+
+ bitBufferCount = 32 ;
+ }
+
+ if (bitBufferCount >= bitCount) {
+ bits = (bitBuffer >>> (32 - bitCount)) & BMASK[bitCount] ;
+ bitBuffer = bitBuffer << bitCount ;
+ bitBufferCount -= bitCount ;
+ } else {
+ bits = (bitBuffer >>> (32 - bitCount)) & BMASK[bitCount] ;
+ bits = bits >>> (bitCount - bitBufferCount) ;
+ bits = bits << (bitCount - bitBufferCount) ;
+
+ bitBuffer = (((gcData[gcIndex++] & 0xff) << 24) |
+ ((gcData[gcIndex++] & 0xff) << 16) |
+ ((gcData[gcIndex++] & 0xff) << 8) |
+ ((gcData[gcIndex++] & 0xff))) ;
+
+ bits = bits |
+ ((bitBuffer >>> (32 - (bitCount - bitBufferCount))) &
+ BMASK[bitCount - bitBufferCount]) ;
+
+ bitBuffer = bitBuffer << (bitCount - bitBufferCount) ;
+ bitBufferCount = 32 - (bitCount - bitBufferCount) ;
+ }
+
+ if (debug)
+ System.out.println(": got 0x" + Integer.toHexString(bits)) ;
+
+ return bits ;
+ }
+
+ //
+ // Shuffle interleaved headers and opcodes.
+ //
+ private void processDecompression() {
+ int mbp ;
+ currentHeader = nextHeader ;
+
+ if ((currentHeader & 0xC0) == GC_VERTEX) {
+ // Process a vertex.
+ if (!bundlingNorm && !bundlingColor) {
+ // get next opcode, process current position opcode
+ nextHeader = getBits(8, "header") ;
+ mbp = processDecompressionOpcode(0) ;
+
+ } else if (bundlingNorm && !bundlingColor) {
+ // get normal header, process current position opcode
+ nextHeader = getBits(6, "normal") ;
+ mbp = processDecompressionOpcode(0) ;
+ currentHeader = nextHeader | GC_SET_NORM ;
+
+ // get next opcode, process current normal opcode
+ nextHeader = getBits(8, "header") ;
+ processDecompressionOpcode(mbp) ;
+
+ } else if (!bundlingNorm && bundlingColor) {
+ // get color header, process current position opcode
+ nextHeader = getBits(6, "color") ;
+ mbp = processDecompressionOpcode(0) ;
+ currentHeader = nextHeader | GC_SET_COLOR ;
+
+ // get next opcode, process current color opcode
+ nextHeader = getBits(8, "header") ;
+ processDecompressionOpcode(mbp) ;
+
+ } else {
+ // get normal header, process current position opcode
+ nextHeader = getBits(6, "normal") ;
+ mbp = processDecompressionOpcode(0) ;
+ currentHeader = nextHeader | GC_SET_NORM ;
+
+ // get color header, process current normal opcode
+ nextHeader = getBits(6, "color") ;
+ processDecompressionOpcode(mbp) ;
+ currentHeader = nextHeader | GC_SET_COLOR ;
+
+ // get next opcode, process current color opcode
+ nextHeader = getBits(8, "header") ;
+ processDecompressionOpcode(mbp) ;
+ }
+
+ // Send out the complete vertex.
+ outputVertex(curPos, curNorm, curColor, repCode) ;
+ if (benchmark) vertexCount++ ;
+
+ // meshState bits get turned off in the setColor and setNormal
+ // routines in order to keep track of what data a mesh buffer
+ // reference should use.
+ meshState |= USE_MESH_NORMAL ;
+ meshState |= USE_MESH_COLOR ;
+
+ } else {
+ // Non-vertex case: get next opcode, then process current opcode.
+ nextHeader = getBits(8, "header") ;
+ processDecompressionOpcode(0) ;
+ }
+ }
+
+ //
+ // Decode the opcode in currentHeader, and dispatch to the appropriate
+ // processing method.
+ //
+ private int processDecompressionOpcode(int mbp) {
+ if ((currentHeader & 0xC0) == GC_SET_NORM)
+ processSetNormal(mbp) ;
+ else if ((currentHeader & 0xC0) == GC_SET_COLOR)
+ processSetColor(mbp) ;
+ else if ((currentHeader & 0xC0) == GC_VERTEX)
+ // Return the state of the mesh buffer push bit
+ // when processing a vertex.
+ return processVertex() ;
+ else if ((currentHeader & 0xE0) == GC_MESH_B_R) {
+ processMeshBR() ;
+
+ // Send out the complete vertex.
+ outputVertex(curPos, curNorm, curColor, repCode) ;
+ if (benchmark) vertexCount++ ;
+
+ // meshState bits get turned off in the setColor and setNormal
+ // routines in order to keep track of what data a mesh buffer
+ // reference should use.
+ meshState |= USE_MESH_NORMAL ;
+ meshState |= USE_MESH_COLOR ;
+ }
+ else if ((currentHeader & 0xF8) == GC_SET_STATE)
+ processSetState() ;
+ else if ((currentHeader & 0xF8) == GC_SET_TABLE)
+ processSetTable() ;
+ else if ((currentHeader & 0xFF) == GC_EOS)
+ processEos() ;
+ else if ((currentHeader & 0xFF) == GC_V_NO_OP)
+ processVNoop() ;
+ else if ((currentHeader & 0xFF) == GC_PASS_THROUGH)
+ processPassThrough() ;
+ else if ((currentHeader & 0xFF) == GC_SKIP_8)
+ processSkip8() ;
+
+ return 0 ;
+ }
+
+ //
+ // Process a set state opcode.
+ //
+ private void processSetState() {
+ int ii ;
+ if (debug)
+ System.out.println("GeometryDecompressor.processSetState") ;
+
+ ii = getBits(3, "bundling") ;
+
+ bundlingNorm = ((currentHeader & 0x1) != 0) ;
+ bundlingColor = (((ii >>> 2) & 0x1) != 0) ;
+ doingAlpha = (((ii >>> 1) & 0x1) != 0) ;
+
+ if (debug)
+ System.out.println(" bundling normal: " + bundlingNorm +
+ " bundling color: " + bundlingColor +
+ " alpha present: " + doingAlpha) ;
+
+ // Call the abstract output implementation.
+ outputVertexFormat(bundlingNorm, bundlingColor, doingAlpha) ;
+ }
+
+ //
+ // Process a set decompression table opcode.
+ //
+ // Extract the parameters of the table set command,
+ // and set the approprate table entries.
+ //
+ private void processSetTable() {
+ HuffmanTableEntry gct[] ;
+ int i, adr, tagLength, dataLength, rightShift, absolute ;
+ int ii, index ;
+
+ if (debug)
+ System.out.println("GeometryDecompressor.processSetTable") ;
+
+ // Get reference to approprate 64 entry table.
+ index = (currentHeader & 0x6) >>> 1 ;
+ gct = gctables[index] ;
+
+ // Get the remaining bits of the set table command.
+ ii = getBits(15, "set table") ;
+
+ // Extract the individual fields from the two bit strings.
+ adr = ((currentHeader & 0x1) << 6) | ((ii >>> 9) & 0x3F) ;
+
+ // Get data length. For positions and colors, 0 really means 16, as 0
+ // lengths are meaningless for them. Normal components are allowed to
+ // have lengths of 0.
+ dataLength = (ii >>> 5) & 0x0F ;
+ if (dataLength == 0 && index != 2)
+ dataLength = 16 ;
+
+ rightShift = ii & 0x0F ;
+ absolute = (ii >>> 4) & 0x1 ;
+
+ //
+ // Decode the tag length from the address field by finding the
+ // first set 1 from the left in the bitfield.
+ //
+ for (tagLength = 6 ; tagLength > 0 ; tagLength--) {
+ if ((adr >> tagLength) != 0) break ;
+ }
+
+ // Shift the address bits up into place, and off the leading 1.
+ adr = (adr << (6 - tagLength)) & 0x3F ;
+
+ if (debug)
+ System.out.println(" table " + ((currentHeader & 0x6) >>> 1) +
+ " address " + adr +
+ " tag length " + tagLength +
+ " data length " + dataLength +
+ " shift " + rightShift +
+ " absolute " + absolute) ;
+
+ // Fill in the table fields with the specified values.
+ for (i = 0 ; i < (1 << (6 - tagLength)) ; i++) {
+ gct[adr+i].tagLength = tagLength ;
+ gct[adr+i].dataLength = dataLength ;
+ gct[adr+i].rightShift = rightShift ;
+ gct[adr+i].absolute = absolute ;
+ }
+ }
+
+
+ //
+ // Process a vertex opcode. Any bundled normal and/or color will be
+ // processed by separate methods. Return the mesh buffer push indicator.
+ //
+ private int processVertex() {
+ HuffmanTableEntry gct ;
+ float fX, fY, fZ ;
+ short dx, dy, dz ;
+ int mbp, x, y, z, dataLen ;
+ int ii ;
+
+ // If the next command is a mesh buffer reference
+ // then use colors and normals from the mesh buffer.
+ meshState = 0 ;
+
+ // Get a reference to the approprate tag table entry.
+ gct = gctables[0][currentHeader & 0x3F] ;
+
+ if (debug) System.out.println("GeometryDecompressor.processVertex\n" +
+ gct.toString()) ;
+
+ // Get the true length of the data.
+ dataLen = gct.dataLength - gct.rightShift ;
+
+ // Read in the replace code and mesh buffer push bits,
+ // if they're not in the current header.
+ if (6 - (3 * dataLen) - gct.tagLength > 0) {
+ int numBits = 6 - (3 * dataLen) - gct.tagLength ;
+ int jj ;
+
+ jj = currentHeader & BMASK[numBits] ;
+ ii = getBits(3 - numBits, "repcode/mbp") ;
+ ii |= (jj << (3 - numBits)) ;
+ }
+ else
+ ii = getBits(3, "repcode/mbp") ;
+
+ repCode = ii >>> 1 ;
+ mbp = ii & 0x1 ;
+
+ // Read in x, y, and z components.
+ x = currentHeader & BMASK[6-gct.tagLength] ;
+
+ if (gct.tagLength + dataLen == 6) {
+ y = getBits(dataLen, "y") ;
+ z = getBits(dataLen, "z") ;
+ } else if (gct.tagLength + dataLen < 6) {
+ x = x >> (6 - gct.tagLength - dataLen) ;
+
+ y = currentHeader & BMASK[6 - gct.tagLength - dataLen] ;
+ if (gct.tagLength + 2*dataLen == 6) {
+ z = getBits(dataLen, "z") ;
+ } else if (gct.tagLength + 2*dataLen < 6) {
+ y = y >> (6 - gct.tagLength - 2*dataLen) ;
+
+ z = currentHeader & BMASK[6 - gct.tagLength - 2*dataLen] ;
+ if (gct.tagLength + 3*dataLen < 6) {
+ z = z >> (6 - gct.tagLength - 3*dataLen) ;
+ } else if (gct.tagLength + 3*dataLen > 6) {
+ ii = getBits(dataLen - (6 - gct.tagLength - 2*dataLen),
+ "z") ;
+ z = (z << (dataLen - (6 - gct.tagLength - 2*dataLen)))
+ | ii ;
+ }
+ } else {
+ ii = getBits(dataLen - (6 - gct.tagLength - dataLen), "y") ;
+ y = (y << (dataLen - (6 - gct.tagLength - dataLen))) | ii ;
+ z = getBits(dataLen, "z") ;
+ }
+ } else {
+ ii = getBits(dataLen - (6 - gct.tagLength), "x") ;
+ x = (x << (dataLen - (6 - gct.tagLength))) | ii ;
+ y = getBits(dataLen, "y") ;
+ z = getBits(dataLen, "z") ;
+ }
+
+ // Sign extend delta x y z components.
+ x = x << (32 - dataLen) ; x = x >> (32 - dataLen) ;
+ y = y << (32 - dataLen) ; y = y >> (32 - dataLen) ;
+ z = z << (32 - dataLen) ; z = z >> (32 - dataLen) ;
+
+ // Normalize values.
+ dx = (short)(x << gct.rightShift) ;
+ dy = (short)(y << gct.rightShift) ;
+ dz = (short)(z << gct.rightShift) ;
+
+ // Update current position, first adding deltas if in relative mode.
+ if (gct.absolute != 0) {
+ curX = dx ; curY = dy ; curZ = dz ;
+ if (debug) System.out.println(" absolute position: " +
+ curX + " " + curY + " " + curZ) ;
+ } else {
+ curX += dx ; curY += dy ; curZ += dz ;
+ if (debug) System.out.println(" delta position: " +
+ dx + " " + dy + " " + dz) ;
+ }
+
+ // Do optional mesh buffer push.
+ if (mbp != 0) {
+ // Increment to next position (meshIndex is initialized to 15).
+ meshIndex = (meshIndex + 1) & 0xF ;
+ meshBuffer[meshIndex].x = curX ;
+ meshBuffer[meshIndex].y = curY ;
+ meshBuffer[meshIndex].z = curZ ;
+ if (debug)
+ System.out.println(" pushed position into mesh buffer at " +
+ meshIndex) ;
+ }
+
+ // Convert point back to [-1..1] floating point.
+ fX = curX ; fX /= 32768.0 ;
+ fY = curY ; fY /= 32768.0 ;
+ fZ = curZ ; fZ /= 32768.0 ;
+ if (debug)
+ System.out.println(" result position " + fX + " " + fY + " " + fZ) ;
+
+ curPos.set(fX, fY, fZ) ;
+ return mbp ;
+ }
+
+
+ //
+ // Process a set current normal opcode.
+ //
+ private void processSetNormal(int mbp) {
+ HuffmanTableEntry gct ;
+ int index, du, dv, n, dataLength ;
+ int ii ;
+
+ // if next command is a mesh buffer reference, use this normal
+ meshState &= ~USE_MESH_NORMAL ;
+
+ // use table 2 for normals
+ gct = gctables[2][currentHeader & 0x3F] ;
+
+ if (debug)
+ System.out.println("GeometryDecompressor.processSetNormal\n" +
+ gct.toString()) ;
+
+ // subtract up-shift amount to get true data (u, v) length
+ dataLength = gct.dataLength - gct.rightShift ;
+
+ if (gct.absolute != 0) {
+ //
+ // Absolute normal case. Extract index from 6-bit tag.
+ //
+ index = currentHeader & BMASK[6-gct.tagLength] ;
+
+ if (gct.tagLength != 0) {
+ // read in the rest of the 6-bit sex/oct pair (index)
+ ii = getBits(6 - (6 - gct.tagLength), "sex/oct") ;
+ index = (index << (6 - (6 - gct.tagLength))) | ii ;
+ }
+
+ // read in u and v data
+ curU = getBits(dataLength, "u") ;
+ curV = getBits(dataLength, "v") ;
+
+ // normalize u, v, sextant, and octant
+ curU = curU << gct.rightShift ;
+ curV = curV << gct.rightShift ;
+
+ curSex = (index >> 3) & 0x7 ;
+ curOct = index & 0x7 ;
+
+ if (debug) {
+ if (curSex < 6)
+ System.out.println(" absolute normal: sex " + curSex +
+ " oct " + curOct +
+ " u " + curU + " v " + curV) ;
+ else
+ System.out.println(" special normal: sex " + curSex +
+ " oct " + curOct) ;
+ }
+ } else {
+ //
+ // Relative normal case. Extract du from 6-bit tag.
+ //
+ du = currentHeader & BMASK[6-gct.tagLength] ;
+
+ if (gct.tagLength + dataLength < 6) {
+ // normalize du, get dv
+ du = du >> (6 - gct.tagLength - dataLength) ;
+ dv = currentHeader & BMASK[6 - gct.tagLength - dataLength] ;
+
+ if (gct.tagLength + 2*dataLength < 6) {
+ // normalize dv
+ dv = dv >> (6 - gct.tagLength - 2*dataLength) ;
+ } else if (gct.tagLength + 2*dataLength > 6) {
+ // read in rest of dv and normalize it
+ ii = getBits(dataLength -
+ (6 - gct.tagLength - dataLength), "dv") ;
+ dv = (dv << (dataLength -
+ (6 - gct.tagLength - dataLength))) | ii ;
+ }
+ } else if (gct.tagLength + dataLength > 6) {
+ // read in rest of du and normalize it
+ ii = getBits(dataLength - (6 - gct.tagLength), "du") ;
+ du = (du << (dataLength - (6 - gct.tagLength))) | ii ;
+ // read in dv
+ dv = getBits(dataLength, "dv") ;
+ } else {
+ // read in dv
+ dv = getBits(dataLength, "dv") ;
+ }
+
+ // Sign extend delta uv components.
+ du = du << (32 - dataLength) ; du = du >> (32 - dataLength) ;
+ dv = dv << (32 - dataLength) ; dv = dv >> (32 - dataLength) ;
+
+ // normalize values
+ du = du << gct.rightShift ;
+ dv = dv << gct.rightShift ;
+
+ // un-delta
+ curU += du ;
+ curV += dv ;
+
+ if (debug)
+ System.out.println(" delta normal: du " + du + " dv " + dv) ;
+
+ //
+ // Check for normal wrap.
+ //
+ if (! ((curU >= 0) && (curV >= 0) && (curU + curV <= 64)))
+ if ((curU < 0) && (curV >= 0)) {
+ // wrap on u, same octant, different sextant
+ curU = -curU ;
+ switch (curSex) {
+ case 0: curSex = 4 ; break ;
+ case 1: curSex = 5 ; break ;
+ case 2: curSex = 3 ; break ;
+ case 3: curSex = 2 ; break ;
+ case 4: curSex = 0 ; break ;
+ case 5: curSex = 1 ; break ;
+ }
+ } else if ((curU >= 0) && (curV < 0)) {
+ // wrap on v, same sextant, different octant
+ curV = -curV ;
+ switch (curSex) {
+ case 1: case 5:
+ curOct = curOct ^ 4 ; // invert x axis
+ break ;
+ case 0: case 4:
+ curOct = curOct ^ 2 ; // invert y axis
+ break ;
+ case 2: case 3:
+ curOct = curOct ^ 1 ; // invert z axis
+ break ;
+ }
+ } else if (curU + curV > 64) {
+ // wrap on uv, same octant, different sextant
+ curU = 64 - curU ;
+ curV = 64 - curV ;
+ switch (curSex) {
+ case 0: curSex = 2 ; break ;
+ case 1: curSex = 3 ; break ;
+ case 2: curSex = 0 ; break ;
+ case 3: curSex = 1 ; break ;
+ case 4: curSex = 5 ; break ;
+ case 5: curSex = 4 ; break ;
+ }
+ } else {
+ throw new IllegalArgumentException
+ (J3dUtilsI18N.getString("GeometryDecompressor1")) ;
+ }
+ }
+
+ // do optional mesh buffer push
+ if (mbp != 0) {
+ if (debug)
+ System.out.println(" pushing normal into mesh buffer at " +
+ meshIndex) ;
+
+ meshBuffer[meshIndex].sextant = (short)curSex ;
+ meshBuffer[meshIndex].octant = (short)curOct ;
+ meshBuffer[meshIndex].u = (short)curU ;
+ meshBuffer[meshIndex].v = (short)curV ;
+ }
+
+ // convert normal back to [-1..1] floating point
+ indexNormal(curSex, curOct, curU, curV, curNorm) ;
+
+ // a set normal opcode when normals aren't bundled with the vertices
+ // is a global normal change.
+ if (! bundlingNorm) outputNormal(curNorm) ;
+ }
+
+
+ //
+ // Get the floating point normal from its sextant, octant, u, and v.
+ //
+ private void indexNormal(int sex, int oct, int u, int v, Vector3f n) {
+ float nx, ny, nz, t ;
+
+ if (debug) System.out.println(" sextant " + sex + " octant " + oct +
+ " u " + u + " v " + v) ;
+ if (sex > 5) {
+ // special normals
+ switch (oct & 0x1) {
+ case 0: // six coordinate axes
+ switch (((sex & 0x1) << 1) | ((oct & 0x4) >> 2)) {
+ case 0: nx = 1.0f ; ny = nz = 0.0f ; break ;
+ case 1: ny = 1.0f ; nx = nz = 0.0f ; break ;
+ default:
+ case 2: nz = 1.0f ; nx = ny = 0.0f ; break ;
+ }
+ sex = 0 ; oct = (oct & 0x2) >> 1 ;
+ oct = (oct << 2) | (oct << 1) | oct ;
+ break ;
+ case 1: // eight mid
+ default:
+ oct = ((sex & 0x1) << 2) | (oct >> 1) ;
+ sex = 0 ;
+ nx = ny = nz = (float)(1.0/Math.sqrt(3.0)) ;
+ break ;
+ }
+ if ((oct & 0x1) != 0) nz = -nz ;
+ if ((oct & 0x2) != 0) ny = -ny ;
+ if ((oct & 0x4) != 0) nx = -nx ;
+
+ } else {
+ // regular normals
+ nx = (float)gcNormals[v][u][0] ;
+ ny = (float)gcNormals[v][u][1] ;
+ nz = (float)gcNormals[v][u][2] ;
+
+ // reverse the swap
+ if ((sex & 0x4) != 0) { t = nx ; nx = nz ; nz = t ; }
+ if ((sex & 0x2) != 0) { t = ny ; ny = nz ; nz = t ; }
+ if ((sex & 0x1) != 0) { t = nx ; nx = ny ; ny = t ; }
+
+ // reverse the sign flip
+ if ((oct & 0x1) != 0) nz = -nz ;
+ if ((oct & 0x2) != 0) ny = -ny ;
+ if ((oct & 0x4) != 0) nx = -nx ;
+ }
+
+ // return resulting normal
+ n.set(nx, ny, nz) ;
+ if (debug)
+ System.out.println(" result normal: " + nx + " " + ny + " " + nz) ;
+ }
+
+
+ //
+ // Process a set current color command.
+ //
+ private void processSetColor(int mbp) {
+ HuffmanTableEntry gct ;
+ short dr, dg, db, da ;
+ float fR, fG, fB, fA ;
+ int r, g, b, a, index, dataLength ;
+ int ii ;
+
+ // If the next command is a mesh buffer reference, use this color.
+ meshState &= ~USE_MESH_COLOR ;
+
+ // Get the huffman table entry.
+ gct = gctables[1][currentHeader & 0x3F] ;
+
+ if (debug)
+ System.out.println("GeometryDecompressor.processSetColor\n" +
+ gct.toString()) ;
+
+ // Get the true length of the data.
+ dataLength = gct.dataLength - gct.rightShift ;
+
+ // Read in red, green, blue, and possibly alpha.
+ r = currentHeader & BMASK[6 - gct.tagLength] ;
+ a = 0 ;
+
+ if (gct.tagLength + dataLength == 6) {
+ g = getBits(dataLength, "g") ;
+ b = getBits(dataLength, "b") ;
+ if (doingAlpha)
+ a = getBits(dataLength, "a") ;
+ }
+ else if (gct.tagLength + dataLength < 6) {
+ r = r >> (6 - gct.tagLength - dataLength) ;
+
+ g = currentHeader & BMASK[6-gct.tagLength-dataLength] ;
+ if (gct.tagLength + 2*dataLength == 6) {
+ b = getBits(dataLength, "b") ;
+ if (doingAlpha)
+ a = getBits(dataLength, "a") ;
+ }
+ else if (gct.tagLength + 2*dataLength < 6) {
+ g = g >> (6 - gct.tagLength - 2*dataLength) ;
+
+ b = currentHeader & BMASK[6-gct.tagLength-2*dataLength] ;
+ if (gct.tagLength + 3*dataLength == 6) {
+ if (doingAlpha)
+ a = getBits(dataLength, "a") ;
+ }
+ else if (gct.tagLength + 3*dataLength < 6) {
+ b = b >> (6 - gct.tagLength - 3*dataLength) ;
+
+ if (doingAlpha) {
+ a = currentHeader &
+ BMASK[6 - gct.tagLength - 4*dataLength] ;
+ if (gct.tagLength + 4 * dataLength < 6) {
+ a = a >> (6 - gct.tagLength - 3*dataLength) ;
+ }
+ else if (gct.tagLength + 4 * dataLength > 6) {
+ ii = getBits(dataLength -
+ (6-gct.tagLength - 3*dataLength), "a") ;
+ a = (a << (dataLength -
+ (6-gct.tagLength - 3*dataLength))) | ii ;
+ }
+ }
+ } else {
+ ii = getBits(dataLength -
+ (6 - gct.tagLength - 2*dataLength), "b") ;
+ b = (b << (dataLength -
+ (6 - gct.tagLength - 2*dataLength))) | ii ;
+ if (doingAlpha)
+ a = getBits(dataLength, "a") ;
+ }
+ } else {
+ ii = getBits(dataLength - (6 - gct.tagLength - dataLength),
+ "g") ;
+ g = (g << (dataLength -
+ (6 - gct.tagLength - dataLength))) | ii ;
+ b = getBits(dataLength, "b") ;
+ if (doingAlpha)
+ a = getBits(dataLength, "a") ;
+ }
+ } else {
+ ii = getBits(dataLength - (6 - gct.tagLength), "r") ;
+ r = (r << (dataLength - (6 - gct.tagLength))) | ii ;
+ g = getBits(dataLength, "g") ;
+ b = getBits(dataLength, "b") ;
+ if (doingAlpha)
+ a = getBits(dataLength, "a") ;
+ }
+
+ // Sign extend delta x y z components.
+ r <<= (32 - dataLength) ; r >>= (32 - dataLength) ;
+ g <<= (32 - dataLength) ; g >>= (32 - dataLength) ;
+ b <<= (32 - dataLength) ; b >>= (32 - dataLength) ;
+ a <<= (32 - dataLength) ; a >>= (32 - dataLength) ;
+
+ // Normalize values.
+ dr = (short)(r << gct.rightShift) ;
+ dg = (short)(g << gct.rightShift) ;
+ db = (short)(b << gct.rightShift) ;
+ da = (short)(a << gct.rightShift) ;
+
+ // Update current position, first adding deltas if in relative mode.
+ if (gct.absolute != 0) {
+ curR = dr ; curG = dg ; curB = db ;
+ if (doingAlpha) curA = da ;
+ if (debug) System.out.println(" absolute color: r " + curR +
+ " g " + curG + " b " + curB +
+ " a " + curA) ;
+ } else {
+ curR += dr ; curG += dg ; curB += db ;
+ if (doingAlpha) curA += da ;
+ if (debug) System.out.println(" delta color: dr " + dr +
+ " dg " + dg + " db " + db +
+ " da " + da) ;
+ }
+
+ // Do optional mesh buffer push.
+ if (mbp != 0) {
+ if (debug)
+ System.out.println(" pushing color into mesh buffer at " +
+ meshIndex) ;
+
+ meshBuffer[meshIndex].r = curR ;
+ meshBuffer[meshIndex].g = curG ;
+ meshBuffer[meshIndex].b = curB ;
+ meshBuffer[meshIndex].a = curA ;
+ }
+
+ // Convert point back to [-1..1] floating point.
+ fR = curR ; fR /= 32768.0 ;
+ fG = curG ; fG /= 32768.0 ;
+ fB = curB ; fB /= 32768.0 ;
+ fA = curA ; fA /= 32768.0 ;
+
+ curColor.set(fR, fG, fB, fA) ;
+ if (debug) System.out.println(" result color: " + fR +
+ " " + fG + " " + fB + " " + fA) ;
+
+ // A set color opcode when colors aren't bundled with the vertices
+ // is a global color change.
+ if (! bundlingColor) outputColor(curColor) ;
+ }
+
+
+ //
+ // Process a mesh buffer reference command.
+ //
+ private void processMeshBR() {
+ MeshBufferEntry entry ;
+ int index, normal ;
+ int ii ;
+
+ if (debug)
+ System.out.println("GeometryDecompressor.processMeshBR") ;
+
+ ii = getBits(1, "mbr") ;
+
+ index = (currentHeader >>> 1) & 0xF ;
+ repCode = ((currentHeader & 0x1) << 1) | ii ;
+
+ // Adjust index to proper place in fifo.
+ index = (meshIndex - index) & 0xf ;
+ if (debug)
+ System.out.println(" using index " + index) ;
+
+ // Get reference to mesh buffer entry.
+ entry = meshBuffer[index] ;
+ curX = entry.x ;
+ curY = entry.y ;
+ curZ = entry.z ;
+
+ // Convert point back to [-1..1] floating point.
+ curPos.set(((float)curX)/32768.0f,
+ ((float)curY)/32768.0f,
+ ((float)curZ)/32768.0f) ;
+
+ if (debug) System.out.println(" retrieved position " + curPos.x +
+ " " + curPos.y + " " + curPos.z +
+ " replace code " + repCode) ;
+
+ // Get mesh buffer normal if previous opcode was not a setNormal.
+ if (bundlingNorm && ((meshState & USE_MESH_NORMAL) != 0)) {
+ curSex = entry.sextant ;
+ curOct = entry.octant ;
+ curU = entry.u ;
+ curV = entry.v ;
+
+ // Convert normal back to -1.0 - 1.0 floating point from index.
+ normal = (curSex<<15) | (curOct<<12) | (curU<<6) | curV ;
+
+ if (debug) System.out.println(" retrieving normal") ;
+ indexNormal(curSex, curOct, curU, curV, curNorm) ;
+ }
+
+ // Get mesh buffer color if previous opcode was not a setColor.
+ if (bundlingColor && ((meshState & USE_MESH_COLOR) != 0)) {
+ curR = entry.r ;
+ curG = entry.g ;
+ curB = entry.b ;
+
+ // Convert point back to -1.0 - 1.0 floating point.
+ curColor.x = curR ; curColor.x /= 32768.0 ;
+ curColor.y = curG ; curColor.y /= 32768.0 ;
+ curColor.z = curB ; curColor.z /= 32768.0 ;
+
+ if (doingAlpha) {
+ curA = entry.a ;
+ curColor.w = curA ; curColor.w /= 32768.0 ;
+ }
+ if (debug)
+ System.out.println(" retrieved color " + curColor.x +
+ " " + curColor.y + " " + curColor.z +
+ " " + curColor.w) ;
+ }
+
+ // Reset meshState.
+ meshState = 0 ;
+ }
+
+
+ // Process a end-of-stream opcode.
+ private void processEos() {
+ if (debug) System.out.println("GeometryDecompressor.processEos") ;
+ }
+
+ // Process a variable length no-op opcode.
+ private void processVNoop() {
+ int ii, ct ;
+ if (debug) System.out.println("GeometryDecompressor.processVNoop") ;
+
+ ct = getBits(5, "noop count") ;
+ ii = getBits(ct, "noop bits") ;
+ }
+
+ // Process a pass-through opcode.
+ private void processPassThrough() {
+ int ignore ;
+ if (debug)
+ System.out.println("GeometryDecompressor.processPassThrough") ;
+
+ ignore = getBits(24, "passthrough") ;
+ ignore = getBits(32, "passthrough") ;
+ }
+
+ // Process a skip-8 opcode.
+ private void processSkip8() {
+ int skip ;
+ if (debug) System.out.println("GeometryDecompressor.processSkip8") ;
+
+ skip = getBits(8, "skip8") ;
+ }
+
+ private void benchmarkStart(int length) {
+ vertexCount = 0 ;
+ System.out.println(" GeometryDecompressor: decompressing " +
+ length + " bytes...") ;
+ startTime = System.currentTimeMillis() ;
+ }
+
+ private void benchmarkPrint(int length) {
+ float t = (System.currentTimeMillis() - startTime) / 1000.0f ;
+ System.out.println
+ (" done in " + t + " sec." + "\n" +
+ " decompressed " + vertexCount + " vertices at " +
+ (vertexCount/t) + " vertices/sec\n") ;
+
+ System.out.print(" vertex data present: coords") ;
+ int floatVertexSize = 12 ;
+ if (bundlingNorm) {
+ System.out.print(" normals") ;
+ floatVertexSize += 12 ;
+ }
+ if (bundlingColor) {
+ System.out.println(" colors") ;
+ floatVertexSize += 12 ;
+ }
+ if (doingAlpha) {
+ System.out.println(" alpha") ;
+ floatVertexSize += 4 ;
+ }
+ System.out.println() ;
+
+ System.out.println
+ (" bytes of data in generalized strip output: " +
+ (vertexCount * floatVertexSize) + "\n" +
+ " compression ratio: " +
+ (length / (float)(vertexCount * floatVertexSize)) + "\n") ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeometryDecompressorShape3D.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeometryDecompressorShape3D.java
new file mode 100644
index 0000000..56fc372
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/GeometryDecompressorShape3D.java
@@ -0,0 +1,525 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import java.util.ArrayList;
+
+import org.jogamp.java3d.Appearance;
+import org.jogamp.java3d.CompressedGeometry;
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.GeometryStripArray;
+import org.jogamp.java3d.LineStripArray;
+import org.jogamp.java3d.Material;
+import org.jogamp.java3d.PointArray;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.java3d.TriangleArray;
+import org.jogamp.java3d.TriangleStripArray;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3f;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+/**
+ * This class implements a Shape3D backend for the abstract
+ * GeometryDecompressor.
+ */
+class GeometryDecompressorShape3D extends GeometryDecompressor {
+ private static final boolean debug = false ;
+ private static final boolean benchmark = false ;
+ private static final boolean statistics = false ;
+ private static final boolean printInfo = debug || benchmark || statistics ;
+
+ // Type of connections in the compressed data:
+ // TYPE_POINT (1), TYPE_LINE (2), or TYPE_TRIANGLE (4).
+ private int bufferDataType ;
+
+ // Data bundled with each vertex: bitwise combination of
+ // NORMAL_IN_BUFFER (1), COLOR_IN_BUFFER (2), ALPHA_IN_BUFFER (4).
+ private int dataPresent ;
+
+ // List for accumulating the output of the decompressor and converting to
+ // GeometryArray representations.
+ private GeneralizedVertexList vlist ;
+
+ // Accumulates Shape3D objects constructed from decompressor output.
+ private ArrayList shapes ;
+
+ // Decompressor output state variables.
+ private Color4f curColor ;
+ private Vector3f curNormal ;
+
+ // Variables for gathering statistics.
+ private int origVertexCount ;
+ private int stripCount ;
+ private int vertexCount ;
+ private int triangleCount ;
+ private long startTime ;
+ private long endTime ;
+
+ // Triangle array type to construct.
+ private int triOutputType ;
+
+ // Types of triangle output available.
+ private static final int TRI_SET = 0 ;
+ private static final int TRI_STRIP_SET = 1 ;
+ private static final int TRI_STRIP_AND_FAN_SET = 2 ;
+ private static final int TRI_STRIP_AND_TRI_SET = 3 ;
+
+ // Private convenience copies of various constants.
+ private static final int TYPE_POINT =
+ CompressedGeometryRetained.TYPE_POINT ;
+ private static final int TYPE_LINE =
+ CompressedGeometryRetained.TYPE_LINE ;
+ private static final int TYPE_TRIANGLE =
+ CompressedGeometryRetained.TYPE_TRIANGLE ;
+ private static final int FRONTFACE_CCW =
+ GeneralizedStripFlags.FRONTFACE_CCW ;
+
+ /**
+ * Decompress the given compressed geometry.
+ * @param cgr CompressedGeometryRetained object with compressed geometry
+ * @return an array of Shape3D with TriangleArray geometry if compressed
+ * data contains triangles; otherwise, Shape3D array containing PointArray
+ * or LineStripArray geometry
+ * @see CompressedGeometry
+ * @see GeometryDecompressor
+ */
+ Shape3D[] toTriangleArrays(CompressedGeometryRetained cgr) {
+ return decompress(cgr, TRI_SET) ;
+ }
+
+
+ /**
+ * Decompress the given compressed geometry.
+ * @param cgr CompressedGeometryRetained object with compressed geometry
+ * @return an array of Shape3D with TriangleStripArray geometry if
+ * compressed data contains triangles; otherwise, Shape3D array containing
+ * PointArray or LineStripArray geometry
+ * @see CompressedGeometry
+ * @see GeometryDecompressor
+ */
+ Shape3D[] toTriangleStripArrays(CompressedGeometryRetained cgr) {
+ return decompress(cgr, TRI_STRIP_SET) ;
+ }
+
+
+ /**
+ * Decompress the given compressed geometry.
+ * @param cgr CompressedGeometryRetained object with compressed geometry
+ * @return an array of Shape3D with TriangleStripArray and
+ * TriangleFanArray geometry if compressed data contains triangles;
+ * otherwise, Shape3D array containing PointArray or LineStripArray
+ * geometry
+ * @see CompressedGeometry
+ * @see GeometryDecompressor
+ */
+ Shape3D[] toStripAndFanArrays(CompressedGeometryRetained cgr) {
+ return decompress(cgr, TRI_STRIP_AND_FAN_SET) ;
+ }
+
+
+ /**
+ * Decompress the given compressed geometry.
+ * @param cgr CompressedGeometryRetained object with compressed geometry
+ * @return an array of Shape3D with TriangleStripArray and
+ * TriangleArray geometry if compressed data contains triangles;
+ * otherwise, Shape3D array containing PointArray or LineStripArray
+ * geometry
+ * @see CompressedGeometry
+ * @see GeometryDecompressor
+ */
+ Shape3D[] toStripAndTriangleArrays(CompressedGeometryRetained cgr) {
+ return decompress(cgr, TRI_STRIP_AND_TRI_SET) ;
+ }
+
+ /**
+ * Decompress the data contained in a CompressedGeometryRetained and
+ * return an array of Shape3D objects using the specified triangle output
+ * type. The triangle output type is ignored if the compressed data
+ * contains points or lines.
+ */
+ private Shape3D[] decompress(CompressedGeometryRetained cgr,
+ int triOutputType) {
+
+ if (! checkVersion(cgr.majorVersionNumber, cgr.minorVersionNumber)) {
+ return null ;
+ }
+
+ vlist = null ;
+ curColor = null ;
+ curNormal = null ;
+
+ // Get descriptors for compressed data.
+ bufferDataType = cgr.bufferType ;
+ dataPresent = cgr.bufferContents ;
+ if (printInfo) beginPrint() ;
+
+ // Initialize the decompressor backend.
+ this.triOutputType = triOutputType ;
+ shapes = new ArrayList() ;
+
+ // Call the superclass decompress() method which calls the output
+ // methods of this subclass. The results are stored in vlist.
+ super.decompress(cgr.offset, cgr.size, cgr.compressedGeometry) ;
+
+ // Convert the decompressor output to Shape3D objects.
+ addShape3D() ;
+ if (printInfo) endPrint() ;
+
+ // Return the fixed-length output array.
+ Shape3D shapeArray[] = new Shape3D[shapes.size()] ;
+ return (Shape3D[])shapes.toArray(shapeArray) ;
+ }
+
+ /**
+ * Initialize the vertex output list based on the vertex format provided
+ * by the SetState decompression command.
+ */
+ @Override
+ void outputVertexFormat(boolean bundlingNorm, boolean bundlingColor,
+ boolean doingAlpha) {
+
+ if (vlist != null)
+ // Construct shapes using the current vertex format.
+ addShape3D() ;
+
+ int vertexFormat = GeometryArray.COORDINATES ;
+
+ if (bundlingNorm) {
+ vertexFormat |= GeometryArray.NORMALS ;
+ }
+
+ if (bundlingColor) {
+ if (doingAlpha) {
+ vertexFormat |= GeometryArray.COLOR_4;
+ } else {
+ vertexFormat |= GeometryArray.COLOR_3;
+ }
+ }
+
+ vlist = new GeneralizedVertexList(vertexFormat, FRONTFACE_CCW) ;
+ }
+
+ /**
+ * Add a new decompressed vertex to the current list.
+ */
+ @Override
+ void outputVertex(Point3f position, Vector3f normal,
+ Color4f color, int vertexReplaceCode) {
+
+ if (curNormal != null) normal = curNormal ;
+ vlist.addVertex(position, normal, color, vertexReplaceCode) ;
+
+ if (debug) {
+ System.out.println(" outputVertex: flag " + vertexReplaceCode) ;
+ System.out.println(" position " + position.toString()) ;
+ if (normal != null)
+ System.out.println(" normal " + normal.toString()) ;
+ if (color != null)
+ System.out.println(" color " + color.toString()) ;
+ }
+ }
+
+ /**
+ * Create a Shape3D using the current color for both the ambient and
+ * diffuse material colors, then start a new vertex list for the new
+ * color. The outputColor() method is never called if colors are bundled
+ * with each vertex in the compressed buffer.
+ */
+ @Override
+ void outputColor(Color4f color) {
+ if (debug) System.out.println(" outputColor: " + color.toString()) ;
+
+ if (vlist.size() > 0) {
+ // Construct Shape3D using the current color.
+ addShape3D() ;
+
+ // Start a new vertex list for the new color.
+ vlist = new GeneralizedVertexList(vlist.vertexFormat,
+ FRONTFACE_CCW) ;
+ }
+ if (curColor == null) curColor = new Color4f() ;
+ curColor.set(color) ;
+ }
+
+ /**
+ * Set the current normal that will be copied to each succeeding vertex
+ * output by the decompressor. The per-vertex copy is needed since in
+ * Java 3D a normal is always associated with a vertex. This method is
+ * never called if normals are bundled with each vertex in the compressed
+ * buffer.
+ */
+ @Override
+ void outputNormal(Vector3f normal) {
+ if (debug) System.out.println(" outputNormal: " + normal.toString()) ;
+
+ if ((vlist.vertexFormat & GeometryArray.NORMALS) == 0) {
+ if (vlist.size() > 0)
+ // Construct Shape3D using the current vertex format.
+ addShape3D() ;
+
+ // Start a new vertex list with the new format.
+ vlist = new GeneralizedVertexList
+ (vlist.vertexFormat|GeometryArray.NORMALS, FRONTFACE_CCW) ;
+ }
+ if (curNormal == null) curNormal = new Vector3f() ;
+ curNormal.set(normal) ;
+ }
+
+ /**
+ * Create a Shape3D object of the desired type from the current vertex
+ * list. Apply the current color, if non-null, as a Material attribute.
+ */
+ private void addShape3D() {
+ Material m = new Material() ;
+
+ if (curColor != null) {
+ if ((vlist.vertexFormat & GeometryArray.COLOR_4) != GeometryArray.COLOR_4) {
+ m.setAmbientColor(curColor.x, curColor.y, curColor.z) ;
+ m.setDiffuseColor(curColor.x, curColor.y, curColor.z) ;
+ }
+ else {
+ m.setAmbientColor(curColor.x, curColor.y, curColor.z) ;
+ m.setDiffuseColor(curColor.x, curColor.y, curColor.z,
+ curColor.w) ;
+ }
+ }
+
+ if ((vlist.vertexFormat & GeometryArray.NORMALS) == 0)
+ m.setLightingEnable(false) ;
+ else
+ m.setLightingEnable(true) ;
+
+ Appearance a = new Appearance() ;
+ a.setMaterial(m) ;
+
+ switch(bufferDataType) {
+ case TYPE_TRIANGLE:
+ switch(triOutputType) {
+ case TRI_SET:
+ TriangleArray ta = vlist.toTriangleArray() ;
+ if (ta != null)
+ shapes.add(new Shape3D(ta, a)) ;
+ break ;
+ case TRI_STRIP_SET:
+ TriangleStripArray tsa = vlist.toTriangleStripArray() ;
+ if (tsa != null)
+ shapes.add(new Shape3D(tsa, a)) ;
+ break ;
+ case TRI_STRIP_AND_FAN_SET:
+ GeometryStripArray gsa[] = vlist.toStripAndFanArrays() ;
+ if (gsa[0] != null)
+ shapes.add(new Shape3D(gsa[0], a)) ;
+ if (gsa[1] != null)
+ shapes.add(new Shape3D(gsa[1], a)) ;
+ break ;
+ case TRI_STRIP_AND_TRI_SET:
+ GeometryArray ga[] = vlist.toStripAndTriangleArrays() ;
+ if (ga[0] != null)
+ shapes.add(new Shape3D(ga[0], a)) ;
+ if (ga[1] != null)
+ shapes.add(new Shape3D(ga[1], a)) ;
+ break ;
+ default:
+ throw new IllegalArgumentException
+ (J3dUtilsI18N.getString("GeometryDecompressorShape3D0")) ;
+ }
+ break ;
+
+ case TYPE_LINE:
+ LineStripArray lsa = vlist.toLineStripArray() ;
+ if (lsa != null)
+ shapes.add(new Shape3D(lsa, a)) ;
+ break ;
+
+ case TYPE_POINT:
+ PointArray pa = vlist.toPointArray() ;
+ if (pa != null)
+ shapes.add(new Shape3D(pa, a)) ;
+ break ;
+
+ default:
+ throw new IllegalArgumentException
+ (J3dUtilsI18N.getString("GeometryDecompressorShape3D1")) ;
+ }
+
+ if (benchmark || statistics) {
+ origVertexCount += vlist.size() ;
+ vertexCount += vlist.vertexCount ;
+ stripCount += vlist.stripCount ;
+ triangleCount += vlist.triangleCount ;
+ }
+ }
+
+ private void beginPrint() {
+ System.out.println("\nGeometryDecompressorShape3D") ;
+
+ switch(bufferDataType) {
+ case TYPE_TRIANGLE:
+ System.out.println(" buffer TYPE_TRIANGLE") ;
+ break ;
+ case TYPE_LINE:
+ System.out.println(" buffer TYPE_LINE") ;
+ break ;
+ case TYPE_POINT:
+ System.out.println(" buffer TYPE_POINT") ;
+ break ;
+ default:
+ throw new IllegalArgumentException
+ (J3dUtilsI18N.getString("GeometryDecompressorShape3D1")) ;
+ }
+
+ System.out.print(" buffer data present: coords") ;
+
+ if ((dataPresent & CompressedGeometryData.Header.NORMAL_IN_BUFFER) != 0)
+ System.out.print(" normals") ;
+ if ((dataPresent & CompressedGeometryData.Header.COLOR_IN_BUFFER) != 0)
+ System.out.print(" colors") ;
+ if ((dataPresent & CompressedGeometryData.Header.ALPHA_IN_BUFFER) != 0)
+ System.out.print(" alpha") ;
+
+ System.out.println() ;
+
+ stripCount = 0 ;
+ vertexCount = 0 ;
+ triangleCount = 0 ;
+ origVertexCount = 0 ;
+
+ startTime = System.currentTimeMillis() ;
+ }
+
+ private void endPrint() {
+ endTime = System.currentTimeMillis() ;
+
+ if (benchmark || statistics)
+ printBench() ;
+
+ if (statistics)
+ printStats() ;
+ }
+
+ private void printBench() {
+ float t = (endTime - startTime) / 1000.0f ;
+ System.out.println
+ (" decompression + strip conversion took " + t + " sec.") ;
+
+ switch(bufferDataType) {
+ case TYPE_POINT:
+ System.out.println
+ (" points decompressed: " + vertexCount + "\n" +
+ " net decompression rate: " + (vertexCount/t) +
+ " points/sec.\n") ;
+ break ;
+ case TYPE_LINE:
+ System.out.println
+ (" lines decompressed: " + (vertexCount - stripCount) + "\n" +
+ " net decompression rate: " + ((vertexCount - stripCount)/t) +
+ " lines/sec.\n") ;
+ break ;
+ case TYPE_TRIANGLE:
+ System.out.println
+ (" triangles decompressed: " +
+ (vertexCount - 2*stripCount) + "\n" +
+ " net decompression rate: " +
+ ((vertexCount - 2*stripCount)/t) + " triangles/sec.\n") ;
+ break ;
+ }
+ }
+
+ private void printStats() {
+ switch(triOutputType) {
+ case TRI_SET:
+ System.out.println(" using individual triangle output") ;
+ break ;
+ case TRI_STRIP_SET:
+ System.out.println(" using strip output") ;
+ break ;
+ case TRI_STRIP_AND_FAN_SET:
+ System.out.println(" using strips and fans for output") ;
+ break ;
+ case TRI_STRIP_AND_TRI_SET:
+ System.out.println(" using strips and triangles for output") ;
+ break ;
+ }
+
+ System.out.print
+ (" number of Shape3D objects: " + shapes.size() +
+ "\n number of Shape3D decompressed vertices: ") ;
+
+ if (triOutputType == TRI_SET || bufferDataType == TYPE_POINT) {
+ System.out.println(vertexCount) ;
+ }
+ else if (triOutputType == TRI_STRIP_AND_TRI_SET) {
+ System.out.println((vertexCount + triangleCount*3) +
+ "\n number of strips: " + stripCount +
+ "\n number of individual triangles: " +
+ triangleCount) ;
+ if (stripCount > 0)
+ System.out.println
+ (" vertices/strip: " + (float)vertexCount/stripCount +
+ "\n triangles represented in strips: " +
+ (vertexCount - 2*stripCount)) ;
+ }
+ else {
+ System.out.println(vertexCount +
+ "\n number of strips: " + stripCount) ;
+ if (stripCount > 0)
+ System.out.println
+ (" vertices/strip: " + (float)vertexCount/stripCount) ;
+ }
+
+ System.out.print(" vertex data present in last Shape3D: coords") ;
+ if ((vlist.vertexFormat & GeometryArray.NORMALS) != 0)
+ System.out.print(" normals") ;
+
+ boolean color4 =
+ (vlist.vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4;
+ boolean color3 = !color4 &&
+ (vlist.vertexFormat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3;
+ if (color3 || color4) {
+ System.out.print(" colors") ;
+ if (color4)
+ System.out.print(" alpha") ;
+ }
+ System.out.println() ;
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/HuffmanNode.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/HuffmanNode.java
new file mode 100644
index 0000000..6ae24ff
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/HuffmanNode.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import java.util.Collection;
+import java.util.Comparator;
+
+/**
+ * Instances of this class are used as the nodes of binary trees representing
+ * mappings of tags to compression stream elements. Tags are descriptors
+ * inserted into the compression command stream that specify the encoding of
+ * immediately succeeding data elements.
+ *
+ * The tag assignments in such a tree are computed from the paths taken from
+ * the root to the leaf nodes. Each leaf node represents the particular way
+ * one or more compression stream elements wound up being encoded with respect
+ * to various combinations of data lengths, shifts, and absolute/relative
+ * status.
+ *
+ * Huffman's algorithm for constructing binary trees with minimal weighted
+ * path lengths can be used to optimize the bit lengths of the tags with
+ * respect to the frequency of occurrence of their associated data encodings
+ * in the compression stream. The weighted path length is the sum of the
+ * frequencies of all the leaf nodes times their path lengths to the root of
+ * the tree.
+ *
+ * The length of the longest tag determines the size of the table mapping tags
+ * to data representations. The geometry compression specification limits the
+ * size of the table to 64 entries, so tags cannot be longer than 6 bits. The
+ * depth of the tree is reduced through a process of increasing the data
+ * lengths of less frequently occuring nodes so they can be merged with other
+ * more frequent nodes.
+ */
+class HuffmanNode {
+ int tag, tagLength ;
+ int shift, dataLength ;
+ boolean absolute ;
+
+ private int frequency ;
+ private HuffmanNode child0, child1, mergeNode ;
+ private boolean merged, unmergeable, cleared ;
+
+ void clear() {
+ tag = -1 ;
+ tagLength = -1 ;
+
+ shift = -1 ;
+ dataLength = -1 ;
+ absolute = false ;
+
+ child0 = null ;
+ child1 = null ;
+ mergeNode = null ;
+
+ frequency = 0 ;
+ merged = false ;
+ unmergeable = false ;
+ cleared = true ;
+ }
+
+ HuffmanNode() {
+ clear() ;
+ }
+
+ HuffmanNode(int length, int shift, boolean absolute) {
+ this() ;
+ set(length, shift, absolute) ;
+ }
+
+ final void set(int length, int shift, boolean absolute) {
+ this.dataLength = length ;
+ this.shift = shift ;
+ this.absolute = absolute ;
+ this.cleared = false ;
+ }
+
+ final boolean cleared() {
+ return cleared ;
+ }
+
+ final void addCount() {
+ frequency++ ;
+ }
+
+ final boolean hasCount() {
+ return frequency > 0 ;
+ }
+
+ final boolean tokenEquals(HuffmanNode node) {
+ return
+ this.absolute == node.absolute &&
+ this.dataLength == node.dataLength &&
+ this.shift == node.shift ;
+ }
+
+ void addChildren(HuffmanNode child0, HuffmanNode child1) {
+ this.child0 = child0 ;
+ this.child1 = child1 ;
+ this.frequency = child0.frequency + child1.frequency ;
+ }
+
+ void collectLeaves(int tag, int tagLength, Collection collection) {
+ if (child0 == null) {
+ this.tag = tag ;
+ this.tagLength = tagLength ;
+ collection.add(this) ;
+ } else {
+ child0.collectLeaves((tag << 1) | 0, tagLength + 1, collection) ;
+ child1.collectLeaves((tag << 1) | 1, tagLength + 1, collection) ;
+ }
+ }
+
+ boolean mergeInto(HuffmanNode node) {
+ if (this.absolute == node.absolute) {
+ if (this.dataLength > node.dataLength)
+ node.dataLength = this.dataLength ;
+
+ if (this.shift < node.shift)
+ node.shift = this.shift ;
+
+ node.frequency += this.frequency ;
+ this.mergeNode = node ;
+ this.merged = true ;
+ return true ;
+
+ } else
+ return false ;
+ }
+
+ int incrementLength() {
+ if (shift > 0)
+ shift-- ;
+ else
+ dataLength++ ;
+
+ return dataLength - shift ;
+ }
+
+ final boolean merged() {
+ return merged ;
+ }
+
+ final HuffmanNode getMergeNode() {
+ return mergeNode ;
+ }
+
+ void setUnmergeable() {
+ unmergeable = true ;
+ }
+
+ final boolean unmergeable() {
+ return unmergeable ;
+ }
+
+ @Override
+ public String toString() {
+ return
+ "shift " + shift + " data length " + dataLength +
+ (absolute? " absolute " : " relative ") +
+ "\ntag 0x" + Integer.toHexString(tag) + " tag length " + tagLength +
+ "\nfrequency: " + frequency ;
+ }
+
+ /**
+ * Sorts nodes in ascending order by frequency.
+ */
+ static class FrequencyComparator implements Comparator {
+ @Override
+ public final int compare(Object o1, Object o2) {
+ return ((HuffmanNode)o1).frequency - ((HuffmanNode)o2).frequency ;
+ }
+ }
+
+ /**
+ * Sorts nodes in descending order by tag bit length.
+ */
+ static class TagLengthComparator implements Comparator {
+ @Override
+ public final int compare(Object o1, Object o2) {
+ return ((HuffmanNode)o2).tagLength - ((HuffmanNode)o1).tagLength ;
+ }
+ }
+
+ static FrequencyComparator frequencyComparator = new FrequencyComparator() ;
+ static TagLengthComparator tagLengthComparator = new TagLengthComparator() ;
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/HuffmanTable.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/HuffmanTable.java
new file mode 100644
index 0000000..cb88872
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/HuffmanTable.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+/**
+ * This class maintains a map from compression stream elements (tokens) onto
+ * HuffmanNode objects. A HuffmanNode contains a tag describing the
+ * associated token's data length, right shift value, and absolute/relative
+ * status.
+ *
+ * The tags are computed using Huffman's algorithm to build a binary tree with
+ * a minimal total weighted path length. The frequency of each token is
+ * used as its node's weight when building the tree. The path length from the
+ * root to the token's node then indicates the bit length that should be used
+ * for that token's tag in order to minimize the total size of the compressed
+ * stream.
+ */
+class HuffmanTable {
+ private static final int MAX_TAG_LENGTH = 6 ;
+
+ private HuffmanNode positions[] ;
+ private HuffmanNode normals[] ;
+ private HuffmanNode colors[] ;
+
+ /**
+ * Create a new HuffmanTable with entries for all possible position,
+ * normal, and color tokens.
+ */
+ HuffmanTable() {
+ //
+ // Position and color components can have data lengths up to 16
+ // bits, with right shifts up to 15 bits. The position and color
+ // lookup tables are therefore 2*17*16=544 entries in length to
+ // account for all possible combinations of data lengths, shifts,
+ // and relative or absolute status.
+ //
+ colors = new HuffmanNode[544] ;
+ positions = new HuffmanNode[544] ;
+
+ //
+ // Delta normals can have uv components up to 7 bits in length with
+ // right shifts up to 6 bits. Absolute normals can have uv components
+ // up to 6 bits in length with right shifts up to 5 bits. The normal
+ // lookup table is therefore 2*8*7=112 entries in length.
+ //
+ normals = new HuffmanNode[112] ;
+ }
+
+ private final int getPositionIndex(int len, int shift, boolean absolute) {
+ return (absolute? 1:0)*272 + len*16 + shift ;
+ }
+
+ private final int getNormalIndex(int length, int shift, boolean absolute) {
+ return (absolute? 1:0)*56 + length*7 + shift ;
+ }
+
+ private final int getColorIndex(int length, int shift, boolean absolute) {
+ return getPositionIndex(length, shift, absolute) ;
+ }
+
+
+ /**
+ * Add a position entry with the given length, shift, and absolute
+ * status.
+ *
+ * @param length number of bits in each X, Y, and Z component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous vertex in the compression stream
+ */
+ void addPositionEntry(int length, int shift, boolean absolute) {
+ addEntry(positions, getPositionIndex(length, shift, absolute),
+ length, shift, absolute) ;
+ }
+
+ /**
+ * Get the position entry associated with the specified length, shift, and
+ * absolute status. This will contain a tag indicating the actual
+ * encoding to be used in the compression command stream, not necessarily
+ * the same as the original length and shift with which the the entry was
+ * created.
+ *
+ * @param length number of bits in each X, Y, and Z component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous vertex in the compression stream
+ * @return HuffmanNode mapped to the specified parameters
+ */
+ HuffmanNode getPositionEntry(int length, int shift, boolean absolute) {
+ return getEntry(positions, getPositionIndex(length, shift, absolute)) ;
+ }
+
+ /**
+ * Add a color entry with the given length, shift, and absolute
+ * status.
+ *
+ * @param length number of bits in each R, G, B, and A component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous color in the compression stream
+ */
+ void addColorEntry(int length, int shift, boolean absolute) {
+ addEntry(colors, getColorIndex(length, shift, absolute),
+ length, shift, absolute) ;
+ }
+
+ /**
+ * Get the color entry associated with the specified length, shift, and
+ * absolute status. This will contain a tag indicating the actual
+ * encoding to be used in the compression command stream, not necessarily
+ * the same as the original length and shift with which the the entry was
+ * created.
+ *
+ * @param length number of bits in each R, G, B, and A component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous color in the compression stream
+ * @return HuffmanNode mapped to the specified parameters
+ */
+ HuffmanNode getColorEntry(int length, int shift, boolean absolute) {
+ return getEntry(colors, getColorIndex(length, shift, absolute)) ;
+ }
+
+ /**
+ * Add a normal entry with the given length, shift, and absolute
+ * status.
+ *
+ * @param length number of bits in each U and V component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous normal in the compression stream
+ */
+ void addNormalEntry(int length, int shift, boolean absolute) {
+ addEntry(normals, getNormalIndex(length, shift, absolute),
+ length, shift, absolute) ;
+ }
+
+ /**
+ * Get the normal entry associated with the specified length, shift, and
+ * absolute status. This will contain a tag indicating the actual
+ * encoding to be used in the compression command stream, not necessarily
+ * the same as the original length and shift with which the the entry was
+ * created.
+ *
+ * @param length number of bits in each U and V component
+ * @param shift number of trailing zeros in each component
+ * @param absolute if false, value represented is a delta from the
+ * previous normal in the compression stream
+ * @return HuffmanNode mapped to the specified parameters
+ */
+ HuffmanNode getNormalEntry(int length, int shift, boolean absolute) {
+ return getEntry(normals, getNormalIndex(length, shift, absolute)) ;
+ }
+
+
+ private void addEntry(HuffmanNode table[], int index,
+ int length, int shift, boolean absolute) {
+
+ if (table[index] == null)
+ table[index] = new HuffmanNode(length, shift, absolute) ;
+
+ else if (table[index].cleared())
+ table[index].set(length, shift, absolute) ;
+
+ table[index].addCount() ;
+ }
+
+ private HuffmanNode getEntry(HuffmanNode table[], int index) {
+ HuffmanNode t = table[index] ;
+
+ while (t.merged())
+ t = t.getMergeNode() ;
+
+ return t ;
+ }
+
+ private void getEntries(HuffmanNode table[], Collection c) {
+ for (int i = 0 ; i < table.length ; i++)
+ if (table[i] != null && !table[i].cleared() &&
+ table[i].hasCount() && !table[i].merged())
+ c.add(table[i]) ;
+ }
+
+
+ /**
+ * Clear this HuffmanTable instance.
+ */
+ void clear() {
+ for (int i = 0 ; i < positions.length ; i++)
+ if (positions[i] != null)
+ positions[i].clear() ;
+
+ for (int i = 0 ; i < colors.length ; i++)
+ if (colors[i] != null)
+ colors[i].clear() ;
+
+ for (int i = 0 ; i < normals.length ; i++)
+ if (normals[i] != null)
+ normals[i].clear() ;
+ }
+
+ /**
+ * Compute optimized tags for each position, color, and normal entry.
+ */
+ void computeTags() {
+ LinkedList nodeList = new LinkedList() ;
+ getEntries(positions, nodeList) ;
+ computeTags(nodeList, 3) ;
+
+ nodeList.clear() ;
+ getEntries(colors, nodeList) ;
+ computeTags(nodeList, 3) ;
+
+ nodeList.clear() ;
+ getEntries(normals, nodeList) ;
+ computeTags(nodeList, 2) ;
+ }
+
+ //
+ // Compute tags for a list of Huffman tokens.
+ //
+ private void computeTags(LinkedList nodes, int minComponentCount) {
+ HuffmanNode node0, node1, node2 ;
+
+ // Return if there's nothing to do.
+ if (nodes.isEmpty())
+ return ;
+
+ while (true) {
+ // Sort the nodes in ascending order by frequency.
+ Collections.sort(nodes, HuffmanNode.frequencyComparator) ;
+
+ // Apply Huffman's algorithm to construct a binary tree with a
+ // minimum total weighted path length.
+ node0 = (HuffmanNode)nodes.removeFirst() ;
+ while (nodes.size() > 0) {
+ node1 = (HuffmanNode)nodes.removeFirst() ;
+ node2 = new HuffmanNode() ;
+
+ node2.addChildren(node0, node1) ;
+ addNodeInOrder(nodes, node2, HuffmanNode.frequencyComparator) ;
+
+ node0 = (HuffmanNode)nodes.removeFirst() ;
+ }
+
+ // node0 is the root of the resulting binary tree. Traverse it
+ // assigning tags and lengths to the leaf nodes. The leaves are
+ // collected into the now empty node list.
+ node0.collectLeaves(0, 0, nodes) ;
+
+ // Sort the nodes in descending order by tag length.
+ Collections.sort(nodes, HuffmanNode.tagLengthComparator) ;
+
+ // Check for tag length overrun.
+ if (((HuffmanNode)nodes.getFirst()).tagLength > MAX_TAG_LENGTH) {
+ // Tokens need to be merged and the tree rebuilt with the new
+ // combined frequencies.
+ merge(nodes) ;
+
+ } else {
+ // Increase tag length + data length if they're too small.
+ expand(nodes, minComponentCount) ;
+ break ;
+ }
+ }
+ }
+
+ //
+ // Merge a token with a long tag into some other token. The merged token
+ // will be removed from the list along with any duplicate node the merge
+ // created, reducing the size of the list by 1 or 2 elements until only
+ // unmergeable tokens are left.
+ //
+ private void merge(LinkedList nodes) {
+ ListIterator i = nodes.listIterator(0) ;
+ HuffmanNode node0, node1, node2 ;
+ int index = 0 ;
+
+ while (i.hasNext()) {
+ // Get the node with the longest possibly mergeable tag.
+ node0 = (HuffmanNode)i.next() ;
+ if (node0.unmergeable()) continue ;
+
+ // Try to find a node that can be merged with node0. This is any
+ // node that matches its absolute/relative status.
+ i.remove() ;
+ while (i.hasNext()) {
+ node1 = (HuffmanNode)i.next() ;
+ if (node0.mergeInto(node1)) {
+ // Search for a duplicate of the possibly modified node1
+ // and merge into it so that node weights remain valid.
+ // If a duplicate exists it must be further in the list,
+ // otherwise node0 would have merged into it.
+ i.remove() ;
+ while (i.hasNext()) {
+ node2 = (HuffmanNode)i.next() ;
+ if (node1.tokenEquals(node2)) {
+ node1.mergeInto(node2) ;
+ return ;
+ }
+ }
+ // node1 has no duplicate, so return it to the list.
+ i.add(node1) ;
+ return ;
+ }
+ }
+
+ // node0 can't be merged with any other node; it must be the only
+ // relative or absolute node in the list. Mark it as unmergeable
+ // to avoid unnecessary searches on subsequent calls to merge()
+ // and return it to the list.
+ node0.setUnmergeable() ;
+ i.add(node0) ;
+
+ // Restart the iteration.
+ i = nodes.listIterator(0) ;
+ }
+ }
+
+ //
+ // Empty bits within a compression command header are not allowed. If
+ // the tag length plus the total data length is less than 6 bits then
+ // the token's length must be increased.
+ //
+ private void expand(LinkedList nodes, int minComponentCount) {
+ Iterator i = nodes.iterator() ;
+
+ while (i.hasNext()) {
+ HuffmanNode n = (HuffmanNode)i.next() ;
+
+ while (n.tagLength +
+ (minComponentCount * (n.dataLength - n.shift)) < 6) {
+
+ n.incrementLength() ;
+ }
+ }
+ }
+
+ //
+ // Insert a node into the correct place in a sorted list of nodes.
+ //
+ private void addNodeInOrder(LinkedList l, HuffmanNode node, Comparator c) {
+ ListIterator i = l.listIterator(0) ;
+
+ while (i.hasNext()) {
+ HuffmanNode n = (HuffmanNode)i.next() ;
+ if (c.compare(n, node) > 0) {
+ n = (HuffmanNode)i.previous() ;
+ break ;
+ }
+ }
+ i.add(node) ;
+ }
+
+ /**
+ * Create compression stream commands for decompressors to use to set up
+ * their decompression tables.
+ *
+ * @param output CommandStream which receives the compression commands
+ */
+ void outputCommands(CommandStream output) {
+ LinkedList nodeList = new LinkedList() ;
+ getEntries(positions, nodeList) ;
+ outputCommands(nodeList, output, CommandStream.POSITION_TABLE) ;
+
+ nodeList.clear() ;
+ getEntries(colors, nodeList) ;
+ outputCommands(nodeList, output, CommandStream.COLOR_TABLE) ;
+
+ nodeList.clear() ;
+ getEntries(normals, nodeList) ;
+ outputCommands(nodeList, output, CommandStream.NORMAL_TABLE) ;
+ }
+
+ //
+ // Output a setTable command for each unique token.
+ //
+ private void outputCommands(Collection nodes,
+ CommandStream output, int tableId) {
+
+ Iterator i = nodes.iterator() ;
+ while (i.hasNext()) {
+ HuffmanNode n = (HuffmanNode)i.next() ;
+ int addressRange = (1 << n.tagLength) | n.tag ;
+ int dataLength = (n.dataLength == 16? 0 : n.dataLength) ;
+
+ int command =
+ CommandStream.SET_TABLE | (tableId << 1) | (addressRange >> 6) ;
+
+ long body =
+ ((addressRange & 0x3f) << 9) | (dataLength << 5) |
+ (n.absolute? 0x10 : 0) | n.shift ;
+
+ output.addCommand(command, 8, body, 15) ;
+ }
+ }
+
+ /**
+ * Print a collection of HuffmanNode objects to standard out.
+ *
+ * @param header descriptive string
+ * @param nodes Collection of HuffmanNode objects to print
+ */
+ void print(String header, Collection nodes) {
+ System.out.println(header + "\nentries: " + nodes.size() + "\n") ;
+
+ Iterator i = nodes.iterator() ;
+ while(i.hasNext()) {
+ HuffmanNode n = (HuffmanNode)i.next() ;
+ System.out.println(n.toString() + "\n") ;
+ }
+ }
+
+ /**
+ * Print the contents of this instance to standard out.
+ */
+ void print() {
+ LinkedList nodeList = new LinkedList() ;
+
+ getEntries(positions, nodeList) ;
+ Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
+ print("\nposition tokens and tags", nodeList) ;
+
+ nodeList.clear() ;
+ getEntries(colors, nodeList) ;
+ Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
+ print("\ncolor tokens and tags", nodeList) ;
+
+ nodeList.clear() ;
+ getEntries(normals, nodeList) ;
+ Collections.sort(nodeList, HuffmanNode.frequencyComparator) ;
+ print("\nnormal tokens and tags", nodeList) ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/MeshBuffer.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/MeshBuffer.java
new file mode 100644
index 0000000..ecfd53f
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/MeshBuffer.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * This class mirrors the vertex mesh buffer stack supported by the geometry
+ * compression semantics.
+ */
+class MeshBuffer {
+ //
+ // The fixed-length mesh buffer stack is represented by circular buffers.
+ // Three stack representations are provided: vertices, positions, and
+ // indices.
+ //
+ // The vertex representation stores references to CompressionStreamVertex
+ // objects. The position representation stores references to Point3f,
+ // Vector3f, Color3f, and Color4f objects, while the index representation
+ // stores indices into externally maintained arrays of those objects. All
+ // these representations may be used independently and all provide access
+ // to the stored references via a mesh buffer index.
+ //
+ // In addition, the position and index representations provide lookup
+ // mechanisms to check if positions or indices exist in the mesh buffer
+ // and return their mesh buffer indices if they do. This is used to
+ // implement a limited meshing algorithm which reduces the number of
+ // vertices when non-stripped abutting facets are added to a compression
+ // stream.
+ //
+ static final int NOT_FOUND = -1 ;
+
+ private static final int SIZE = 16 ;
+ private static final int NAN_HASH =
+ new Point3f(Float.NaN, Float.NaN, Float.NaN).hashCode() ;
+
+ private int topIndex = SIZE - 1 ;
+ private int positionIndices[] = new int[SIZE] ;
+ private int normalIndices[] = new int[SIZE] ;
+ private int colorIndices[] = new int[SIZE] ;
+
+ private int topPosition = SIZE - 1 ;
+ private int positionHashCodes[] = new int[SIZE] ;
+ private Point3f positions[] = new Point3f[SIZE] ;
+ private Vector3f normals[] = new Vector3f[SIZE] ;
+ private Color3f colors3[] = new Color3f[SIZE] ;
+ private Color4f colors4[] = new Color4f[SIZE] ;
+
+ private int topVertex = SIZE - 1 ;
+ private CompressionStreamVertex vertices[] =
+ new CompressionStreamVertex[SIZE] ;
+
+ MeshBuffer() {
+ for (int i = 0 ; i < SIZE ; i++) {
+ positionHashCodes[i] = NAN_HASH ;
+
+ positionIndices[i] = NOT_FOUND ;
+ normalIndices[i] = NOT_FOUND ;
+ colorIndices[i] = NOT_FOUND ;
+ }
+ }
+
+ private static int nextTop(int top) {
+ // The stack top references an element in the fixed-length backing
+ // array in which the stack is stored. Stack elements below it have
+ // decreasing indices into the backing array until element 0, at which
+ // point the indices wrap to the end of the backing array and back to
+ // the top.
+ //
+ // A push is accomplished by incrementing the stack top in a circular
+ // buffer and storing the data into the new stack element it
+ // references. The bottom of the stack is the element with the next
+ // higher index from the top in the backing array, and is overwritten
+ // with each new push.
+ return (top + 1) % SIZE ;
+ }
+
+ private static int flipOffset(int top, int offset) {
+ // Flips an offset relative to the beginning of the backing array to
+ // an offset from the top of the stack. Also works in reverse, from
+ // an offset from the top of the stack to an offset from the beginning
+ // of the backing array.
+ if (offset > top) offset -= SIZE ;
+ return top - offset ;
+ }
+
+ //
+ // Mesh buffer vertex stack. This is currently only used for vertex
+ // lookup during the quantization pass in order to compute delta values;
+ // no mesh reference lookup is necessary.
+ //
+ void push(CompressionStreamVertex v) {
+ topVertex = nextTop(topVertex) ;
+ vertices[topVertex] = v ;
+ }
+
+ CompressionStreamVertex getVertex(int meshReference) {
+ return vertices[flipOffset(topVertex, meshReference)] ;
+ }
+
+
+ //
+ // Mesh buffer index stack and index reference lookup support.
+ //
+ void push(int positionIndex, int normalIndex) {
+ topIndex = nextTop(topIndex) ;
+
+ positionIndices[topIndex] = positionIndex ;
+ normalIndices[topIndex] = normalIndex ;
+ }
+
+ void push(int positionIndex, int colorIndex, int normalIndex) {
+ push(positionIndex, normalIndex) ;
+ colorIndices[topIndex] = colorIndex ;
+ }
+
+ int getMeshReference(int positionIndex) {
+ int index ;
+ for (index = 0 ; index < SIZE ; index++)
+ if (positionIndices[index] == positionIndex)
+ break ;
+
+ if (index == SIZE) return NOT_FOUND ;
+ return flipOffset(topIndex, index) ;
+ }
+
+ int getPositionIndex(int meshReference) {
+ return positionIndices[flipOffset(topIndex, meshReference)] ;
+ }
+
+ int getColorIndex(int meshReference) {
+ return colorIndices[flipOffset(topIndex, meshReference)] ;
+ }
+
+ int getNormalIndex(int meshReference) {
+ return normalIndices[flipOffset(topIndex, meshReference)] ;
+ }
+
+
+ //
+ // Mesh buffer position stack and position reference lookup support.
+ //
+ void push(Point3f position, Vector3f normal) {
+ topPosition = nextTop(topPosition) ;
+
+ positionHashCodes[topPosition] = position.hashCode() ;
+ positions[topPosition] = position ;
+ normals[topPosition] = normal ;
+ }
+
+ void push(Point3f position, Color3f color, Vector3f normal) {
+ push(position, normal) ;
+ colors3[topPosition] = color ;
+ }
+
+ void push(Point3f position, Color4f color, Vector3f normal) {
+ push(position, normal) ;
+ colors4[topPosition] = color ;
+ }
+
+ void push(Point3f position, Object color, Vector3f normal) {
+ push(position, normal) ;
+ if (color instanceof Color3f)
+ colors3[topPosition] = (Color3f)color ;
+ else
+ colors4[topPosition] = (Color4f)color ;
+ }
+
+ int getMeshReference(Point3f position) {
+ int index ;
+ int hashCode = position.hashCode() ;
+
+ for (index = 0 ; index < SIZE ; index++)
+ if (positionHashCodes[index] == hashCode)
+ if (positions[index].equals(position))
+ break ;
+
+ if (index == SIZE) return NOT_FOUND ;
+ return flipOffset(topPosition, index) ;
+ }
+
+ Point3f getPosition(int meshReference) {
+ return positions[flipOffset(topPosition, meshReference)] ;
+ }
+
+ Color3f getColor3(int meshReference) {
+ return colors3[flipOffset(topPosition, meshReference)] ;
+ }
+
+ Color4f getColor4(int meshReference) {
+ return colors4[flipOffset(topPosition, meshReference)] ;
+ }
+
+ Vector3f getNormal(int meshReference) {
+ return normals[flipOffset(topPosition, meshReference)] ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/package.html b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/package.html
new file mode 100644
index 0000000..948d235
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/package.html
@@ -0,0 +1,13 @@
+
+
+ Provides compressed geometry utility classes.
+ This package supersedes the org.jogamp.java3d.CompressedGeometry class and
+ the org.jogamp.java3d.utils.compression package. Provides geometry construction, triangulation, and optimization
+utility classes.
+ * Note that non-power-of-two textures may not be supported by all graphics
+ * cards. Applications should check whether a particular Canvas3D supports
+ * non-power-of-two textures by calling the {@link Canvas3D#queryProperties}
+ * method, and checking whether the
+ * Provides texture image utility classes.
+ * The pick tolerance specifies the distance from the
+ * pick center to include in the pick shape. A tolerance of 0.0 may speedup
+ * picking slightly, but also make it very difficult to pick points and lines.
+ *
+ * The pick canvas can be used to make a series of picks. For example, to
+ * initialize the pick canvas:
+ *
+ * Then for each mouse event:
+ *
+ * NOTE: For the pickAllSorted or pickClosest methods, the picks will be sorted
+ * by the distance from the ViewPlatform to the intersection point.
+ * @see PickTool
+ */
+public class PickCanvas extends PickTool {
+
+ /* OPEN ISSUES:
+ -- Should restrict the pick shape to the front/back clip plane
+ */
+
+
+ /** The canvas we are picking into */
+ Canvas3D canvas;
+
+ /* the pick tolerance, default to 2.0 */
+ float tolerance = 2.0f;
+ int save_xpos;
+ int save_ypos;
+
+ /** Constructor with Canvas3D for mouse events and BranchGroup to be picked.
+ */
+ public PickCanvas (Canvas3D c, BranchGroup b) {
+ super (b);
+ canvas = c;
+ }
+
+ /** Constructor with Canvas3D for mouse events and Locale to be picked.
+ */
+ public PickCanvas (Canvas3D c, Locale l) {
+ super (l);
+ canvas = c;
+ }
+
+ /** Inquire the canvas to be used for picking operations.
+ @return the canvas.
+ */
+ public Canvas3D getCanvas() {
+ return canvas;
+ }
+
+ /** Set the picking tolerance. Objects within this distance
+ * (in pixels)
+ * to the mouse x,y location will be picked. The default tolerance is 2.0.
+ * @param t The tolerance
+ * @exception IllegalArgumentException if the tolerance is less than 0.
+ */
+ public void setTolerance(float t) {
+ if (t < 0.0f) {
+ throw new IllegalArgumentException();
+ }
+ tolerance = t;
+
+ if ((pickShape != null) && (!userDefineShape)) {
+ // reset pickShape
+ pickShape = null;
+ setShapeLocation(save_xpos, save_ypos);
+ }
+ }
+
+ /** Get the pick tolerance.
+ */
+ public float getTolerance() {
+ return tolerance;
+ }
+
+ /** Set the pick location. Defines the location on the canvas where the
+ pick is to be performed.
+ @param mevent The MouseEvent for the picking point
+ */
+ public void setShapeLocation(MouseEvent mevent) {
+ setShapeLocation(mevent.getX(), mevent.getY());
+ }
+ /** Set the pick location. Defines the location on the canvas where the
+ pick is to be performed (upper left corner of canvas is 0,0).
+ @param xpos the X position of the picking point
+ @param ypos the Y position of the picking point
+ */
+ public void setShapeLocation (int xpos, int ypos) {
+ Transform3D motion = new Transform3D();
+ Point3d eyePosn = new Point3d();
+ Point3d mousePosn = new Point3d();
+ Vector3d mouseVec = new Vector3d();
+ boolean isParallel = false;
+ double radius = 0.0;
+ double spreadAngle = 0.0;
+
+ this.save_xpos = xpos;
+ this.save_ypos = ypos;
+ canvas.getCenterEyeInImagePlate(eyePosn);
+ canvas.getPixelLocationInImagePlate(xpos,ypos,mousePosn);
+
+ if ((canvas.getView() != null) &&
+ (canvas.getView().getProjectionPolicy() ==
+ View.PARALLEL_PROJECTION)) {
+ // Correct for the parallel projection: keep the eye's z
+ // coordinate, but make x,y be the same as the mouse, this
+ // simulates the eye being at "infinity"
+ eyePosn.x = mousePosn.x;
+ eyePosn.y = mousePosn.y;
+ isParallel = true;
+ }
+
+ // Calculate radius for PickCylinderRay and spread angle for PickConeRay
+ Vector3d eyeToCanvas = new Vector3d();
+ eyeToCanvas.sub (mousePosn, eyePosn);
+ double distanceEyeToCanvas = eyeToCanvas.length();
+
+ Point3d deltaImgPlate = new Point3d();
+ canvas.getPixelLocationInImagePlate (xpos+1, ypos, deltaImgPlate);
+
+ Vector3d ptToDelta = new Vector3d();
+ ptToDelta.sub (mousePosn, deltaImgPlate);
+ double distancePtToDelta = ptToDelta.length();
+ distancePtToDelta *= tolerance;
+
+ canvas.getImagePlateToVworld(motion);
+
+ /*
+ System.out.println("mouse position " + xpos + " " + ypos);
+ System.out.println("before, mouse " + mousePosn + " eye " + eyePosn);
+ */
+
+ motion.transform(eyePosn);
+ start = new Point3d (eyePosn); // store the eye position
+ motion.transform(mousePosn);
+ mouseVec.sub(mousePosn, eyePosn);
+ mouseVec.normalize();
+
+ /*
+ System.out.println(motion + "\n");
+ System.out.println("after, mouse " + mousePosn + " eye " + eyePosn +
+ " mouseVec " + mouseVec);
+ */
+
+ if (tolerance == 0.0) {
+ if ((pickShape != null) && (pickShape instanceof PickRay)) {
+ ((PickRay)pickShape).set (eyePosn, mouseVec);
+ } else {
+ pickShape = (PickShape) new PickRay (eyePosn, mouseVec);
+ }
+ // pickShape = (PickShape) new PickConeRay (eyePosn,
+ // mouseVec,1.0*Math.PI/180.0);
+ } else {
+ if (isParallel) {
+ // Parallel projection, use a PickCylinderRay
+ distancePtToDelta *= motion.getScale();
+ if ((pickShape != null) &&
+ (pickShape instanceof PickCylinderRay)) {
+ ((PickCylinderRay)pickShape).set (eyePosn, mouseVec,
+ distancePtToDelta);
+ } else {
+ pickShape = (PickShape) new PickCylinderRay (eyePosn,
+ mouseVec, distancePtToDelta);
+ }
+ } else {
+ // Perspective projection, use a PickConeRay
+
+ // Calculate spread angle
+ spreadAngle = Math.atan (distancePtToDelta/distanceEyeToCanvas);
+
+ if ((pickShape != null) &&
+ (pickShape instanceof PickConeRay)) {
+ ((PickConeRay)pickShape).set (eyePosn, mouseVec,
+ spreadAngle);
+ } else {
+ pickShape = (PickShape) new PickConeRay (eyePosn, mouseVec,
+ spreadAngle);
+ }
+ }
+ }
+ }
+} // PickCanvas
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/pickfast/PickIntersection.java b/src/classes/share/org/jogamp/java3d/utils/pickfast/PickIntersection.java
new file mode 100644
index 0000000..d082095
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/pickfast/PickIntersection.java
@@ -0,0 +1,1383 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.pickfast;
+
+import org.jogamp.java3d.Geometry;
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.IndexedGeometryArray;
+import org.jogamp.java3d.PickInfo;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.TexCoord3f;
+import org.jogamp.vecmath.Vector3d;
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * Holds information about an intersection of a PickShape with a Node
+ * as part of a PickInfo.IntersectionInfo. Information about
+ * the intersected geometry, intersected primitive, intersection point, and
+ * closest vertex can be inquired.
+ *
+ * The intersected primitive indicates which primitive out of the GeometryArray
+ * was intersected (where the primitive is a point, line, triangle or quad,
+ * not a
+ *
+ * The primitive's VWorld coordinates are saved when then intersection is
+ * calculated. The local coordinates, normal, color and texture coordinates
+ * for the primitive can also be inquired if they are present and readable.
+ *
+ * The intersection point is the location on the primitive which intersects the
+ * pick shape closest to the center of the pick shape. The intersection point's
+ * location in VWorld coordinates is saved when the intersection is calculated.
+ * The local coordinates, normal, color and texture coordiantes of at the
+ * intersection can be interpolated if they are present and readable.
+ *
+ * The closest vertex is the vertex of the primitive closest to the intersection
+ * point. The vertex index, VWorld coordinates and local coordinates of the
+ * closest vertex can be inquired. The normal, color and texture coordinate
+ * of the closest vertex can be inquired from the geometry array:
+ *
+ * The color, normal
+ * and texture coordinate information for the intersected primitive and the
+ * intersection point
+ * can be inquired
+ * the geometry includes them and the corresponding READ capibility bits are
+ * set.
+ */
+
+public class PickIntersection {
+
+
+ /* The intersection point */
+ // Point3d getIntersectionPoint()
+
+ /* Distance between start point of pickShape and intersection point */
+ // double getDistance()
+
+ /* The vertex indices of the intersected primitive in the geometry */
+ // int[] getVertexIndices()
+
+ /*************************/
+
+ /** Weight factors for interpolation, values correspond to vertex indices,
+ * sum == 1
+ */
+ private double[] interpWeights;
+
+ private static final boolean debug = false;
+
+ // Axis constants
+ private static final int X_AXIS = 1;
+ private static final int Y_AXIS = 2;
+ private static final int Z_AXIS = 3;
+
+ // Tolerance for numerical stability
+ static final double TOL = 1.0e-5;
+
+ /* The references to the intersectionInfo object */
+ private PickInfo.IntersectionInfo iInfo = null;
+ private Transform3D l2vw = null;
+ private Geometry geometry = null;
+ private boolean geometryIsIndexed = false;
+ private double distance;
+
+ private boolean hasColors;
+ private boolean hasNormals;
+ private boolean hasTexCoords;
+
+ // Primitive
+ /* indices for the different data types */
+ private int[] primitiveCoordinateIndices;
+ private int[] primitiveNormalIndices;
+ private int[] primitiveColorIndices;
+ private int[] primitiveTexCoordIndices;
+
+ /** Indices of the intersected primitive */
+ private int[] primitiveVertexIndices = null;
+
+ /* Local coordinates of the intersected primitive */
+ private Point3d[] primitiveCoordinates = null;
+
+ /** VWorld coordinates of intersected primitive */
+ private Point3d[] primitiveCoordinatesVW = null;
+
+ /* Normals of the intersected primitive */
+ private Vector3f[] primitiveNormals = null;
+
+ /* Colors of the intersected primitive */
+ private Color4f[] primitiveColors = null;
+
+ /* TextureCoordinates of the intersected primitive */
+ private TexCoord3f[] primitiveTexCoords = null;
+
+ // Intersection point
+ /** VWorld Coordinates of the intersection point */
+ private Point3d pointCoordinatesVW = null;
+
+ /** Local Coordinates of the intersection point */
+ private Point3d pointCoordinates = null;
+
+ /** Normal at the intersection point */
+ private Vector3f pointNormal = null;
+
+ /** Color at the intersection point */
+ private Color4f pointColor = null;
+
+ /** TexCoord at the intersection point */
+ private TexCoord3f pointTexCoord = null;
+
+ // Closest Vertex
+ /** Index of the closest vertex */
+ private int closestVertexIndex = -1;
+
+ /** Coordinates of the closest vertex */
+ private Point3d closestVertexCoordinates = null;
+
+ /** Coordinates of the closest vertex (World coordinates) */
+ private Point3d closestVertexCoordinatesVW = null;
+
+ /* =================== METHODS ======================= */
+
+ /**
+ * Constructor
+ * @param intersectionInfo The IntersectionInfo this intersection is part of.
+ */
+ public PickIntersection (Transform3D localToVWorld,
+ PickInfo.IntersectionInfo intersectionInfo) {
+
+ // Should check and throw NPE if the following is null.
+ // localToVWorld can't be null.
+ l2vw = localToVWorld;
+ // intersectionInfo can't be null.
+ iInfo = intersectionInfo;
+ // geometry can't be null.
+ geometry = iInfo.getGeometry();
+
+ pointCoordinates = iInfo.getIntersectionPoint();
+ distance = iInfo.getDistance();
+ primitiveVertexIndices = iInfo.getVertexIndices();
+
+ if (geometry instanceof GeometryArray) {
+
+ int vertexFormat = ((GeometryArray)geometry).getVertexFormat();
+ hasColors = (0 != (vertexFormat &
+ (GeometryArray.COLOR_3 | GeometryArray.COLOR_4)));
+ hasNormals = (0 != (vertexFormat & GeometryArray.NORMALS));
+ hasTexCoords = (0 != (vertexFormat &
+ (GeometryArray.TEXTURE_COORDINATE_2 |
+ GeometryArray.TEXTURE_COORDINATE_3)));
+
+ if (geometry instanceof IndexedGeometryArray) {
+ geometryIsIndexed = true;
+ }
+ }
+ }
+
+ /**
+ * Returns true if the geometry is indexed
+ *
+ */
+ public boolean geometryIsIndexed() {
+ return geometryIsIndexed;
+ }
+
+ /**
+ * Get coordinates of closest vertex (local)
+ * @return the coordinates of the vertex closest to the intersection point
+ *
+ */
+ public Point3d getClosestVertexCoordinates() {
+ // System.out.println("PI.closestVertexCoordinates " + closestVertexCoordinates);
+ GeometryArray geom = (GeometryArray) geometry;
+
+ if (closestVertexCoordinates == null) {
+ int vertexIndex = getClosestVertexIndex();
+ int vformat = geom.getVertexFormat();
+ int val;
+
+ int[] indices = getPrimitiveCoordinateIndices();
+ if ((vformat & GeometryArray.BY_REFERENCE) == 0) {
+ closestVertexCoordinates = new Point3d();
+ geom.getCoordinate(indices[vertexIndex], closestVertexCoordinates);
+ // System.out.println("PI.closestVertexCoordinates " +
+// closestVertexCoordinates + " vertexIndex " +
+// vertexIndex);
+ }
+ else {
+ if ((vformat & GeometryArray.INTERLEAVED) == 0) {
+ double[] doubleData = geom.getCoordRefDouble();
+ // If data was set as float then ..
+ if (doubleData == null) {
+ float[] floatData = geom.getCoordRefFloat();
+ if (floatData == null) {
+ throw new UnsupportedOperationException("Deprecated : BY_REF - p3f and p3d");
+ }
+ else {
+ val = indices[vertexIndex] * 3; // for x,y,z
+ closestVertexCoordinates = new Point3d(floatData[val],
+ floatData[val+1],
+ floatData[val+2]);
+ }
+ }
+ else {
+ val = indices[vertexIndex] * 3; // for x,y,z
+ closestVertexCoordinates = new Point3d(doubleData[val],
+ doubleData[val+1],
+ doubleData[val+2]);
+ }
+ }
+ else {
+ float[] floatData = geom.getInterleavedVertices();
+ int offset = getInterleavedVertexOffset(geom);
+ int stride = offset + 3; // for the vertices .
+ val = stride * indices[vertexIndex]+offset;
+ closestVertexCoordinates = new Point3d(floatData[val],
+ floatData[val+1],
+ floatData[val+2]);
+ }
+ }
+ }
+
+ return closestVertexCoordinates;
+ }
+
+ /**
+ * Get coordinates of closest vertex (world)
+ * @return the coordinates of the vertex closest to the intersection point
+ *
+ */
+ public Point3d getClosestVertexCoordinatesVW() {
+ if (closestVertexCoordinatesVW == null) {
+ int vertexIndex = getClosestVertexIndex();
+ Point3d[] coordinatesVW = getPrimitiveCoordinatesVW();
+ closestVertexCoordinatesVW = coordinatesVW[vertexIndex];
+ }
+ return closestVertexCoordinatesVW;
+ }
+
+ /**
+ * Get index of closest vertex
+ * @return the index of the closest vertex
+ */
+ public int getClosestVertexIndex() {
+ if (closestVertexIndex == -1) {
+ double maxDist = Double.MAX_VALUE;
+ double curDist = Double.MAX_VALUE;
+ int closestIndex = -1;
+ primitiveCoordinates = getPrimitiveCoordinates();
+
+ assert(primitiveCoordinates != null);
+
+// System.out.println("PI.getClosestVertexIndex : primitiveCoordinates.length " +
+// primitiveCoordinates.length);
+
+ for (int i=0;i
+ * The pick mode specifies the detail level of picking before the PickInfo
+ * is returned:
+ *
+ *
+ * The pick flags specifies the content of the PickInfo(s) returned by the
+ * pick methods. This is specified as one or more individual bits that are
+ * bitwise "OR"ed together to describe the PickInfo data. The flags include :
+ *
+ * When using pickAllSorted or pickClosest methods, the picks
+ * will be sorted by the distance from the start point of the pick shape to
+ * the intersection point.
+ *
+ * @see Locale#pickClosest(int,int,org.jogamp.java3d.PickShape)
+ */
+public class PickTool {
+
+
+ /**
+ * Flag to pass to
+ *
+ @return An array of
+ @return A
+ * 1. Create your scene graph.
+ *
+ * 2. Create this behavior with root and canvas.
+ *
+ *
+ * The above behavior will monitor for any picking events on
+ * the scene graph (below root node) and handle mouse rotates on pick hits.
+ * Note the root node can also be a subgraph node of the scene graph (rather
+ * than the topmost).
+ */
+
+public class PickRotateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
+ MouseRotate rotate;
+ private PickingCallback callback=null;
+ private TransformGroup currentTG;
+
+ /**
+ * Creates a pick/rotate behavior that waits for user mouse events for
+ * the scene graph. This method has its pickMode set to BOUNDS picking.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ **/
+
+ public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
+ super(canvas, root, bounds);
+ rotate = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
+ rotate.setTransformGroup(currGrp);
+ currGrp.addChild(rotate);
+ rotate.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ }
+
+ /**
+ * Creates a pick/rotate behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ * @param pickMode specifys PickTool.PICK_BOUNDS or PickTool.PICK_GEOMETRY.
+ * @see PickTool#setMode
+ **/
+
+ public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
+ int pickMode){
+ super(canvas, root, bounds);
+ rotate = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
+ rotate.setTransformGroup(currGrp);
+ currGrp.addChild(rotate);
+ rotate.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ this.setMode(pickMode);
+ }
+
+
+ /**
+ * Update the scene to manipulate any nodes. This is not meant to be
+ * called by users. Behavior automatically calls this. You can call
+ * this only if you know what you are doing.
+ *
+ * @param xpos Current mouse X pos.
+ * @param ypos Current mouse Y pos.
+ **/
+ @Override
+ public void updateScene(int xpos, int ypos) {
+ TransformGroup tg = null;
+
+ if (!mevent.isMetaDown() && !mevent.isAltDown()){
+
+ // System.out.println("PickRotateBeh : using pickfast pkg : PickInfo ...");
+ pickCanvas.setFlags(PickInfo.NODE | PickInfo.SCENEGRAPHPATH);
+
+ pickCanvas.setShapeLocation(xpos, ypos);
+ PickInfo pickInfo = pickCanvas.pickClosest();
+ if(pickInfo != null) {
+ // System.out.println("Intersected!");
+ tg = (TransformGroup) pickCanvas.getNode(pickInfo, PickTool.TYPE_TRANSFORM_GROUP);
+ if((tg != null) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))) {
+ rotate.setTransformGroup(tg);
+ rotate.wakeup();
+ currentTG = tg;
+ }
+ } else if (callback!=null)
+ callback.transformChanged( PickingCallback.NO_PICK, null );
+ }
+ }
+
+ /**
+ * Callback method from MouseRotate
+ * This is used when the Picking callback is enabled
+ */
+ @Override
+ public void transformChanged( int type, Transform3D transform ) {
+ callback.transformChanged( PickingCallback.ROTATE, currentTG );
+ }
+
+ /**
+ * Register the class @param callback to be called each
+ * time the picked object moves
+ */
+ public void setupCallback( PickingCallback callback ) {
+ this.callback = callback;
+ if (callback==null)
+ rotate.setupCallback( null );
+ else
+ rotate.setupCallback( this );
+ }
+
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickTranslateBehavior.java b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickTranslateBehavior.java
new file mode 100644
index 0000000..b885192
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickTranslateBehavior.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.pickfast.behaviors;
+
+import org.jogamp.java3d.Bounds;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.PickInfo;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehavior;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehaviorCallback;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseTranslate;
+import org.jogamp.java3d.utils.pickfast.PickTool;
+
+/**
+ * A mouse behavior that allows user to pick and translate scene graph objects.
+ * Common usage: 1. Create your scene graph. 2. Create this behavior with
+ * the root and canvas. See PickRotateBehavior for more details.
+ */
+
+public class PickTranslateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
+ MouseTranslate translate;
+ private PickingCallback callback = null;
+ private TransformGroup currentTG;
+
+ /**
+ * Creates a pick/translate behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ **/
+
+ public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
+ super(canvas, root, bounds);
+ translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
+ translate.setTransformGroup(currGrp);
+ currGrp.addChild(translate);
+ translate.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ }
+
+ /**
+ * Creates a pick/translate behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ * @param pickMode specifys PickTool.PICK_BOUNDS or PickTool.PICK_GEOMETRY.
+ * @see PickTool#setMode
+ **/
+ public PickTranslateBehavior(BranchGroup root, Canvas3D canvas,
+ Bounds bounds, int pickMode) {
+ super(canvas, root, bounds);
+ translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
+ translate.setTransformGroup(currGrp);
+ currGrp.addChild(translate);
+ translate.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ this.setMode(pickMode);
+ }
+
+
+ /**
+ * Update the scene to manipulate any nodes. This is not meant to be
+ * called by users. Behavior automatically calls this. You can call
+ * this only if you know what you are doing.
+ *
+ * @param xpos Current mouse X pos.
+ * @param ypos Current mouse Y pos.
+ **/
+ @Override
+ public void updateScene(int xpos, int ypos){
+ TransformGroup tg = null;
+
+ if(!mevent.isAltDown() && mevent.isMetaDown()){
+
+ pickCanvas.setShapeLocation(xpos, ypos);
+
+ // System.out.println("PickTranslateBeh : using pickfast pkg : PickInfo ...");
+
+ pickCanvas.setFlags(PickInfo.NODE | PickInfo.SCENEGRAPHPATH);
+ PickInfo pickInfo = pickCanvas.pickClosest();
+
+ if(pickInfo != null) {
+ // System.out.println("Intersected!");
+ tg = (TransformGroup) pickCanvas.getNode(pickInfo, PickTool.TYPE_TRANSFORM_GROUP);
+ if((tg != null) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))) {
+ translate.setTransformGroup(tg);
+ translate.wakeup();
+ currentTG = tg;
+ }
+ } else if (callback!=null)
+ callback.transformChanged( PickingCallback.NO_PICK, null );
+
+ }
+
+ }
+
+ /**
+ * Callback method from MouseTranslate
+ * This is used when the Picking callback is enabled
+ */
+ @Override
+ public void transformChanged( int type, Transform3D transform ) {
+ callback.transformChanged( PickingCallback.TRANSLATE, currentTG );
+ }
+
+ /**
+ * Register the class @param callback to be called each
+ * time the picked object moves
+ */
+ public void setupCallback( PickingCallback callback ) {
+ this.callback = callback;
+ if (callback==null)
+ translate.setupCallback( null );
+ else
+ translate.setupCallback( this );
+ }
+
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickZoomBehavior.java b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickZoomBehavior.java
new file mode 100644
index 0000000..04faacc
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickZoomBehavior.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.pickfast.behaviors;
+
+import org.jogamp.java3d.Bounds;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.PickInfo;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehavior;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehaviorCallback;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseZoom;
+import org.jogamp.java3d.utils.pickfast.PickTool;
+
+
+/**
+ * A mouse behavior that allows user to pick and zoom scene graph objects.
+ * Common usage: 1. Create your scene graph. 2. Create this behavior with
+ * the root and canvas. See PickRotateBehavior for more details.
+ */
+
+public class PickZoomBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
+ MouseZoom zoom;
+ private PickingCallback callback = null;
+ private TransformGroup currentTG;
+
+ /**
+ * Creates a pick/zoom behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ **/
+
+ public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
+ super(canvas, root, bounds);
+ zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
+ zoom.setTransformGroup(currGrp);
+ currGrp.addChild(zoom);
+ zoom.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ }
+
+ /**
+ * Creates a pick/zoom behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ * @param pickMode specifys PickTool.PICK_BOUNDS or PickTool.PICK_GEOMETRY.
+ * @see PickTool#setMode
+ */
+ public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
+ int pickMode) {
+ super(canvas, root, bounds);
+ zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
+ zoom.setTransformGroup(currGrp);
+ currGrp.addChild(zoom);
+ zoom.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ this.setMode(pickMode);
+ }
+
+ /**
+ * Update the scene to manipulate any nodes. This is not meant to be
+ * called by users. Behavior automatically calls this. You can call
+ * this only if you know what you are doing.
+ *
+ * @param xpos Current mouse X pos.
+ * @param ypos Current mouse Y pos.
+ **/
+
+ @Override
+ public void updateScene(int xpos, int ypos){
+ TransformGroup tg = null;
+
+ if (mevent.isAltDown() && !mevent.isMetaDown()){
+
+ pickCanvas.setShapeLocation(xpos, ypos);
+ // System.out.println("PickZoomBeh : using pickfast pkg : PickInfo ...");
+
+ pickCanvas.setFlags(PickInfo.NODE | PickInfo.SCENEGRAPHPATH);
+
+ PickInfo pickInfo = pickCanvas.pickClosest();
+ if(pickInfo != null) {
+ // System.out.println("Intersected!");
+ tg = (TransformGroup) pickCanvas.getNode(pickInfo, PickTool.TYPE_TRANSFORM_GROUP);
+ if((tg != null) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))) {
+ zoom.setTransformGroup(tg);
+ zoom.wakeup();
+ currentTG = tg;
+ }
+ } else if (callback!=null)
+ callback.transformChanged( PickingCallback.NO_PICK, null );
+
+
+ }
+ }
+
+ /**
+ * Callback method from MouseZoom
+ * This is used when the Picking callback is enabled
+ */
+ @Override
+ public void transformChanged( int type, Transform3D transform ) {
+ callback.transformChanged( PickingCallback.ZOOM, currentTG );
+ }
+
+ /**
+ * Register the class @param callback to be called each
+ * time the picked object moves
+ */
+ public void setupCallback( PickingCallback callback ) {
+ this.callback = callback;
+ if (callback==null)
+ zoom.setupCallback( null );
+ else
+ zoom.setupCallback( this );
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickingCallback.java b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickingCallback.java
new file mode 100644
index 0000000..0a967d3
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickingCallback.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.pickfast.behaviors;
+
+import org.jogamp.java3d.TransformGroup;
+
+/**
+ * The PickingCallback interface allows a class to be notified when a
+ * picked object is moved. The class that is interested in object
+ * movement implements this interface, and the object created with
+ * that class is registered with the desired subclass of
+ * PickMouseBehavior using the Provides picking behaviors for the new core picking methods. Provides picking utility classes for the new core picking methods.
+ * The pick tolerance specifies the distance from the
+ * pick center to include in the pick shape. A tolerance of 0.0 may speedup
+ * picking slightly, but also make it very difficult to pick points and lines.
+ *
+ * The pick canvas can be used to make a series of picks. For example, to
+ * initialize the pick canvas:
+ *
+ * Then for each mouse event:
+ *
+ * NOTE: For the pickAllSorted or pickClosest methods, the picks will be sorted
+ * by the distance from the ViewPlatform to the intersection point.
+ * @see PickTool
+ */
+public class PickCanvas extends PickTool {
+
+ /* OPEN ISSUES:
+ -- Should restrict the pick shape to the front/back clip plane
+ */
+
+
+ /** The canvas we are picking into */
+ Canvas3D canvas;
+
+ /* the pick tolerance, default to 2.0 */
+ float tolerance = 2.0f;
+ int save_xpos;
+ int save_ypos;
+
+ /** Constructor with Canvas3D for mouse events and BranchGroup to be picked.
+ */
+ public PickCanvas (Canvas3D c, BranchGroup b) {
+ super (b);
+ canvas = c;
+ }
+
+ /** Constructor with Canvas3D for mouse events and Locale to be picked.
+ */
+ public PickCanvas (Canvas3D c, Locale l) {
+ super (l);
+ canvas = c;
+ }
+
+ /** Inquire the canvas to be used for picking operations.
+ @return the canvas.
+ */
+ public Canvas3D getCanvas() {
+ return canvas;
+ }
+
+ /** Set the picking tolerance. Objects within this distance
+ * (in pixels)
+ * to the mouse x,y location will be picked. The default tolerance is 2.0.
+ * @param t The tolerance
+ * @exception IllegalArgumentException if the tolerance is less than 0.
+ */
+ public void setTolerance(float t) {
+ if (t < 0.0f) {
+ throw new IllegalArgumentException();
+ }
+ tolerance = t;
+
+ if ((pickShape != null) && (!userDefineShape)) {
+ // reset pickShape
+ pickShape = null;
+ setShapeLocation(save_xpos, save_ypos);
+ }
+ }
+
+ /** Get the pick tolerance.
+ */
+ public float getTolerance() {
+ return tolerance;
+ }
+
+ /** Set the pick location. Defines the location on the canvas where the
+ pick is to be performed.
+ @param mevent The MouseEvent for the picking point
+ */
+ public void setShapeLocation(MouseEvent mevent) {
+ setShapeLocation(mevent.getX(), mevent.getY());
+ }
+ /** Set the pick location. Defines the location on the canvas where the
+ pick is to be performed (upper left corner of canvas is 0,0).
+ @param xpos the X position of the picking point
+ @param ypos the Y position of the picking point
+ */
+ public void setShapeLocation (int xpos, int ypos) {
+ Transform3D motion = new Transform3D();
+ Point3d eyePosn = new Point3d();
+ Point3d mousePosn = new Point3d();
+ Vector3d mouseVec = new Vector3d();
+ boolean isParallel = false;
+ double radius = 0.0;
+ double spreadAngle = 0.0;
+
+ this.save_xpos = xpos;
+ this.save_ypos = ypos;
+ canvas.getCenterEyeInImagePlate(eyePosn);
+ canvas.getPixelLocationInImagePlate(xpos,ypos,mousePosn);
+
+ if ((canvas.getView() != null) &&
+ (canvas.getView().getProjectionPolicy() ==
+ View.PARALLEL_PROJECTION)) {
+ // Correct for the parallel projection: keep the eye's z
+ // coordinate, but make x,y be the same as the mouse, this
+ // simulates the eye being at "infinity"
+ eyePosn.x = mousePosn.x;
+ eyePosn.y = mousePosn.y;
+ isParallel = true;
+ }
+
+ // Calculate radius for PickCylinderRay and spread angle for PickConeRay
+ Vector3d eyeToCanvas = new Vector3d();
+ eyeToCanvas.sub (mousePosn, eyePosn);
+ double distanceEyeToCanvas = eyeToCanvas.length();
+
+ Point3d deltaImgPlate = new Point3d();
+ canvas.getPixelLocationInImagePlate (xpos+1, ypos, deltaImgPlate);
+
+ Vector3d ptToDelta = new Vector3d();
+ ptToDelta.sub (mousePosn, deltaImgPlate);
+ double distancePtToDelta = ptToDelta.length();
+ distancePtToDelta *= tolerance;
+
+ canvas.getImagePlateToVworld(motion);
+
+ /*
+ System.out.println("mouse position " + xpos + " " + ypos);
+ System.out.println("before, mouse " + mousePosn + " eye " + eyePosn);
+ */
+
+ motion.transform(eyePosn);
+ start = new Point3d (eyePosn); // store the eye position
+ motion.transform(mousePosn);
+ mouseVec.sub(mousePosn, eyePosn);
+ mouseVec.normalize();
+
+ /*
+ System.out.println(motion + "\n");
+ System.out.println("after, mouse " + mousePosn + " eye " + eyePosn +
+ " mouseVec " + mouseVec);
+ */
+
+ if (tolerance == 0.0) {
+ if ((pickShape != null) && (pickShape instanceof PickRay)) {
+ ((PickRay)pickShape).set (eyePosn, mouseVec);
+ } else {
+ pickShape = (PickShape) new PickRay (eyePosn, mouseVec);
+ }
+ // pickShape = (PickShape) new PickConeRay (eyePosn,
+ // mouseVec,1.0*Math.PI/180.0);
+ } else {
+ if (isParallel) {
+ // Parallel projection, use a PickCylinderRay
+ distancePtToDelta *= motion.getScale();
+ if ((pickShape != null) &&
+ (pickShape instanceof PickCylinderRay)) {
+ ((PickCylinderRay)pickShape).set (eyePosn, mouseVec,
+ distancePtToDelta);
+ } else {
+ pickShape = (PickShape) new PickCylinderRay (eyePosn,
+ mouseVec, distancePtToDelta);
+ }
+ } else {
+ // Perspective projection, use a PickConeRay
+
+ // Calculate spread angle
+ spreadAngle = Math.atan (distancePtToDelta/distanceEyeToCanvas);
+
+ if ((pickShape != null) &&
+ (pickShape instanceof PickConeRay)) {
+ ((PickConeRay)pickShape).set (eyePosn, mouseVec,
+ spreadAngle);
+ } else {
+ pickShape = (PickShape) new PickConeRay (eyePosn, mouseVec,
+ spreadAngle);
+ }
+ }
+ }
+ }
+} // PickCanvas
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/picking/PickIntersection.java b/src/classes/share/org/jogamp/java3d/utils/picking/PickIntersection.java
new file mode 100644
index 0000000..2e7c070
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/picking/PickIntersection.java
@@ -0,0 +1,1581 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.picking;
+
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.IndexedGeometryArray;
+import org.jogamp.vecmath.Color3b;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4b;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.TexCoord2f;
+import org.jogamp.vecmath.TexCoord3f;
+import org.jogamp.vecmath.Vector3d;
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * Holds information about an intersection of a PickShape with a Node
+ * as part of a PickResult. Information about
+ * the intersected geometry, intersected primitive, intersection point, and
+ * closest vertex can be inquired.
+ *
+ * The intersected geometry is indicated by an index into the list of
+ * geometry arrays on the PickResult. It can also be inquired from this
+ * object.
+ *
+ * The intersected primitive indicates which primitive out of the GeometryArray
+ * was intersected (where the primitive is a point, line, triangle or quad,
+ * not a
+ *
+ * The primitive's VWorld coordinates are saved when then intersection is
+ * calculated. The local coordinates, normal, color and texture coordinates
+ * for the primitive can also be inquired if they are present and readable.
+ *
+ * The intersection point is the location on the primitive which intersects the
+ * pick shape closest to the center of the pick shape. The intersection point's
+ * location in VWorld coordinates is saved when the intersection is calculated.
+ * The local coordinates, normal, color and texture coordiantes of at the
+ * intersection can be interpolated if they are present and readable.
+ *
+ * The closest vertex is the vertex of the primitive closest to the intersection
+ * point. The vertex index, VWorld coordinates and local coordinates of the
+ * closest vertex can be inquired. The normal, color and texture coordinate
+ * of the closest vertex can be inquired from the geometry array:
+ *
+ * The color, normal
+ * and texture coordinate information for the intersected primitive and the
+ * intersection point
+ * can be inquired
+ * the geometry includes them and the corresponding READ capibility bits are
+ * set.
+ *
+ *
+ * A PickResult can be used to calculate intersections on Node which is not part
+ * of a live scene graph using the constructor which takes a local to VWorld
+ * transformation for the Node.
+ *
+ * Pick hits on TriangleStrip primitives will store the triangle points in the
+ * PickIntersection with
+ * the verticies in counter-clockwise order. For triangles which start with
+ * an odd numbered vertex this will be the the opposite of the
+ * order of the points in the TriangleStrip.
+ * This way the triangle in
+ * the PickIntersection will display the same was as the triangle in the
+ * strip.
+ *
+ * If the Shape3D being picked has multiple geometry arrays, the arrays are
+ * stored in the PickResult and referred to by a geometry index.
+ *
+ * If the Shape3D refers to a CompressedGeometry, the geometry is decompressed
+ * into an array of Shape3D nodes which can be inquired. The geometry
+ * NodeComponents for the Shape3D nodes are stored and used as if the Shape3D
+ * had multiple geometries. If there are multiple CompressedGeometries on the
+ * Shape3D, the decompressed Shape3Ds and GeometryArrays will be stored
+ * sequentially.
+ *
+ * The intersection point for Morph nodes cannot be calculated using the
+ * displayed geometry
+ * due to limitations in the current Java3D core API (the current
+ * geometry of the the Morph cannot be inquired). Instead
+ * the geometry at index 0 in the Morph is used. This limitation may
+ * be eliminated in a future release of Java3D.
+ */
+public class PickResult {
+
+ /* OPEN ISSUES:
+ -- getInterpolatedTextureCoordinates uses the depricated API faor
+ getTextureCoordinate(), need to update.
+ -- Bounds tests don't fill in any picking info.
+ -- Can't do any intersections with the PickPoint shape.
+ */
+
+
+ // Externally used constants
+
+ /**
+ * Flag to pass to
+ *
+ * The utility method
+ *
+ *
+ * A PickResult from a lower level of detail pick can be used to
+ * inquire more detailed information if the capibility bits are set.
+ * This can be used to filter the PickResults
+ * before the more computationally intensive intersection processing.
+ * For example,
+ * the application can do a BOUNDS pick and then selectively inquire
+ * intersections on some of the PickResults. This will save the effort of
+ * doing intersection computation on the other PickResults.
+ * However, inquiring the intersections from a GEOMETRY pick will make
+ * the intersection computation happen twice, use GEOMETRY_INTERSECT_INFO
+ * if you want to inquire the intersection information on all the PickResults.
+ *
+ * When using pickAllSorted or pickClosest methods, the picks
+ * will be sorted by the distance from the start point of the pick shape to
+ * the intersection point.
+ *
+ * Morph nodes cannot be picked using the displayed geometry in
+ * GEOMETRY_INTERSECT_INFO mode due to limitations in the current Java3D core
+ * API (the current
+ * geometry of the the Morph cannot be inquired). Instead they are picked
+ * using
+ * the geometry at index 0 in the Morph, this limitation may be eliminated in a
+ * future release of Java3D.
+ *
+ * If the pick shape is a PickBounds, the pick result will contain only the
+ * scene graph path, even if the mode is GEOMETRY_INTERSECT_INFO.
+ */
+public class PickTool {
+
+ /* OPEN ISSUES:
+ -- pickClosest() and pickAllSorted() using GEOMETRY and a non-PickRay
+ shape => unsorted picking.
+ -- Need to implement Morph geometry index 0 picking.
+ */
+
+ private final boolean debug = true;
+ protected boolean userDefineShape = false;
+
+ PickShape pickShape;
+
+ /** Used to store the BranchGroup used for picking */
+ BranchGroup pickRootBG = null;
+ /** Used to store the Locale used for picking */
+ Locale pickRootL = null;
+
+ /** Used to store a reference point used in determining how "close" points
+ are.
+ */
+ Point3d start = null;
+
+ /* pick mode, one of BOUNDS, GEOMETRY, etc. */
+ int mode = BOUNDS;
+
+ /** Use this mode to pick by bounds and get basic information
+ on the pick.
+ */
+ public static final int BOUNDS = 0x200;
+
+ /** Use this mode to pick by geometry and get basic
+ information on the pick.
+ */
+ public static final int GEOMETRY = 0x100;
+
+ /** Use this mode to pick by geometry and save
+ information about the intersections (intersected primitive,
+ intersection point and closest vertex).
+ */
+ public static final int GEOMETRY_INTERSECT_INFO = 0x400;
+
+
+ // Flags for the setCapabilities() method
+ /**
+ * Flag to pass to
+ * Note that by default all org.jogamp.java3d.utils.geometry.Primitive
+ * objects with the same parameters share their geometry (e.g.,
+ * you can have 50 spheres in your scene, but the geometry is
+ * stored only once). Therefore the capabilities of the geometry
+ * are also shared, and once a shared node is live, the
+ * capabilities cannot be changed. To assign capabilities to
+ * Primitives with the same parameters, either set the
+ * capabilities before the primitive is set live, or specify the
+ * Primitive.GEOMETRY_NOT_SHARED constructor parameter when
+ * creating the primitive.
+ * @param node The node to modify
+ * @param level The capability level, must be one of INTERSECT_TEST,
+ * INTERSECT_COORD or INTERSECT_FULL
+ * @throws IllegalArgumentException if Node is not a Shape3D or Morph or
+ * if the flag value is not valid.
+ * @throws org.jogamp.java3d.RestrictedAccessException if the node is part
+ * of a live or compiled scene graph. */
+ static public void setCapabilities(Node node, int level) {
+ if (node instanceof Morph) {
+ Morph morph = (Morph) node;
+ switch (level) {
+ case INTERSECT_FULL:
+ /* intentional fallthrough */
+ case INTERSECT_COORD:
+ morph.setCapability(Morph.ALLOW_GEOMETRY_ARRAY_READ);
+ /* intentional fallthrough */
+ case INTERSECT_TEST:
+ break;
+ default:
+ throw new IllegalArgumentException("Improper level");
+ }
+ double[] weights = morph.getWeights();
+ for (int i = 0; i < weights.length; i++) {
+ GeometryArray ga = morph.getGeometryArray(i);
+ setCapabilities(ga, level);
+ }
+ } else if (node instanceof Shape3D) {
+ Shape3D shape = (Shape3D) node;
+ switch (level) {
+ case INTERSECT_FULL:
+ /* intentional fallthrough */
+ case INTERSECT_COORD:
+ shape.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
+ /* intentional fallthrough */
+ case INTERSECT_TEST:
+ break;
+ default:
+ throw new IllegalArgumentException("Improper level");
+ }
+ for (int i = 0; i < shape.numGeometries(); i++) {
+ Geometry geo = shape.getGeometry(i);
+ if (geo instanceof GeometryArray) {
+ setCapabilities((GeometryArray)geo, level);
+ } else if (geo instanceof CompressedGeometry) {
+ setCapabilities((CompressedGeometry)geo, level);
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("Improper node type");
+ }
+ }
+
+ static private void setCapabilities(GeometryArray ga, int level) {
+ switch (level) {
+ case INTERSECT_FULL:
+ ga.setCapability(GeometryArray.ALLOW_COLOR_READ);
+ ga.setCapability(GeometryArray.ALLOW_NORMAL_READ);
+ ga.setCapability(GeometryArray.ALLOW_TEXCOORD_READ);
+ /* intential fallthrough */
+ case INTERSECT_COORD:
+ ga.setCapability(GeometryArray.ALLOW_COUNT_READ);
+ ga.setCapability(GeometryArray.ALLOW_FORMAT_READ);
+ ga.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
+ /* intential fallthrough */
+ case INTERSECT_TEST:
+ ga.setCapability(GeometryArray.ALLOW_INTERSECT);
+ break;
+ }
+ if (ga instanceof IndexedGeometryArray) {
+ setCapabilities((IndexedGeometryArray)ga, level);
+ }
+ }
+
+ static private void setCapabilities(IndexedGeometryArray iga, int level) {
+ switch (level) {
+ case INTERSECT_FULL:
+ iga.setCapability(IndexedGeometryArray.ALLOW_COLOR_INDEX_READ);
+ iga.setCapability(IndexedGeometryArray.ALLOW_NORMAL_INDEX_READ);
+ iga.setCapability(IndexedGeometryArray.ALLOW_TEXCOORD_INDEX_READ);
+ /* intential fallthrough */
+ case INTERSECT_COORD:
+ iga.setCapability(IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ);
+ /* intential fallthrough */
+ case INTERSECT_TEST:
+ break;
+ }
+ }
+
+ static private void setCapabilities(CompressedGeometry cg, int level) {
+ switch (level) {
+ case INTERSECT_FULL:
+ /* intential fallthrough */
+ case INTERSECT_COORD:
+ cg.setCapability(CompressedGeometry.ALLOW_GEOMETRY_READ);
+ /* intential fallthrough */
+ case INTERSECT_TEST:
+ cg.setCapability(CompressedGeometry.ALLOW_INTERSECT);
+ break;
+ }
+ }
+
+ // Methods used to define the pick shape
+
+ /** Sets the pick shape to a user-provided PickShape object
+ * @param ps The pick shape to pick against.
+ * @param startPt The start point to use for distance calculations
+ */
+ public void setShape (PickShape ps, Point3d startPt) {
+ this.pickShape = ps;
+ this.start = startPt;
+ userDefineShape = (ps != null);
+ }
+
+ /** Sets the pick shape to use a user-provided Bounds object
+ * @param bounds The bounds to pick against.
+ * @param startPt The start point to use for distance calculations
+ */
+ public void setShapeBounds (Bounds bounds, Point3d startPt) {
+ this.pickShape = (PickShape) new PickBounds (bounds);
+ this.start = startPt;
+ userDefineShape = true;
+ }
+
+ /** Sets the picking detail mode. The default is BOUNDS.
+ * @param mode One of BOUNDS, GEOMETRY, GEOMETRY_INTERSECT_INFO, or
+ * @exception IllegalArgumentException if mode is not a legal value
+ */
+ public void setMode (int mode) {
+ if ((mode != BOUNDS) && (mode != GEOMETRY) &&
+ (mode != GEOMETRY_INTERSECT_INFO)) {
+ throw new java.lang.IllegalArgumentException();
+ }
+ this.mode = mode;
+ }
+
+ /** Gets the picking detail mode.
+ */
+ public int getMode () {
+ return mode;
+ }
+
+ /** Sets the pick shape to a PickRay.
+ * @param start The start of the ray
+ * @param dir The direction of the ray
+ */
+ public void setShapeRay (Point3d start, Vector3d dir) {
+ this.pickShape = (PickShape) new PickRay (start, dir);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Sets the pick shape to a PickSegment.
+ @param start The start of the segment
+p @param end The end of the segment
+ */
+ public void setShapeSegment (Point3d start, Point3d end) {
+ this.pickShape = (PickShape) new PickSegment (start, end);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Sets the pick shape to a capped PickCylinder
+ * @param start The start of axis of the cylinder
+ * @param end The end of the axis of the cylinder
+ * @param radius The radius of the cylinder
+ */
+ public void setShapeCylinderSegment (Point3d start, Point3d end,
+ double radius) {
+ this.pickShape = (PickShape)
+ new PickCylinderSegment (start, end, radius);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Sets the pick shape to an infinite PickCylinder.
+ * @param start The start of axis of the cylinder
+ * @param dir The direction of the axis of the cylinder
+ * @param radius The radius of the cylinder
+ */
+ public void setShapeCylinderRay (Point3d start, Vector3d dir,
+ double radius) {
+ this.pickShape = (PickShape) new PickCylinderRay (start, dir, radius);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Sets the pick shape to a capped PickCone
+ * @param start The start of axis of the cone
+ * @param end The end of the axis of the cone
+ * @param angle The angle of the cone
+ */
+ public void setShapeConeSegment (Point3d start, Point3d end,
+ double angle) {
+ this.pickShape = (PickShape) new PickConeSegment (start, end, angle);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Sets the pick shape to an infinite PickCone.
+ * @param start The start of axis of the cone
+ * @param dir The direction of the axis of the cone
+ * @param angle The angle of the cone
+ */
+ public void setShapeConeRay (Point3d start, Vector3d dir,
+ double angle) {
+ this.pickShape = (PickShape) new PickConeRay (start, dir, angle);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Returns the PickShape for this object. */
+ public PickShape getPickShape () {
+ return pickShape;
+ }
+
+ /** Returns the start postion used for distance measurement. */
+ public Point3d getStartPosition () {
+ return start;
+ }
+
+ /** Selects all the nodes that intersect the PickShape.
+ @return An array of
+ @return An array of
+ @return A
+ * 2. Create this behavior with root and canvas.
+ *
+ *
+ * The above behavior will monitor for any picking events on
+ * the scene graph (below root node) and handle mouse drags on pick hits.
+ * Note the root node can also be a subgraph node of the scene graph (rather
+ * than the topmost).
+ */
+
+public class PickRotateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
+ MouseRotate drag;
+// int pickMode = PickTool.BOUNDS;
+ private PickingCallback callback=null;
+ private TransformGroup currentTG;
+
+ /**
+ * Creates a pick/rotate behavior that waits for user mouse events for
+ * the scene graph. This method has its pickMode set to BOUNDS picking.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ **/
+
+ public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
+ super(canvas, root, bounds);
+ drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
+ drag.setTransformGroup(currGrp);
+ currGrp.addChild(drag);
+ drag.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ }
+
+ /**
+ * Creates a pick/rotate behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ * @param pickMode specifys PickTool.BOUNDS, PickTool.GEOMETRY or
+ * PickTool.GEOMETRY_INTERSECT_INFO.
+ * @see PickTool#setMode
+ **/
+
+ public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
+ int pickMode){
+ super(canvas, root, bounds);
+ drag = new MouseRotate(MouseRotate.MANUAL_WAKEUP);
+ drag.setTransformGroup(currGrp);
+ currGrp.addChild(drag);
+ drag.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ this.setMode(pickMode);
+ }
+
+
+ /**
+ * Update the scene to manipulate any nodes. This is not meant to be
+ * called by users. Behavior automatically calls this. You can call
+ * this only if you know what you are doing.
+ *
+ * @param xpos Current mouse X pos.
+ * @param ypos Current mouse Y pos.
+ **/
+ @Override
+ public void updateScene(int xpos, int ypos){
+ TransformGroup tg = null;
+
+ if (!mevent.isMetaDown() && !mevent.isAltDown()){
+
+ pickCanvas.setShapeLocation(xpos, ypos);
+ PickResult pr = pickCanvas.pickClosest();
+ if ((pr != null) &&
+ ((tg = (TransformGroup)pr.getNode(PickResult.TRANSFORM_GROUP))
+ != null) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
+ drag.setTransformGroup(tg);
+ drag.wakeup();
+ currentTG = tg;
+ // free the PickResult
+ // Need to clean up Issue 123 --- Chien
+ // freePickResult(pr);
+ } else if (callback!=null)
+ callback.transformChanged( PickingCallback.NO_PICK, null );
+ }
+ }
+
+ /**
+ * Callback method from MouseRotate
+ * This is used when the Picking callback is enabled
+ */
+ @Override
+ public void transformChanged( int type, Transform3D transform ) {
+ callback.transformChanged( PickingCallback.ROTATE, currentTG );
+ }
+
+ /**
+ * Register the class @param callback to be called each
+ * time the picked object moves
+ */
+ public void setupCallback( PickingCallback callback ) {
+ this.callback = callback;
+ if (callback==null)
+ drag.setupCallback( null );
+ else
+ drag.setupCallback( this );
+ }
+
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/PickTranslateBehavior.java b/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/PickTranslateBehavior.java
new file mode 100644
index 0000000..0d8c544
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/PickTranslateBehavior.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.picking.behaviors;
+
+import org.jogamp.java3d.Bounds;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehavior;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehaviorCallback;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseTranslate;
+import org.jogamp.java3d.utils.picking.PickResult;
+import org.jogamp.java3d.utils.picking.PickTool;
+
+/**
+ * A mouse behavior that allows user to pick and translate scene graph objects.
+ * Common usage: 1. Create your scene graph. 2. Create this behavior with
+ * the root and canvas. See PickRotateBehavior for more details.
+ */
+
+public class PickTranslateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
+ MouseTranslate translate;
+ private PickingCallback callback = null;
+ private TransformGroup currentTG;
+
+ /**
+ * Creates a pick/translate behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ **/
+
+ public PickTranslateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
+ super(canvas, root, bounds);
+ translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
+ translate.setTransformGroup(currGrp);
+ currGrp.addChild(translate);
+ translate.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ }
+
+ /**
+ * Creates a pick/translate behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ * @param pickMode specifys PickTool.BOUNDS, PickTool.GEOMETRY or
+ * PickTool.GEOMETRY_INTERSECT_INFO.
+ * @see PickTool#setMode
+ **/
+ public PickTranslateBehavior(BranchGroup root, Canvas3D canvas,
+ Bounds bounds, int pickMode) {
+ super(canvas, root, bounds);
+ translate = new MouseTranslate(MouseBehavior.MANUAL_WAKEUP);
+ translate.setTransformGroup(currGrp);
+ currGrp.addChild(translate);
+ translate.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ this.setMode(pickMode);
+ }
+
+
+ /**
+ * Update the scene to manipulate any nodes. This is not meant to be
+ * called by users. Behavior automatically calls this. You can call
+ * this only if you know what you are doing.
+ *
+ * @param xpos Current mouse X pos.
+ * @param ypos Current mouse Y pos.
+ **/
+ @Override
+ public void updateScene(int xpos, int ypos){
+ TransformGroup tg = null;
+
+ if (!mevent.isAltDown() && mevent.isMetaDown()){
+
+ pickCanvas.setShapeLocation(xpos, ypos);
+ PickResult pr = pickCanvas.pickClosest();
+ if ((pr != null) &&
+ ((tg = (TransformGroup)pr.getNode(PickResult.TRANSFORM_GROUP))
+ != null) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
+
+ translate.setTransformGroup(tg);
+ translate.wakeup();
+ currentTG = tg;
+ // Need to clean up Issue 123 --- Chien
+ // freePickResult(pr);
+ } else if (callback!=null)
+ callback.transformChanged( PickingCallback.NO_PICK, null );
+ }
+
+ }
+
+ /**
+ * Callback method from MouseTranslate
+ * This is used when the Picking callback is enabled
+ */
+ @Override
+ public void transformChanged( int type, Transform3D transform ) {
+ callback.transformChanged( PickingCallback.TRANSLATE, currentTG );
+ }
+
+ /**
+ * Register the class @param callback to be called each
+ * time the picked object moves
+ */
+ public void setupCallback( PickingCallback callback ) {
+ this.callback = callback;
+ if (callback==null)
+ translate.setupCallback( null );
+ else
+ translate.setupCallback( this );
+ }
+
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/PickZoomBehavior.java b/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/PickZoomBehavior.java
new file mode 100644
index 0000000..f50ad05
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/PickZoomBehavior.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.picking.behaviors;
+
+import org.jogamp.java3d.Bounds;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehavior;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehaviorCallback;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseZoom;
+import org.jogamp.java3d.utils.picking.PickResult;
+import org.jogamp.java3d.utils.picking.PickTool;
+
+
+/**
+ * A mouse behavior that allows user to pick and zoom scene graph objects.
+ * Common usage: 1. Create your scene graph. 2. Create this behavior with
+ * the root and canvas. See PickRotateBehavior for more details.
+ */
+
+public class PickZoomBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
+ MouseZoom zoom;
+ private PickingCallback callback = null;
+ private TransformGroup currentTG;
+
+ /**
+ * Creates a pick/zoom behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ **/
+
+ public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
+ super(canvas, root, bounds);
+ zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
+ zoom.setTransformGroup(currGrp);
+ currGrp.addChild(zoom);
+ zoom.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ }
+
+ /**
+ * Creates a pick/zoom behavior that waits for user mouse events for
+ * the scene graph.
+ * @param root Root of your scene graph.
+ * @param canvas Java 3D drawing canvas.
+ * @param bounds Bounds of your scene.
+ * @param pickMode specifys PickTool.BOUNDS, PickTool.GEOMETRY or
+ * PickTool.GEOMETRY_INTERSECT_INFO.
+ * @see PickTool#setMode
+ */
+ public PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
+ int pickMode) {
+ super(canvas, root, bounds);
+ zoom = new MouseZoom(MouseBehavior.MANUAL_WAKEUP);
+ zoom.setTransformGroup(currGrp);
+ currGrp.addChild(zoom);
+ zoom.setSchedulingBounds(bounds);
+ this.setSchedulingBounds(bounds);
+ this.setMode(pickMode);
+ }
+
+ /**
+ * Update the scene to manipulate any nodes. This is not meant to be
+ * called by users. Behavior automatically calls this. You can call
+ * this only if you know what you are doing.
+ *
+ * @param xpos Current mouse X pos.
+ * @param ypos Current mouse Y pos.
+ **/
+
+ @Override
+ public void updateScene(int xpos, int ypos){
+ TransformGroup tg = null;
+
+ if (mevent.isAltDown() && !mevent.isMetaDown()){
+
+ pickCanvas.setShapeLocation(xpos, ypos);
+ PickResult pr = pickCanvas.pickClosest();
+ if ((pr != null) &&
+ ((tg = (TransformGroup)pr.getNode(PickResult.TRANSFORM_GROUP))
+ != null) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
+ (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
+ zoom.setTransformGroup(tg);
+ zoom.wakeup();
+ currentTG = tg;
+ // Need to clean up Issue 123 --- Chien
+ // freePickResult(pr);
+ } else if (callback!=null)
+ callback.transformChanged( PickingCallback.NO_PICK, null );
+ }
+ }
+
+ /**
+ * Callback method from MouseZoom
+ * This is used when the Picking callback is enabled
+ */
+ @Override
+ public void transformChanged( int type, Transform3D transform ) {
+ callback.transformChanged( PickingCallback.ZOOM, currentTG );
+ }
+
+ /**
+ * Register the class @param callback to be called each
+ * time the picked object moves
+ */
+ public void setupCallback( PickingCallback callback ) {
+ this.callback = callback;
+ if (callback==null)
+ zoom.setupCallback( null );
+ else
+ zoom.setupCallback( this );
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/PickingCallback.java b/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/PickingCallback.java
new file mode 100644
index 0000000..7663b37
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/PickingCallback.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.picking.behaviors;
+
+import org.jogamp.java3d.TransformGroup;
+
+/**
+ * The PickingCallback interface allows a class to be notified when a
+ * picked object is moved. The class that is interested in object
+ * movement implements this interface, and the object created with
+ * that class is registered with the desired subclass of
+ * PickMouseBehavior using the OBSOLETE: provides picking behaviors for the old picking
+methods. OBSOLETE: provides picking utility classes for the old
+picking methods.
+ * If the file does not contain universe information, null is returned.
+ *
+ * @param attachBranchGraphs load and attach all the branchgraphs
+ * to the universe.
+ * @see ConfiguredUniverse#getConfigURL
+ */
+ public ConfiguredUniverse readUniverse(boolean attachBranchGraphs ) throws IOException {
+ return fileControl.readUniverse( attachBranchGraphs, null );
+ }
+
+ /**
+ * Set the ClassLoader used to load the scene graph objects and
+ * deserialize user data
+ */
+ public void setClassLoader( ClassLoader classLoader ) {
+ fileControl.setClassLoader( classLoader );
+ }
+
+ /**
+ * Get the ClassLoader used to load the scene graph objects and
+ * deserialize user data
+ */
+ public ClassLoader getClassLoader() {
+ return fileControl.getClassLoader();
+ }
+
+ /**
+ * Create and return a ConfiguredUniverse with the PlatformGeometry, ViewerAvatar,
+ * and Locales saved in the file. The MultiTransformGroup between the ViewingPlatform
+ * and the View is also restored.
+ * If the file does not contain universe information, null is returned.
+ *
+ * @param attachBranchGraphs load and attach all the branchgraphs
+ * to the universe.
+ * @param canvas The canvas to be associated with the Universe.
+ */
+ public ConfiguredUniverse readUniverse(boolean attachBranchGraphs,
+ Canvas3D canvas) throws IOException {
+ return fileControl.readUniverse( attachBranchGraphs, canvas );
+ }
+
+ /**
+ * Get the UserData in the File header
+ */
+ public Object readUserData() throws IOException {
+ return fileControl.getUserData();
+ }
+
+ /**
+ * Get the Description of this file's contents
+ */
+ public String readDescription() throws IOException {
+ return fileControl.readFileDescription();
+ }
+
+ /**
+ * Return the number of BranchGraphs in the file
+ */
+ public int getBranchGraphCount() {
+ return fileControl.getBranchGraphCount();
+ }
+
+ /**
+ * Read the BranchGraph at index in the file. If the graph
+ * contains references to nodes in other BranchGraphs that have not already been
+ * loaded, they will also be loaded and returned.
+ *
+ * The requested graph will always be the first element in the array.
+ *
+ * The file index of all the Graphs can be discovered using
+ *
+ * @param index The index of the Graph in the file. First graph is at index 0
+ *
+ * @see #getBranchGraphPosition( BranchGroup graph )
+ *
+ */
+ public BranchGroup[] readBranchGraph(int index) throws IOException {
+ return fileControl.readBranchGraph( index );
+ }
+
+ /**
+ * Read and return all the branchgraphs in the file
+ */
+ public BranchGroup[] readAllBranchGraphs() throws IOException {
+ return fileControl.readAllBranchGraphs();
+ }
+
+ /**
+ * Remove the IO system's reference to this branchgraph and all its nodes.
+ *
+ * References to all loaded graphs are maintained by the IO system in
+ * order to facilitate node and component sharing between the graphs.
+ *
+ * This call removes the references to graph
+ *
+ * NOT CURRENTLY IMPLEMENTED
+ */
+ public void dereferenceBranchGraph( BranchGroup graph ) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ /**
+ * Given a BranchGraph that has been loaded return the index of the
+ * graph in the file. The the Branchgroup isn't found, -1 is returned.
+ */
+ public int getBranchGraphPosition( BranchGroup graph ) {
+ return fileControl.getBranchGraphPosition( graph );
+ }
+
+ /**
+ * Read the userdata for the branchgraph at 'index' in the file
+ *
+ * @param index the index of the graph in the file
+ */
+ public Object readBranchGraphUserData( int index ) throws IOException {
+ return fileControl.readBranchGraphUserData( index );
+ }
+
+ /**
+ * Return the names of all the named objects
+ */
+ public String[] getNames() {
+ return fileControl.getNames();
+ }
+
+ /**
+ * Return the named object.
+ *
+ * @param name The name of the object
+ *
+ * @exception NamedObjectException is thrown if the name is not known to the system
+ * @exception ObjectNotLoadedException is thrown if the named object has not been loaded yet
+ */
+ public SceneGraphObject getNamedObject( String name ) throws NamedObjectException, ObjectNotLoadedException {
+ return fileControl.getNamedObject( name );
+ }
+
+ /**
+ * Close the file and cleanup internal data structures
+ */
+ public void close() throws IOException {
+ fileControl.close();
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphFileWriter.java b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphFileWriter.java
new file mode 100644
index 0000000..836b07e
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphFileWriter.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.scenegraph.io;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.SceneGraphObject;
+
+import org.jogamp.java3d.utils.scenegraph.io.retained.RandomAccessFileControl;
+import org.jogamp.java3d.utils.universe.SimpleUniverse;
+
+/**
+ * Write a (set) of Java3D BranchGraphs and/or Universe to a file. The BranchGraphs
+ * are stored in the order in which they are written, they can be read in any order
+ * using SceneGraphFileReader.
+ *
+ * The API handles Nodes and NodeComponents that are shared between seperate
+ * graphs. It will handle all Java3D 1.3 core classes and any user
+ * subclass of a Node or NodeComponent that implements the SceneGraphIO
+ * interface.
+ */
+public class SceneGraphFileWriter extends java.lang.Object {
+
+ private RandomAccessFileControl fileControl;
+ private File file;
+
+ /** Creates new SceneGraphFileWriter and opens the file for writing.
+ *
+ * Writes the
+ * Java3D Universe structure to the file. This includes the number and position of
+ * the Locales, PlatformGeometry, ViewerAvatar, and the MultitransformGroup between
+ * the ViewingPlatform and the View. However this
+ * call does not write the content of the branch graphs unless writeUniverseContent is true.
+ * close() MUST be called when IO is complete. If close() is not called
+ * the file contents will be undefined.
+ * Using this class to write to a FileOutputStream is not recommended. Use
+ * SceneGraphFileWriter instead to achieve maximum performance and flexibility.
+ */
+public class SceneGraphStreamWriter extends java.lang.Object {
+
+ private StreamControl control;
+ private DataOutputStream out;
+
+ /** Creates new SceneGraphStreamWriter that will write to the supplied stream */
+ public SceneGraphStreamWriter(java.io.OutputStream outputStream ) throws IOException {
+ this.out = new java.io.DataOutputStream( outputStream );
+ control = new StreamControl( out );
+ control.writeStreamHeader();
+ }
+
+
+ /**
+ * Write
+ *
+ * If
+ *
+ * If
+ *
+ * @param universe The universe to write
+ * @param writeContent Flag enabling the BranchGraphs to be written
+ *
+ * @exception IOException
+ * @exception UnsupportedUniverseException Thrown if the universe class is not
+ * supported by this implementation
+ */
+ public void writeUniverse( SimpleUniverse universe, boolean writeContent ) throws IOException, UnsupportedUniverseException {
+ control.writeUniverse( out, universe, writeContent );
+ }
+
+ /**
+ * Write the entire graph to the stream.
+ *
+ * The API will correctly handle NodeComponents that are shared
+ * between seperate graphs. However Nodes cannot be referenced
+ * in other Graphs.
+ *
+ * If a reference to a Node in another graph is encountered a
+ * DanglingReferenceException will be thrown.
+ *
+ * The scenegraph.io APIs will handle the IO for all the core Java3D
+SceneGraphObjects. However, if you create a subclass of one of these
+objects and add it to your Scene Graph, the IO system, by default,
+will not store any state information specific to your class. The default behavior when an unrecognized SceneGraphObject class
+is encountered is to traverse up the superclasses of the object until
+a recognized Java3D class is located. The data structures for this
+class are then used for IO. The system does store the class name of
+the original object.
+ For example:
+ When the Scene Graph is written to a file and this node is
+encountered, the superclass org.jogamp.java3d.BranchGroup will be used
+to store all the state for the object so any children of
+MyBranchGroup, the capabilities, etc. will be stored, but myData will
+be lost. When the scene graph is loaded, MyBranchGroup will be
+instantiated and will be populated with all the state from
+BranchGroup but myData will have been lost. To overcome this, the scenegraph.io API provides an interface for
+you to implement in your own classes that provides the opportunity
+for you to save the state of your classes during the IO processes.
+This is the SceneGraphIO interface. When the scenegraph is saved, the methods of SceneGraphIO are
+called in this order
+ createSceneGraphObjectReferences saveChildren writeSceneGraphObject During the load cycle the method call order is Instantiate Object using default constructor Populate object with state from superclasses readSceneGraphObject restoreSceneGraphObjectReferences Within each method you need to perform the following actions:
+ createSceneGraphObjectReferences If your object has
+ references to other SceneGraphObjects then you need to obtain an
+ object reference (int) for each reference using the
+ SceneGraphReferenceControl object passed as a parameter to this
+ method. If you don't have references to other SceneGraphObjects then
+ no action is required. saveChildren If your object is a subclass of Group and you
+ want the scenegraph.io package to save the children then this must
+ return true. If it returns false, the object will be saved but not
+ its children. writeSceneGraphObject In this method you must write all the
+ state information for your class, including the object references
+ obtained in createSceneGraphObjectReferences, to the DataOutput
+ stream passed into this method. readSceneGraphObject By the time this method is called your
+ class has been instantiated and the state information in the Java3D
+ superclass will have been loaded. You should load all the state
+ information you saved for your class. restoreSceneGraphObjectReferences is called once all the
+ SceneGraph objects have been loaded and allows you to restore the
+ references to the other SceneGraph objects. Here are some examples. Only the parts of the source pertaining to
+IO are show.... This package provides a Java3D SceneGraph IO capability.
+The API supports IO of a scenegraph to and from a Java Stream and/or
+RandomAccessFile. The features offered for these two io systems are
+somewhat different. The SceneGraphFileReader and SceneGraphFileWriter classes provide
+IO to and from a RandomAccessFile. They allow a universe and/or
+multiple BranchGraphs to be written to the file with Node's and
+NodeComponent's shared between the separate graphs. The graphs can be
+read in any order. SceneGraphStreamReader and SceneGraphStreamWriter classes provide
+IO to and from a Stream. These classes allow a universe and/or
+multiple BranchGraphs to be passed over stream. In contrast to the
+FileReader/Writer sharing of Node's is NOT supported between graphs
+by the API. Sharing of node components is supported. If your
+application requires references to Nodes in other graphs (such as
+SharedGroups) the application must handle the references using the
+namedObjects constructs. Note : If you use SceneGraphStreamWriter class to write to a
+FileOutputStream the resulting file cannot be read using the
+SceneGraphFileReader, the converse is also true, you can not use a
+FileInputStream to load a file written by SceneGraphFileWriter.
+
+The package supports the IO of all the Java3D 1.3 core classes
+and many of the utilities. It also includes interfaces which can be
+implemented to allow user defined subclasses of SceneGraphObjects to
+be stored. Information on the extensibility can be found
+here
+
+The package has a number of properties which can be used to control the IO
+behavior
+
+
+
+j3d.io.ImageCompression this can be set to None, GZIP, JPEG and tells the
+IO system to compress images in the .j3f file using the prescribed technique. In
+the future this will be extended to support all the formats available in
+javax.imageio in JDK 1.4.
+ Provides transparency sorting utility classes. Provides shader utility classes. Deprecated: Use java.lang.System.nanoTime() instead.
+ *
+ * As of Java 3D 1.3.1, this is handled the same as an attribute.
+ * The individual setProperty() method implementations of
+ * ConfigObject determine whether the method to set the property can
+ * be invoked directly or through introspection. If through
+ * introspection, then the evaluation of the property must be
+ * delayed until the target object is instantiated.
+ */
+ static final int PROPERTY = 2 ;
+
+ /**
+ * Specifies that this command creates an alias for a ConfigObject of the
+ * same base name.
+ */
+ static final int ALIAS = 3 ;
+
+ /**
+ * Specifies that this command is a deferred built-in command that can't
+ * be immediately evaluated by the parser. Its evaluation is delayed
+ * until all config objects are instantiated and their properties can be
+ * evaluated.
+ */
+ static final int BUILTIN = 4 ;
+
+ /**
+ * Specifies that this command is an include file directive.
+ */
+ static final int INCLUDE = 5 ;
+
+ /**
+ * Specifes that this command is entirely processed by the
+ * constructor and should be ignored by subsequent recipients.
+ */
+ static final int IGNORE = 6 ;
+
+ /**
+ * The type of this command, either CREATE, PROPERTY, ALIAS,
+ * BUILTIN, INCLUDE, or IGNORE.
+ */
+ int type = -1 ;
+
+ /**
+ * The number of arguments in this command, including the command
+ * name.
+ */
+ int argc = 0 ;
+
+ /**
+ * An array containing all of this command's arguments, including
+ * the command name.
+ */
+ Object[] argv = null ;
+
+ /**
+ * The name of the command being invoked, which is always the first
+ * argument of the command.
+ */
+ String commandName = null ;
+
+ /**
+ * The base name of this command, from which the name of the ConfigObject
+ * subclass that processes it is derived. This is constructed by
+ * stripping off the leading "New" prefix or the trailing "Attribute",
+ * "Property", or "Alias" suffix of the command name. The name of the
+ * ConfigObject subclass which handles the command is derived by adding
+ * "Config" as a prefix to the base name.
+ */
+ String baseName = null ;
+
+ /**
+ * The instance name of the ConfigObject subclass which processes this
+ * command. Together with the base name this provides the handle by which
+ * a ConfigObject can be referenced by other commands in the configuration
+ * file.
+ */
+ String instanceName = null ;
+
+ /**
+ * The file from which this command was read.
+ */
+ String fileName = null ;
+
+ /**
+ * The line number from which this command was read.
+ */
+ int lineNumber = 0 ;
+
+ /**
+ * Constructs a ConfigCommand from configuration file command arguments.
+ *
+ * @param elements arguments to this command, including the command name
+ * @param fileName name of the file from where the command was read
+ * @param lineNumber line number where the command is found in the file
+ */
+ ConfigCommand(Collection elements, String fileName, int lineNumber) {
+ this.fileName = fileName ;
+ this.lineNumber = lineNumber ;
+
+ argc = elements.size() ;
+ argv = elements.toArray(new Object[0]) ;
+
+ if (! (argc > 0 && (argv[0] instanceof String)))
+ throw new IllegalArgumentException("malformed command") ;
+
+ commandName = (String)argv[0] ;
+
+ if (commandName.startsWith("New")) {
+ type = CREATE ;
+ baseName = commandName.substring(3) ;
+ instanceName = checkName(argv[1]) ;
+ }
+ else if (commandName.endsWith("Property")) {
+ baseName = commandName.substring(0, commandName.length()-8) ;
+ if (baseName.equals("Java")) {
+ type = IGNORE ;
+ processJavaProperty(argc, argv) ;
+ }
+ else {
+ type = PROPERTY ;
+ instanceName = checkName(argv[1]) ;
+ }
+ }
+ else if (commandName.endsWith("Attribute")) {
+ // Backward compatibility.
+ type = PROPERTY ;
+ baseName = commandName.substring(0, commandName.length()-9) ;
+ instanceName = checkName(argv[1]) ;
+ }
+ else if (commandName.endsWith("Alias")) {
+ type = ALIAS ;
+ baseName = commandName.substring(0, commandName.length()-5) ;
+ instanceName = checkName(argv[1]) ;
+ }
+ else if (commandName.equals("Include")) {
+ type = INCLUDE ;
+ }
+ else {
+ type = BUILTIN ;
+ }
+
+ // We allow "Window" as an equivalent to "Screen".
+ if (baseName != null && baseName.equals("Window"))
+ baseName = "Screen" ;
+ }
+
+ /**
+ * Sets the Java property specified in the command. If the command
+ * has 3 arguments then it's an unconditional assignment. If the
+ * 3rd argument is "Default", then the property is set to the value
+ * of the 4th argument only if the specified property has no
+ * existing value.
+ *
+ * @param argc the number of arguments in the command
+ * @param argv command arguments as an array of Objects; the 1st is
+ * the command name (ignored), the 2nd is the name of the Java
+ * property, the 3rd is the value to be set or the keyword
+ * "Default", and the 4th is thevalue to be set if the Java
+ * property doesn't already exist
+ */
+ private static void processJavaProperty(int argc, Object[] argv) {
+ for (int i = 1 ; i < argc ; i++) {
+ // Check args.
+ if (argv[i] instanceof Boolean) {
+ argv[i] = ((Boolean)argv[i]).toString() ;
+ }
+ else if (! (argv[i] instanceof String)) {
+ throw new IllegalArgumentException
+ ("JavaProperty arguments must be Strings or Booleans") ;
+ }
+ }
+ if (argc == 3) {
+ // Unconditional assignment.
+ setJavaProperty((String)argv[1], (String)argv[2]) ;
+ }
+ else if (argc != 4) {
+ // Conditional assignment must have 4 args.
+ throw new IllegalArgumentException
+ ("JavaProperty must have either 2 or 3 arguments") ;
+ }
+ else if (! ((String)argv[2]).equals("Default")) {
+ // Penultimate arg must be "Default" keyword.
+ throw new IllegalArgumentException
+ ("JavaProperty 2nd argument must be \"Default\"") ;
+ }
+ else if (evaluateJavaProperty((String)argv[1]) == null) {
+ // Assignment only if no existing value.
+ setJavaProperty((String)argv[1], (String)argv[3]) ;
+ }
+ }
+
+ /**
+ * Sets the given Java system property if allowed by the security manager.
+ *
+ * @param key property name
+ * @param value property value
+ * @return previous property value if any
+ */
+ static String setJavaProperty(final String key, final String value) {
+ return (String)java.security.AccessController.doPrivileged
+ (new java.security.PrivilegedAction() {
+ @Override
+ public Object run() {
+ return System.setProperty(key, value) ;
+ }
+ }) ;
+ }
+
+ /**
+ * Evaluates the specified Java property string if allowed by the security
+ * manager.
+ *
+ * @param key string containing a Java property name
+ * @return string containing the Java property valaue
+ */
+ static String evaluateJavaProperty(final String key) {
+ return (String)java.security.AccessController.doPrivileged
+ (new java.security.PrivilegedAction() {
+ @Override
+ public Object run() {
+ return System.getProperty(key) ;
+ }
+ }) ;
+ }
+
+ /**
+ * Checks if the given object is an instance of String.
+ *
+ * @param o the object to be checked
+ * @return the object cast to a String
+ * @exception IllegalArgumentException if the object is not a String
+ */
+ private final String checkName(Object o) {
+ if (! (o instanceof String))
+ throw new IllegalArgumentException
+ ("second argument to \"" + commandName + "\" must be a name") ;
+
+ return (String)o ;
+ }
+
+ /**
+ * Calls
+ *
+ * Clients can construct the view side of a scene graph by retrieving these
+ * objects using the accessor methods provided by this class. This could
+ * involve as little as just attaching ViewingPlatforms to a Locale, depending
+ * upon how completely the viewing configuration is specified in the file.
+ * The ConfiguredUniverse class is an example of a ConfigContainer client and
+ * how it can be used.
+ *
+ * ConfigContainer can be useful for clients other than ConfiguredUniverse.
+ * InputDevice and ViewPlatformBehavior configuration is fully supported, so a
+ * given Java 3D installation can provide configuration files to an
+ * application that will allow it to fully utilize whatever site-specific
+ * devices and behaviors are available. The configuration mechanism can be
+ * extended for any target object through the use of the
+ *
+ *
+ * Normally the flag should be true. However, when instantiated by
+ * ConfiguredUniverse, this flag is set false so that ConfiguredUniverse
+ * can set a reference to itself in the ViewingPlatform before attaching
+ * the behavior. This provides backwards compatibility to behaviors that
+ * access the ConfiguredUniverse instance from a call to
+ *
+ *
+ * The preferred methods to retrieve instances of specific objects defined
+ * in the configuration file are to either 1) get the ConfiguredUniverse
+ * instance when the behavior's
+ *
+ * (New{baseName} {instanceName} ... [Alias {aliasName}])
+ *
+ * The first two command elements and the optional trailing Alias syntax
+ * are processed here, at which point the subclass implementation of
+ * initialize() is called. Subclasses must override initialize() if they
+ * need to process more than what is processed by default here.
+ *
+ * @param cmd configuration command that creates a new ConfigObject
+ */
+ private ConfigObject createConfigObject(ConfigCommand cmd) {
+ Class objectClass = null ;
+ ConfigObject configObject = null ;
+
+ // Instantatiate the ConfigObject if possible. This is not the target
+ // object, but an object that will gather configuration properties,
+ // instantiate the target object, and then apply the configuration
+ // properties to it.
+ try {
+ objectClass = Class.forName("org.jogamp.java3d.utils.universe.Config" +
+ cmd.baseName) ;
+ }
+ catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException
+ ("\"" + cmd.baseName + "\"" +
+ " is not a configurable object; ignoring command") ;
+ }
+ try {
+ configObject = (ConfigObject)(objectClass.newInstance()) ;
+ }
+ catch (IllegalAccessException e) {
+ System.out.println(e) ;
+ throw new IllegalArgumentException("Ignoring command") ;
+ }
+ catch (InstantiationException e) {
+ System.out.println(e) ;
+ throw new IllegalArgumentException("Ignoring command") ;
+ }
+
+ // Process an Alias keyword if present. This option is available for
+ // all New commands so it is processed here. The Alias keyword must
+ // be the penultimate command element, followed by a String.
+ for (int i = 2 ; i < cmd.argc ; i++) {
+ if (cmd.argv[i] instanceof String &&
+ ((String)cmd.argv[i]).equals("Alias")) {
+ if (i == (cmd.argc - 2) && cmd.argv[i+1] instanceof String) {
+ addConfigObject(new ConfigAlias(cmd.baseName,
+ (String)cmd.argv[i+1],
+ configObject)) ;
+ cmd.argc -= 2 ;
+ }
+ else {
+ throw new IllegalArgumentException
+ ("The alias name must be a string and " +
+ "must be the last command argument") ;
+ }
+ }
+ }
+
+ // Initialize common fields.
+ configObject.baseName = cmd.baseName ;
+ configObject.instanceName = cmd.instanceName ;
+ configObject.creatingCommand = cmd ;
+ configObject.configContainer = this ;
+
+ // Initialize specific fields and return the ConfigObject.
+ configObject.setClassLoader(classLoader);
+ configObject.initialize(cmd) ;
+ return configObject ;
+ }
+
+ /**
+ * Instantiate and initialize a ConfigObject base class containing alias
+ * information. The command is of the form:
+ *
+ * ({baseName}Alias {aliasName} {originalName})
+ *
+ * @param cmd configuration command that creates a new alias
+ * @return the new ConfigObject with alias information
+ */
+ private ConfigObject createConfigAlias(ConfigCommand cmd) {
+ ConfigObject original ;
+
+ if (cmd.argc != 3 || ! (cmd.argv[2] instanceof String))
+ throw new IllegalArgumentException
+ ("Command \"" + cmd.commandName +
+ "\" requires an instance name as second argument") ;
+
+ original = findConfigObject(cmd.baseName, (String)cmd.argv[2]) ;
+ return new ConfigAlias(cmd.baseName, cmd.instanceName, original) ;
+ }
+
+ /**
+ * A class that does nothing but reference another ConfigObject. Once
+ * created, the alias name can be used in all commands that would accept
+ * the original name. A lookup of the alias name will always return the
+ * original instance.
+ */
+ private static class ConfigAlias extends ConfigObject {
+ ConfigAlias(String baseName, String instanceName, ConfigObject targ) {
+ this.baseName = baseName ;
+ this.instanceName = instanceName ;
+ this.isAlias = true ;
+ this.original = targ ;
+ targ.aliases.add(instanceName) ;
+ }
+ }
+
+ /**
+ * Adds the specified ConfigObject instance into this container using the
+ * given ConfigCommand's base name and instance name.
+ *
+ * @param object the ConfigObject instance to add into the database
+ */
+ private void addConfigObject(ConfigObject object) {
+ ArrayList instances ;
+
+ instances = (ArrayList)baseNameMap.get(object.baseName) ;
+ if (instances == null) {
+ instances = new ArrayList() ;
+ baseNameMap.put(object.baseName, instances) ;
+ }
+
+ // Disallow duplicate instance names.
+ for (int i = 0 ; i < instances.size() ; i++) {
+ ConfigObject co = (ConfigObject)instances.get(i) ;
+ if (co.instanceName.equals(object.instanceName)) {
+ // Don't confuse anybody using Window.
+ String base = object.baseName ;
+ if (base.equals("Screen")) base = "Screen or Window" ;
+ throw new IllegalArgumentException
+ ("Duplicate " + base + " instance name \"" +
+ object.instanceName + "\" ignored") ;
+ }
+ }
+
+ instances.add(object) ;
+ }
+
+ /**
+ * Finds a config object matching the given base name and the instance
+ * name. If an alias is found, then its original is returned. If the
+ * object is not found, an IllegalArgumentException is thrown.
+ *
+ * @param basename base name of the config object
+ * @param instanceName name associated with this config object instance
+ * @return the found ConfigObject
+ */
+ ConfigObject findConfigObject(String baseName, String instanceName) {
+ ArrayList instances ;
+ ConfigObject configObject ;
+
+ instances = (ArrayList)baseNameMap.get(baseName) ;
+ if (instances != null) {
+ for (int i = 0 ; i < instances.size() ; i++) {
+ configObject = (ConfigObject)instances.get(i) ;
+
+ if (configObject.instanceName.equals(instanceName)) {
+ if (configObject.isAlias)
+ return configObject.original ;
+ else
+ return configObject ;
+ }
+ }
+ }
+
+ // Throw an error, but don't confuse anybody using Window.
+ if (baseName.equals("Screen")) baseName = "Screen or Window" ;
+ throw new IllegalArgumentException
+ (baseName + " \"" + instanceName + "\" not found") ;
+ }
+
+ /**
+ * Find instances of config objects with the given base name.
+ * This is the same as
+ *
+ *
+ *
+ * PhysicalEnvironment instances are created with the following command:
+ *
+ *
+ *
+ * Viewer instances are created with the following command:
+ *
+ *
+ *
+ * @return read-only Map from names to Viewer instances, or
+ * null if no instances
+ */
+ public Map getNamedViewers() {
+ if (viewerMap != null) return viewerMap ;
+ viewerMap = createMap("View") ;
+ return viewerMap ;
+ }
+
+ /**
+ * Returns a read-only Set of all configured InputDevice instances in the
+ * order they were defined in the configuration file. All InputDevice
+ * instances in the set are initialized and registered with any
+ * PhysicalEnvironments that reference them.
+ *
+ * InputDevice instances are created with the following command:
+ *
+ *
+ * The InputDevice is configured through the DeviceProperty command:
+ *
+ *
+ * Sensor instances are named with the following command:
+ *
+ *
+ * The Sensor is configured through the SensorProperty command:
+ *
+ *
+ * With the sole exception of the Sensor assigned to the head tracker,
+ * none of the Sensors defined in the configuration file are placed into
+ * the Sensor array maintained by a PhysicalEnvironment.
+ *
+ * @return read-only Map from names to Sensor instances, or
+ * null if no instances
+ */
+ public Map getNamedSensors() {
+ if (sensorMap != null) return sensorMap ;
+ sensorMap = createMap("Sensor") ;
+ return sensorMap ;
+ }
+
+ /**
+ * Returns a read-only Set of all configured ViewingPlatform instances in
+ * the order they were defined in the configuration file. The
+ * ConfigContainer class itself does not attach the ViewingPlatform
+ * instances to any scengraph components or universe Locales; they are not
+ * "live" until made so by a separate client such as ConfiguredUniverse.
+ *
+ * ViewingPlatform instances are created with the following command:
+ *
+ *
+ *
+ * The behaviors are attached to any ViewingPlatforms that specified them;
+ * that is, the
+ *
+ * ViewPlatformBehavior instances are created by the following command:
+ *
+ *
+ * The behavior is configured using ViewPlatformBehaviorProperty:
+ *
+ *
+ * Concrete ViewPlatformBehavior instances can also define their own
+ * unique properties. In those cases, propertyName must be the
+ * name of a behavior method that takes an array of Objects as its only
+ * parameter; the array is populated with the values of arg0
+ * through argn when the method is invoked to set the property.
+ * These additional requirements for configurable behaviors can usually be
+ * fulfilled by extending or wrapping available ViewPlatformBehavior
+ * subclasses.
+ *
+ * @return read-only Set of all unique instances, or null
+ */
+ public Set getViewPlatformBehaviors() {
+ if (behaviors != null) return behaviors ;
+ behaviors = createSet("ViewPlatformBehavior") ;
+ return behaviors ;
+ }
+
+ /**
+ * Returns a read-only Map that maps ViewPlatformBehavior names to
+ * instances. Names may be aliases and if so will map to the original
+ * instances.
+ *
+ * The behaviors are attached to any ViewingPlatforms that specified them;
+ * that is, the
+ *
+ * @return read-only Map from names to ViewPlatformBehavior instances, or
+ * null if no instances
+ * @see #getViewPlatformBehaviors
+ */
+ public Map getNamedViewPlatformBehaviors() {
+ if (behaviorMap != null) return behaviorMap ;
+ behaviorMap = createMap("ViewPlatformBehavior") ;
+ return behaviorMap ;
+ }
+
+ /**
+ * Returns a read-only Map containing the named Canvas3D instances used by
+ * the specified Viewer. Names may be aliases and if so will map to the
+ * original instances. The set of unique Canvas3D instances used by a
+ * Viewer may be obtained by calling the Viewer's accessor methods
+ * directly.
+ *
+ * A named Canvas3D is created and added to a Viewer whenever any of the
+ * following configuration commands are used:
+ *
+ *
+ * Generic object instances are created with the following command:
+ *
+ *
+ * The object is configured through the ObjectProperty command:
+ *
+ *
+ * Generic base implementations are provided for the initialize(),
+ * setProperty(), and processProperties() methods. These implementations
+ * assume target objects that are unknown and thus instantiated via
+ * introspection. Property names are assumed to be method names that take an
+ * array of Objects as a parameter; they are invoked through introspection as
+ * well.
+ *
+ * Most ConfigObjects target concrete Java 3D core classes, so these
+ * implementations are usually overridden to instantiate those objects and
+ * call their methods directly.
+ */
+class ConfigObject {
+ /**
+ * The base name of this object, derived from the configuration command
+ * which created it. This is constructed by stripping off the leading
+ * "New" prefix or the trailing "Attribute", "Property", or "Alias" suffix
+ * of the command name. The name of the ConfigObject subclass which
+ * handles the command is derived by adding "Config" as a prefix to the
+ * base name.
+ */
+ String baseName = null ;
+
+ /**
+ * The instance name of this object, as specified in the configuration
+ * file.
+ */
+ String instanceName = null ;
+
+ /**
+ * The corresponding target object which this ConfigObject is configuring.
+ */
+ Object targetObject = null ;
+
+ /**
+ * The name of the target class this object is configuring.
+ */
+ String targetClassName = null ;
+
+ /**
+ * The Class object for the target.
+ */
+ Class targetClass = null ;
+
+ /**
+ * Configurable properties gathered by this object, represented by the
+ * ConfigCommands that set them.
+ */
+ List properties = new ArrayList() ;
+
+ /**
+ * The ConfigContainer in which this ConfigObject is contained.
+ */
+ ConfigContainer configContainer = null ;
+
+ /**
+ * The command that created this class.
+ */
+ ConfigCommand creatingCommand = null ;
+
+ /**
+ * If true, this object is an alias to another.
+ */
+ boolean isAlias = false ;
+
+ /**
+ * If isAlias is true, this references the original object.
+ */
+ ConfigObject original = null ;
+
+ /**
+ * List of alias Strings for this object if it's not an alias itself.
+ */
+ List aliases = new ArrayList() ;
+
+ protected ClassLoader classLoader;
+
+ /**
+ * @param classLoader the ClassLoader to use when loading the implementation
+ * class for this object
+ */
+ void setClassLoader( ClassLoader classLoader ) {
+ this.classLoader = classLoader;
+ }
+
+ /**
+ * The base initialize() implementation. This takes a ConfigCommand with
+ * three arguments: the command name, the instance name, and the name of
+ * the target class this ConfigObject is configuring. The command in the
+ * configuration file should have the form:
+ *
+ * (New{configType} {instanceName} {className})
+ *
+ * For example, (NewDevice tracker org.jogamp.java3d.input.LogitechTracker) will
+ * first cause ConfigDevice to be instantiated, which will then be
+ * initialized with this method. After all the properties are collected,
+ * ConfigDevice will instantiate org.jogamp.java3d.input.LogitechTracker,
+ * evaluate its properties, and allow references to it in the
+ * configuration file by the name "tracker".
+ *
+ * It's assumed the target class will be instantiated through
+ * introspection and its properties set through introspection as well.
+ * Most config objects (ConfigScreen, ConfigView, ConfigViewPlatform,
+ * ConfigPhysicalBody, and ConfigPhysicalEnvironment) target a concrete
+ * core Java 3D class and will instantiate them directly, so they override
+ * this method.
+ *
+ * @param c the command that created this ConfigObject
+ */
+ protected void initialize(ConfigCommand c) {
+ if (c.argc != 3) {
+ syntaxError("Wrong number of arguments to " + c.commandName) ;
+ }
+
+ if (!isName(c.argv[1])) {
+ syntaxError("The first argument to " + c.commandName +
+ " must be the instance name") ;
+ }
+
+ if (!isName(c.argv[2])) {
+ syntaxError("The second argument to " + c.commandName +
+ " must be the class name") ;
+ }
+
+ targetClassName = (String)c.argv[2] ;
+ }
+
+ /**
+ * The base setProperty() implementation. This implementation assumes the
+ * property needs to be set by introspection on the property name as a
+ * method that accepts an array of Objects. That is, the command in the
+ * configuration file is of the form:
+ *
+ * ({type}Property {instance name} {method name} {arg0} ... {argn})
+ *
+ * For example, (DeviceProperty tracker SerialPort "/dev/ttya") will
+ * invoke the method named "SerialPort" in the object referenced by
+ * "tracker" with an array of 1 Object containing the String
+ * "/dev/ttya".
+ *
+ * The property is stored as the original ConfigCommand and is evaluated
+ * after the configuration file has been parsed. It is overridden by
+ * subclasses that instantiate concrete core Java 3D classes with known
+ * method names.
+ *
+ * @param c the command that invoked this method
+ */
+ protected void setProperty(ConfigCommand c) {
+ if (c.argc < 4) {
+ syntaxError("Wrong number of arguments to " + c.commandName) ;
+ }
+
+ if (!isName(c.argv[1])) {
+ syntaxError("The first argument to " + c.commandName +
+ " must be the instance name") ;
+ }
+
+ if (!isName(c.argv[2])) {
+ syntaxError("The second argument to " + c.commandName +
+ " must be the property name") ;
+ }
+
+ properties.add(c) ;
+ }
+
+ /**
+ * Instantiates the target object.
+ */
+ protected Object createTargetObject() {
+ if (targetClassName == null)
+ return null ;
+
+ targetClass = getClassForName(creatingCommand, targetClassName) ;
+ targetObject = getNewInstance(creatingCommand, targetClass) ;
+
+ return targetObject ;
+ }
+
+ /**
+ * Return the class for the specified class name string.
+ *
+ * @param className the name of the class
+ * @return the object representing the class
+ */
+ protected Class getClassForName(ConfigCommand cmd, String className) {
+ try {
+ // Use the system class loader. If the Java 3D jar files are
+ // installed directly in the JVM's lib/ext directory, then the
+ // default class loader won't find user classes outside ext.
+ //
+ // From 1.3.2 we use the classLoader supplied to this object,
+ // normally this will be the system class loader, but for webstart
+ // apps the user can supply another class loader.
+ return Class.forName(className, true,
+ classLoader) ;
+ }
+ catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException
+ (errorMessage(cmd, "Class \"" + className + "\" not found")) ;
+ }
+ }
+
+ /**
+ * Return an instance of the class specified by the given class object.
+ *
+ * @param objectClass the object representing the class
+ * @return a new instance of the class
+ */
+ protected Object getNewInstance(ConfigCommand cmd, Class objectClass) {
+ try {
+ return objectClass.newInstance() ;
+ }
+ catch (IllegalAccessException e) {
+ throw new IllegalArgumentException
+ (errorMessage(cmd, "Illegal access to object class")) ;
+ }
+ catch (InstantiationException e) {
+ throw new IllegalArgumentException
+ (errorMessage(cmd, "Instantiation error for object class")) ;
+ }
+ }
+
+ /**
+ * Evaluate properties for the the given class instance. The property
+ * names are used as the names of methods to be invoked by the instance.
+ * Each such method takes an array of Objects as its only parameter. The
+ * array will contain Objects corresponding to the property values.
+ */
+ protected void processProperties() {
+ evaluateProperties(this.targetClass,
+ this.targetObject, this.properties) ;
+
+ // Potentially holds a lot of references, and not needed anymore.
+ this.properties.clear() ;
+ }
+
+ /**
+ * Evaluate properties for the the given class instance.
+ *
+ * @param objectClass the class object representing the given class
+ * @param objectInstance the class instance whose methods will be invoked
+ * @param properties list of property setting commands
+ */
+ protected void evaluateProperties(Class objectClass,
+ Object objectInstance,
+ List properties) {
+
+ // Holds the single parameter passed to the class instance methods.
+ Object[] parameters = new Object[1] ;
+
+ // Specifies the class of the single method parameter.
+ Class[] parameterTypes = new Class[1] ;
+
+ // All property methods use Object[] as their single parameter, which
+ // happens to be the same type as the parameters variable above.
+ parameterTypes[0] = parameters.getClass() ;
+
+ // Loop through all property commands and invoke the appropriate
+ // method for each one. Property commands are of the form:
+ // ({configClass}Property {instanceName} {methodName} {arg} ...)
+ for (int i = 0 ; i < properties.size() ; i++) {
+ ConfigCommand cmd = (ConfigCommand)properties.get(i) ;
+ String methodName = (String)cmd.argv[2] ;
+ Object[] argv = new Object[cmd.argc - 3] ;
+
+ for (int a = 0 ; a < argv.length ; a++) {
+ argv[a] = cmd.argv[a + 3] ;
+ if (argv[a] instanceof ConfigCommand) {
+ // Evaluate a delayed built-in command.
+ ConfigCommand bcmd = (ConfigCommand)argv[a] ;
+ argv[a] = configContainer.evaluateBuiltIn(bcmd) ;
+ }
+ }
+
+ parameters[0] = argv ;
+
+ try {
+ Method objectMethod =
+ objectClass.getMethod(methodName, parameterTypes) ;
+
+ objectMethod.invoke(objectInstance, parameters) ;
+ }
+ catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException
+ (errorMessage
+ (cmd, "Unknown property \"" + methodName + "\"")) ;
+ }
+ catch (IllegalAccessException e) {
+ throw new IllegalArgumentException
+ (errorMessage
+ (cmd, "Illegal access to \"" + methodName + "\"")) ;
+ }
+ catch (InvocationTargetException e) {
+ throw new IllegalArgumentException
+ (errorMessage(cmd, e.getTargetException().getMessage())) ;
+ }
+ }
+ }
+
+ /**
+ * Throws an IllegalArgumentException with the specified description.
+ * This is caught by the parser which prints out error diagnostics and
+ * continues parsing if it can.
+ *
+ * @param s string describing the syntax error
+ */
+ protected void syntaxError(String s) {
+ throw new IllegalArgumentException(s) ;
+ }
+
+ /**
+ * Constructs an error message from the given string and file information
+ * from the given command.
+ */
+ static String errorMessage(ConfigCommand cmd, String s) {
+ return
+ s + "\nat line " + cmd.lineNumber +
+ " in " + cmd.fileName + "\n" + cmd;
+ }
+
+ /**
+ * Check if the argument is a name string.
+ *
+ * @param o the object to be checked
+ * @return true if the object is an instance of String
+ */
+ protected boolean isName(Object o) {
+ return (o instanceof String) ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfigPhysicalBody.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigPhysicalBody.java
new file mode 100644
index 0000000..a45e66a
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigPhysicalBody.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe;
+
+import org.jogamp.java3d.PhysicalBody;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.vecmath.Matrix4d;
+import org.jogamp.vecmath.Point3d;
+
+class ConfigPhysicalBody extends ConfigObject {
+
+ Point3d leftEyePosition = new Point3d(-0.033, 0.0, 0.0);
+ Point3d rightEyePosition = new Point3d(0.033, 0.0, 0.0);
+ double stereoEyeSeparation = Double.MAX_VALUE;
+
+ Point3d leftEarPosition = new Point3d(-0.080, -0.030, 0.09);
+ Point3d rightEarPosition = new Point3d(0.080, -0.030, 0.09);
+
+ double nominalEyeHeightFromGround = 1.68;
+ double nominalEyeOffsetFromNominalScreen = 0.4572;
+
+ Matrix4d headToHeadTracker = new Matrix4d(
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0);
+
+ PhysicalBody j3dPhysicalBody;
+
+ // Overridden to do nothing.
+ @Override
+ protected void initialize(ConfigCommand command) {
+ }
+
+ @Override
+ protected void setProperty(ConfigCommand command) {
+ int argc = command.argc;
+ Object[] argv = command.argv;
+ String prop;
+ Object val;
+
+ // Check that arg[1] and arg[2] are strings
+ if (argc != 4) {
+ syntaxError("Incorrect number of arguments to " +
+ command.commandName);
+ }
+
+ if (!isName(argv[1])) {
+ syntaxError("The first argument to " + command.commandName +
+ " must be a name");
+ }
+
+ if (!isName(argv[2])) {
+ syntaxError("The second argument to " + command.commandName +
+ " must be an property/attribute name");
+ }
+
+ prop = (String) argv[2];
+ val = argv[3];
+
+ if (prop.equals("StereoEyeSeparation")) {
+ if (!(val instanceof Double)) {
+ syntaxError("StereoEyeSeparation must be a number");
+ }
+ stereoEyeSeparation = ((Double) val).doubleValue();
+ }
+ else if (prop.equals("LeftEyePosition")) {
+ if (!(val instanceof Point3d)) {
+ syntaxError("LeftEyePosition must be a point");
+ }
+ leftEyePosition = (Point3d) val;
+ }
+ else if (prop.equals("RightEyePosition")) {
+ if (!(val instanceof Point3d)) {
+ syntaxError("RightEyePosition must be a point");
+ }
+ rightEyePosition = (Point3d) val;
+ }
+ else if (prop.equals("LeftEarPosition")) {
+ if (!(val instanceof Point3d)) {
+ syntaxError("LeftEarPosition must be a point");
+ }
+ leftEarPosition = (Point3d) val;
+ }
+ else if (prop.equals("RightEarPosition")) {
+ if (!(val instanceof Point3d)) {
+ syntaxError("RightEarPosition must be a point");
+ }
+ leftEarPosition = (Point3d) val;
+ }
+ else if (prop.equals("NominalEyeHeightFromGround")) {
+ if (!(val instanceof Double)) {
+ syntaxError("NominalEyeHeightFromGround must be a number");
+ }
+ nominalEyeHeightFromGround = ((Double) val).doubleValue();
+ }
+ else if (prop.equals("NominalEyeOffsetFromNominalScreen")) {
+ if (!(val instanceof Double)) {
+ syntaxError("NominalEyeOffsetFromNominalScreen " +
+ "must be a number");
+ }
+ nominalEyeOffsetFromNominalScreen = ((Double) val).doubleValue();
+ }
+ else if (prop.equals("HeadToHeadTracker")) {
+ if (!(val instanceof Matrix4d)) {
+ syntaxError("HeadToHeadTracker must be a matrix");
+ }
+ headToHeadTracker = (Matrix4d) val;
+ }
+ else {
+ syntaxError("Unknown " + command.commandName +
+ " \"" + prop + "\"") ;
+ }
+ }
+
+ PhysicalBody createJ3dPhysicalBody() {
+ // Transfer all the information from the config version
+ if (stereoEyeSeparation < Double.MAX_VALUE) {
+ leftEyePosition.set(-stereoEyeSeparation / 2.0, 0.0, 0.0);
+ rightEyePosition.set(stereoEyeSeparation / 2.0, 0.0, 0.0);
+ }
+
+ j3dPhysicalBody = new PhysicalBody(leftEyePosition, rightEyePosition,
+ leftEarPosition, rightEarPosition);
+
+ j3dPhysicalBody.setHeadToHeadTracker(
+ new Transform3D(headToHeadTracker));
+
+ j3dPhysicalBody.setNominalEyeHeightFromGround(
+ nominalEyeHeightFromGround);
+ j3dPhysicalBody.setNominalEyeOffsetFromNominalScreen(
+ nominalEyeOffsetFromNominalScreen);
+
+ return j3dPhysicalBody ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfigPhysicalEnvironment.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigPhysicalEnvironment.java
new file mode 100644
index 0000000..d31ebf2
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigPhysicalEnvironment.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe ;
+
+import java.util.ArrayList;
+
+import org.jogamp.java3d.InputDevice;
+import org.jogamp.java3d.PhysicalEnvironment;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.View;
+import org.jogamp.vecmath.Matrix4d;
+
+class ConfigPhysicalEnvironment extends ConfigObject {
+
+ /**
+ * The corresponding J3D core PhysicalEnvironment instance.
+ */
+ PhysicalEnvironment j3dPhysicalEnvironment = null ;
+
+ /**
+ * The coexistence to tracker base matrix.
+ */
+ Matrix4d coexistenceToTrackerBase = null ;
+
+ // All other configurable attributes.
+ private ConfigSensor headTracker = null ;
+ private ArrayList inputDevices = new ArrayList() ;
+ private int coexistenceCenterInPworldPolicy = View.NOMINAL_SCREEN ;
+
+ /**
+ * Overrides initialize() to do nothing.
+ */
+ @Override
+ protected void initialize(ConfigCommand command) {
+ }
+
+ /**
+ * Handles the commands
+ * (PhysicalEnvironmentAttribute {instance} {attrName} {attrValue}) and
+ * (PhysicalEnvironmentProperty {instance} {attrName} {attrValue}).
+ *
+ * @param command the command that invoked this method
+ */
+ @Override
+ protected void setProperty(ConfigCommand command) {
+ Object val ;
+ Object[] argv = command.argv ;
+ int argc = command.argc ;
+ String sval, prop ;
+
+ if (argc != 4) {
+ syntaxError("Incorrect number of arguments to " +
+ command.commandName) ;
+ }
+
+ if (!isName(argv[1])) {
+ syntaxError("The first argument to " + command.commandName +
+ " must be a name") ;
+ }
+
+ if (!isName(argv[2])) {
+ syntaxError("The second argument to " + command.commandName +
+ " must be a property name") ;
+ }
+
+ prop = (String)argv[2] ;
+ val = argv[3] ;
+
+ if (prop.equals("CoexistenceCenterInPworldPolicy")) {
+ if (!(val instanceof String))
+ syntaxError("CoexistenceCenterInPworldPolicy must be string") ;
+
+ sval = (String)val ;
+ if (sval.equals("NOMINAL_HEAD"))
+ coexistenceCenterInPworldPolicy = View.NOMINAL_HEAD ;
+ else if (sval.equals("NOMINAL_SCREEN"))
+ coexistenceCenterInPworldPolicy = View.NOMINAL_SCREEN ;
+ else if (sval.equals("NOMINAL_FEET"))
+ coexistenceCenterInPworldPolicy = View.NOMINAL_FEET ;
+ else
+ syntaxError("Illegal value " + sval +
+ " for CoexistenceCenterInPworldPolicy") ;
+ }
+ else if (prop.equals("CoexistenceToTrackerBase")) {
+ if (val instanceof Matrix4d)
+ coexistenceToTrackerBase = (Matrix4d)val ;
+ else
+ syntaxError("CoexistenceToTrackerBase must be a Matrix4d") ;
+ }
+ else if (prop.equals("InputDevice")) {
+ if (!(val instanceof String))
+ syntaxError("InputDevice must be a name") ;
+
+ sval = (String)val ;
+ inputDevices.add(configContainer.findConfigObject("Device", sval));
+ }
+ else if (prop.equals("HeadTracker")) {
+ if (!(val instanceof String))
+ syntaxError("HeadTracker must be a Sensor name") ;
+
+ sval = (String)val ;
+ headTracker =
+ (ConfigSensor)configContainer.findConfigObject("Sensor", sval);
+ }
+ else {
+ syntaxError("Unknown " + command.commandName +
+ " \"" + prop + "\"") ;
+ }
+ }
+
+ /**
+ * Create a core Java 3D PhysicalEnvironment instance using the attributes
+ * gathered by this object.
+ */
+ PhysicalEnvironment createJ3dPhysicalEnvironment() {
+ j3dPhysicalEnvironment = new PhysicalEnvironment() ;
+
+ j3dPhysicalEnvironment.setCoexistenceCenterInPworldPolicy
+ (coexistenceCenterInPworldPolicy) ;
+
+ if (coexistenceToTrackerBase != null)
+ j3dPhysicalEnvironment.setCoexistenceToTrackerBase
+ (new Transform3D(coexistenceToTrackerBase)) ;
+
+ return j3dPhysicalEnvironment ;
+ }
+
+ /**
+ * Process the devices associated with the PhysicalEnvironment.
+ */
+ void processDevices() {
+ for (int j = 0; j < inputDevices.size(); j++) {
+ ConfigDevice configDevice = (ConfigDevice)inputDevices.get(j) ;
+ InputDevice device = configDevice.j3dInputDevice ;
+ j3dPhysicalEnvironment.addInputDevice(device) ;
+ }
+
+ if (headTracker != null) {
+ j3dPhysicalEnvironment.setHeadIndex(0) ;
+ j3dPhysicalEnvironment.setSensor(0, headTracker.j3dSensor) ;
+ }
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfigScreen.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigScreen.java
new file mode 100644
index 0000000..f32e534
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigScreen.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe ;
+
+import java.awt.Window;
+
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.View;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import org.jogamp.vecmath.Matrix4d;
+import org.jogamp.vecmath.Point2d;
+
+class ConfigScreen extends ConfigObject {
+
+ /**
+ * The index of this screen in the GraphicsDevice array returned by
+ * GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices().
+ */
+ int frameBufferNumber ;
+
+ /**
+ * The physical width in meters of the screen area of the GraphicsDevice
+ * associated with this ConfigScreen. The default is based on a screen
+ * resolution of 90 pixels/inch.
+ */
+ double physicalScreenWidth = 0.0 ;
+
+ /**
+ * The physical height in meters of the screen area of the GraphicsDevice
+ * associated with this ConfigScreen. The default is based on a screen
+ * resolution of 90 pixels/inch.
+ */
+ double physicalScreenHeight = 0.0 ;
+
+ /**
+ * The trackerBaseToImagePlate transform of this ConfigScreen.
+ * The default is the identity transform.
+ */
+ Matrix4d trackerBaseToImagePlate = null ;
+
+ /**
+ * The headTrackerToLeftImagePlate transform of this ConfigScreen if HMD
+ * mode is in effect. The default is the identity transform.
+ */
+ Matrix4d headTrackerToLeftImagePlate = null ;
+
+ /**
+ * The headTrackerToRightImagePlate transform of this ConfigScreen if HMD
+ * mode is in effect. The default is the identity transform.
+ */
+ Matrix4d headTrackerToRightImagePlate = null ;
+
+ /**
+ * The monoscopicViewPolicy for this ConfigScreen. The default is
+ * View.CYCLOPEAN_EYE_VIEW.
+ */
+ int monoscopicViewPolicy = View.CYCLOPEAN_EYE_VIEW ;
+
+ /**
+ * Boolean indicating whether a full-screen window should be created for
+ * this ConfigScreen. The default is false.
+ */
+ boolean fullScreen = false ;
+
+ /**
+ * Boolean indicating whether a full-screen window with no borders should
+ * be created for this ConfigScreen. The default is false.
+ */
+ boolean noBorderFullScreen = false ;
+
+ /**
+ * The width in pixels for the window to be created for this ConfigScreen
+ * if a full screen window is not specified. The default is 512.
+ */
+ int windowWidthInPixels = 512 ;
+
+ /**
+ * The height in pixels for the window to be created for this ConfigScreen
+ * if a full screen window is not specified. The default is 512.
+ */
+ int windowHeightInPixels = 512 ;
+
+ /**
+ * The X pixel position of the top-left corner of the window, relative to
+ * the physical screen. The default is 0.
+ */
+ int windowX = 0 ;
+
+ /**
+ * The Y pixel position of the top-left corner of the window, relative to
+ * the physical screen. The default is 0.
+ */
+ int windowY = 0 ;
+
+ /**
+ * The JFrame created for this ConfigScreen. When running under JDK 1.4
+ * or newer, the JFrame always contains a JPanel which contains the
+ * Canvas3D. When running under JDK 1.3.1 and using a borderless full
+ * screen the JFrame will instead contain a JWindow which will contain the
+ * JPanel and Canvas3D.
+ */
+ JFrame j3dJFrame ;
+
+ /**
+ * The Window created for this ConfigScreen. Under JDK 1.4 or higher this
+ * is the same reference as j3dJFrame. If a borderless full screen is
+ * specified while running under JDK 1.3.1 then this is a JWindow with the
+ * j3dJFrame as its parent.
+ */
+ Window j3dWindow ;
+
+ /**
+ * The JPanel created for this ConfigScreen to hold the Canvas3D.
+ */
+ JPanel j3dJPanel ;
+
+ /**
+ * The Canvas3D created for this ConfigScreen.
+ */
+ Canvas3D j3dCanvas ;
+
+ /**
+ * Processes attributes for this object. Handles commands of the form:
+ * (ScreenAttribute {instanceName} {attrName} {attrValue})
+ * (ScreenProperty {instanceName} {attrName} {attrValue})
+ * (DisplayAttribute {instanceName} {attrName} {attrValue})
+ * (DisplayProperty {instanceName} {attrName} {attrValue})
+ *
+ * @param command the command that invoked this method
+ */
+ @Override
+ protected void setProperty(ConfigCommand command) {
+
+ String attr = null ;
+ Object val = null ;
+ String sval = null ;
+
+ if (command.argc != 4) {
+ syntaxError("Incorrect number of arguments to " +
+ command.commandName) ;
+ }
+
+ if (!isName(command.argv[2])) {
+ syntaxError("The second argument to " + command.commandName +
+ " must be a property name") ;
+ }
+
+ attr = (String)command.argv[2] ;
+ val = command.argv[3] ;
+
+ if (attr.equals("PhysicalScreenWidth")) {
+ if (!(val instanceof Double)) {
+ syntaxError("Value for PhysicalScreenWidth " +
+ "must be a number") ;
+ }
+ physicalScreenWidth = ((Double)val).doubleValue() ;
+ }
+ else if (attr.equals("PhysicalScreenHeight")) {
+ if (!(val instanceof Double)) {
+ syntaxError("Value for PhysicalScreenHeight " +
+ "must be a number") ;
+ }
+ physicalScreenHeight = ((Double)val).doubleValue() ;
+ }
+ else if (attr.equals("TrackerBaseToImagePlate")) {
+ if (!(val instanceof Matrix4d)) {
+ syntaxError("Value for TrackerBaseToImagePlate " +
+ "must be a 4x3 or 4x4 matrix") ;
+ }
+ trackerBaseToImagePlate = (Matrix4d)val ;
+ }
+ else if (attr.equals("HeadTrackerToLeftImagePlate")) {
+ if (!(val instanceof Matrix4d)) {
+ syntaxError("Value for HeadTrackerToLeftImagePlate "
+ + "must be a 4x3 or 4x4 matrix") ;
+ }
+ headTrackerToLeftImagePlate = (Matrix4d)val ;
+ }
+ else if (attr.equals("HeadTrackerToRightImagePlate")) {
+ if (!(val instanceof Matrix4d)) {
+ syntaxError("Value for HeadTrackerToRightImagePlate "
+ + "must be a 4x3 or 4x4 matrix") ;
+ }
+ headTrackerToRightImagePlate = (Matrix4d)val ;
+ }
+ else if (attr.equals("MonoscopicViewPolicy")) {
+ if (!(val instanceof String)) {
+ syntaxError("Value for MonoscopicViewPolicy " +
+ "must be a name") ;
+ }
+ sval = (String)val ;
+ if (sval.equals("LEFT_EYE_VIEW"))
+ monoscopicViewPolicy = View.LEFT_EYE_VIEW ;
+ else if (sval.equals("RIGHT_EYE_VIEW"))
+ monoscopicViewPolicy = View.RIGHT_EYE_VIEW ;
+ else if (sval.equals("CYCLOPEAN_EYE_VIEW"))
+ monoscopicViewPolicy = View.CYCLOPEAN_EYE_VIEW ;
+ else
+ syntaxError("Invalid value for MonoscopicViewPolicy "
+ + "\"" + sval + "\"") ;
+ }
+ else if (attr.equals("WindowPosition")) {
+ if (! (val instanceof Point2d)) {
+ syntaxError("WindowPosition must be a Point2d") ;
+ }
+ Point2d p2d = (Point2d)val ;
+ windowX = (int)p2d.x ;
+ windowY = (int)p2d.y ;
+ }
+ else if (attr.equals("WindowSize")) {
+ if (val instanceof Point2d) {
+ fullScreen = false ;
+ noBorderFullScreen = false ;
+
+ Point2d p2d = (Point2d)val ;
+ windowWidthInPixels = (int)p2d.x ;
+ windowHeightInPixels = (int)p2d.y ;
+ }
+ else if (val instanceof String) {
+ String s = (String)val ;
+
+ if (s.equals("FullScreen")) {
+ fullScreen = true ;
+ noBorderFullScreen = false ;
+ } else if (s.equals("NoBorderFullScreen")) {
+ fullScreen = false ;
+ noBorderFullScreen = true ;
+ } else {
+ syntaxError("Value for WindowSize " +
+ "must be one of\n" + "\"FullScreen\" " +
+ "\"NoBorderFullScreen\" or Point2d") ;
+ }
+ }
+ else {
+ syntaxError("Invalid WindowSize value: " + val +
+ "\nValue for WindowSize " +
+ "must be one of\n" + "\"FullScreen\" " +
+ "\"NoBorderFullScreen\" or Point2d") ;
+ }
+ }
+ else {
+ syntaxError("Unknown " + command.commandName +
+ " \"" + attr + "\"") ;
+ }
+ }
+
+ /**
+ * Initializes this object. Handles commands of the form:
+ * (NewScreen {instanceName} {FrameBufferNumber}).
+ *
+ * @param command the command that invoked this method
+ */
+ @Override
+ protected void initialize(ConfigCommand command) {
+ if (command.argc != 3) {
+ syntaxError("Incorrect number of arguments to " +
+ command.commandName) ;
+ }
+
+ if (!(command.argv[2] instanceof Double)) {
+ syntaxError("The second argument to " + command.commandName +
+ " must be a GraphicsDevice index") ;
+ }
+
+ frameBufferNumber = ((Double)command.argv[2]).intValue() ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfigSensor.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigSensor.java
new file mode 100644
index 0000000..baa3fd3
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigSensor.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe ;
+
+import org.jogamp.java3d.Sensor;
+import org.jogamp.vecmath.Point3d;
+
+class ConfigSensor extends ConfigObject {
+
+ // The index of this sensor in the associated InputDevice.
+ private int sensorIndex ;
+
+ // The ConfigDevice which creates the associated InputDevice.
+ private ConfigDevice configDevice ;
+
+ // All configurable attributes.
+ private Point3d hotspot = null ;
+ private int predictor = -1 ;
+ private int predictionPolicy = -1 ;
+ private int sensorReadCount = -1 ;
+
+ /**
+ * The corresponding Java 3D core Sensor instance. This is created by the
+ * associated InputDevice.
+ */
+ Sensor j3dSensor ;
+
+ /**
+ * Handles the command
+ * (NewSensor {instanceName} {inputDeviceName} {indexInInputDevice})
+ *
+ * @param command the command that invoked this method
+ */
+ @Override
+ protected void initialize(ConfigCommand command) {
+
+ int argc = command.argc ;
+ Object[] argv = command.argv ;
+
+ // Check that arg[1] and arg[2] are strings, arg[3] a number
+ if (argc != 4) {
+ syntaxError("Incorrect number of arguments to " +
+ command.commandName) ;
+ }
+
+ if (!isName(argv[2])) {
+ syntaxError("The second argument to " + command.commandName +
+ " must be the device name") ;
+ }
+
+ if (!(argv[3] instanceof Double)) {
+ syntaxError("The third argument to " + command.commandName +
+ " must be a sensor index") ;
+ }
+
+ sensorIndex = ((Double)argv[3]).intValue() ;
+ configDevice = (ConfigDevice)configContainer.findConfigObject
+ ("Device", (String)argv[2]) ;
+ }
+
+ /**
+ * Handles the commands
+ * (SensorAttribute {instanceName} {attributeName} {attributeValue}) and
+ * (SensorProperty {instanceName} {attributeName} {attributeValue}).
+ *
+ * @param command the command that invoked this method
+ */
+ @Override
+ protected void setProperty(ConfigCommand command) {
+
+ int argc = command.argc ;
+ Object[] argv = command.argv ;
+ String attribute ;
+
+ // Check that arg[1] and arg[2] are strings
+ if (argc != 4) {
+ syntaxError("Incorrect number of arguments to " +
+ command.commandName) ;
+ }
+
+ if (! isName(argv[1])) {
+ syntaxError("The first argument to " + command.commandName +
+ " must be the instance name") ;
+ }
+
+ if (! isName(argv[2])) {
+ syntaxError("The second argument to " + command.commandName +
+ " must be a property name") ;
+ }
+
+ attribute = (String)argv[2] ;
+ if (attribute.equals("Hotspot")) {
+ if (! (argv[3] instanceof Point3d)) {
+ syntaxError("Hotspot must be a 3D point") ;
+ }
+ hotspot = (Point3d)argv[3] ;
+ }
+ /*
+ * Questionable attributes. Commented out for now.
+ else if (attribute.equals("Predictor")) {
+ if (! isName(argv[3])) {
+ syntaxError("Predictor must be a name") ;
+ }
+
+ String predictorName = (String)argv[3] ;
+ if (predictorName.equals("PREDICT_NONE")) {
+ predictor = Sensor.PREDICT_NONE ;
+ }
+ else if (predictorName.equals("PREDICT_NEXT_FRAME_TIME")) {
+ predictor = Sensor.PREDICT_NEXT_FRAME_TIME ;
+ }
+ else {
+ syntaxError("Predictor must be either PREDICT_NONE " +
+ "or PREDICT_NEXT_FRAME_TIME") ;
+ }
+ }
+ else if (attribute.equals("PredictionPolicy")) {
+ if (! isName(argv[3])) {
+ syntaxError("PredictionPolicy must be a name") ;
+ }
+
+ String predictionPolicyName = (String)argv[3] ;
+ if (predictionPolicyName.equals("NO_PREDICTOR")) {
+ predictionPolicy = Sensor.NO_PREDICTOR ;
+ }
+ else if (predictionPolicyName.equals("HEAD_PREDICTOR")) {
+ predictionPolicy = Sensor.HEAD_PREDICTOR ;
+ }
+ else if (predictionPolicyName.equals("HAND_PREDICTOR")) {
+ predictionPolicy = Sensor.HAND_PREDICTOR ;
+ }
+ else {
+ syntaxError("PredictionPolicy must be either NO_PREDICTOR, " +
+ "HEAD_PREDICTOR, or HAND_PREDICTOR") ;
+ }
+ }
+ else if (attribute.equals("SensorReadCount")) {
+ if (! (argv[3] instanceof Double)) {
+ syntaxError("SensorReadCount must be a number") ;
+ }
+ sensorReadCount = ((Double)argv[3]).intValue() ;
+ }
+ */
+ else {
+ syntaxError("Unknown " + command.commandName +
+ " \"" + attribute + "\"") ;
+ }
+ }
+
+ /**
+ * This method is called after all InputDevice implementations have been
+ * instantiated and initialized. All the specified attributes for this
+ * sensor are set in the corresponding Java3D core Sensor instantiated by
+ * the associated InputDevice.
+ */
+ void configureSensor() {
+ j3dSensor = configDevice.j3dInputDevice.getSensor(sensorIndex) ;
+
+ if (hotspot != null)
+ j3dSensor.setHotspot(hotspot) ;
+
+ if (predictor != -1)
+ j3dSensor.setPredictor(predictor) ;
+
+ if (predictionPolicy != -1)
+ j3dSensor.setPredictionPolicy(predictionPolicy) ;
+
+ if (sensorReadCount != -1)
+ j3dSensor.setSensorReadCount(sensorReadCount) ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfigSexpression.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigSexpression.java
new file mode 100644
index 0000000..b4b8320
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigSexpression.java
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe ;
+
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.util.ArrayList;
+
+import org.jogamp.java3d.BoundingSphere;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.vecmath.Matrix3d;
+import org.jogamp.vecmath.Matrix4d;
+import org.jogamp.vecmath.Point2d;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Point4d;
+import org.jogamp.vecmath.Vector3d;
+
+class ConfigSexpression {
+
+ private ArrayList elements = new ArrayList() ;
+
+ private void syntaxError(StreamTokenizer st, String file, String s) {
+ System.out.println(s + ":\nat line " + st.lineno() + " in " + file) ;
+ print() ; System.out.print("\n\n") ;
+ }
+
+ private int myNextToken(StreamTokenizer st, String file) {
+ int tok = 0 ;
+ try {
+ tok = st.nextToken() ;
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e + "\nwhile reading " + file) ;
+ }
+ return tok ;
+ }
+
+
+ Object parseAndEval(ConfigContainer configContainer,
+ StreamTokenizer st, int level) {
+ int tok ;
+ String s ;
+ String file = configContainer.currentFileName ;
+
+ //
+ // First tokenize the character stream and add the tokens to the
+ // elements array.
+ //
+ elements.clear() ;
+
+ // Look for an open paren to start this sexp.
+ while (true) {
+ tok = myNextToken(st, file) ;
+
+ if (tok == StreamTokenizer.TT_EOF)
+ return Boolean.FALSE ;
+
+ if (tok == ')')
+ syntaxError(st, file, "Premature closing parenthesis") ;
+
+ if (tok == '(')
+ break ;
+ }
+
+ // Add elements until a close paren for this sexp is found.
+ for (int i = 0 ; true ; i++) {
+ tok = myNextToken(st, file) ;
+
+ if (tok == StreamTokenizer.TT_EOF) {
+ syntaxError(st, file, "Missing closing parenthesis") ;
+ break ;
+ }
+
+ // An open paren starts a new embedded sexp. Put the paren back,
+ // evaluate the sexp, and add the result to the elements list.
+ if (tok == '(') {
+ st.pushBack() ;
+ ConfigSexpression cs = new ConfigSexpression() ;
+ elements.add(cs.parseAndEval(configContainer, st, level+1)) ;
+ continue ;
+ }
+
+ // A close paren finishes the scan.
+ if (tok == ')')
+ break ;
+
+ // Check for too many arguments.
+ if (i >= 20)
+ syntaxError(st, file, "Too many arguments") ;
+
+ // Check for numeric argument.
+ if (tok == StreamTokenizer.TT_NUMBER) {
+ elements.add(new Double(st.nval)) ;
+ continue ;
+ }
+
+ // Anything other than a word or a quoted string is an error.
+ if (tok != StreamTokenizer.TT_WORD && tok != '"' && tok != '\'') {
+ String badToken = String.valueOf((char)tok) ;
+ elements.add(badToken) ; // so bad token prints out
+ syntaxError(st, file, "Invalid token \"" + badToken +
+ "\" must be enclosed in quotes") ;
+ continue ;
+ }
+
+ // Scan the token for Java property substitution syntax ${...}.
+ s = scanJavaProperties(st, file, st.sval) ;
+ if (s == null) continue ;
+
+ if (s.equalsIgnoreCase("true"))
+ // Replace "true" or "True" with the Boolean equivalent.
+ elements.add(new Boolean(true)) ;
+
+ else if (s.equalsIgnoreCase("false"))
+ // Replace "false" or "False" with the Boolean equivalent.
+ elements.add(new Boolean(false)) ;
+
+ else
+ // Add the token as a string element.
+ elements.add(s) ;
+ }
+
+
+ //
+ // Now evaluate elements.
+ //
+ if (elements.size() == 0)
+ syntaxError(st, file, "Null command") ;
+
+ // If the first argument is a string, then this sexp must be
+ // a top-level command or a built-in, and needs to be evaluated.
+ if (elements.get(0) instanceof String) {
+ try {
+ if (level == 0) {
+ configContainer.evaluateCommand(elements, st.lineno()) ;
+
+ // Continue parsing top-level commands.
+ return Boolean.TRUE ;
+ }
+ else {
+ // Evaluate built-in and return result to next level up.
+ return evaluateBuiltIn
+ (configContainer, elements, st.lineno()) ;
+ }
+ }
+ catch (IllegalArgumentException e) {
+ syntaxError(st, file, e.getMessage()) ;
+ if (level == 0)
+ // Command ignored: continue parsing.
+ return Boolean.TRUE ;
+ else
+ // Function ignored: return sexp to next level up so error
+ // processing can print it out in context of command.
+ return this ;
+ }
+ }
+
+ // If the first argument isn't a string, and we are at level 0,
+ // this is a syntax error.
+ if (level == 0)
+ syntaxError(st, file, "Malformed top-level command name") ;
+
+ // If the first argument is a number, then we must have
+ // either a 2D, 3D, or 4D numeric vector.
+ if (elements.get(0) instanceof Double) {
+ if (elements.size() == 1)
+ syntaxError(st, file, "Can't have single-element vector") ;
+
+ // Point2D
+ if (elements.size() == 2) {
+ if (!(elements.get(1) instanceof Double))
+ syntaxError(st, file, "Both elements must be numbers") ;
+
+ return new Point2d(((Double)elements.get(0)).doubleValue(),
+ ((Double)elements.get(1)).doubleValue()) ;
+ }
+
+ // Point3d
+ if (elements.size() == 3) {
+ if (!(elements.get(1) instanceof Double) ||
+ !(elements.get(2) instanceof Double))
+ syntaxError(st, file, "All elements must be numbers") ;
+
+ return new Point3d(((Double)elements.get(0)).doubleValue(),
+ ((Double)elements.get(1)).doubleValue(),
+ ((Double)elements.get(2)).doubleValue()) ;
+ }
+
+ // Point4D
+ if (elements.size() == 4) {
+ if (!(elements.get(1) instanceof Double) ||
+ !(elements.get(2) instanceof Double) ||
+ !(elements.get(3) instanceof Double))
+ syntaxError(st, file, "All elements must be numbers") ;
+
+ return new Point4d(((Double)elements.get(0)).doubleValue(),
+ ((Double)elements.get(1)).doubleValue(),
+ ((Double)elements.get(2)).doubleValue(),
+ ((Double)elements.get(3)).doubleValue()) ;
+ }
+
+ // Anything else is an error.
+ syntaxError(st, file, "Too many vector elements") ;
+ }
+
+ // If the first argument is a Point3d, then we should be a Matrix3d.
+ if (elements.get(0) instanceof Point3d) {
+ if (elements.size() != 3)
+ syntaxError(st, file, "Matrix must have three rows") ;
+
+ if (!(elements.get(1) instanceof Point3d) ||
+ !(elements.get(2) instanceof Point3d))
+ syntaxError(st, file, "All rows must have three elements") ;
+
+ return new Matrix3d(((Point3d)elements.get(0)).x,
+ ((Point3d)elements.get(0)).y,
+ ((Point3d)elements.get(0)).z,
+ ((Point3d)elements.get(1)).x,
+ ((Point3d)elements.get(1)).y,
+ ((Point3d)elements.get(1)).z,
+ ((Point3d)elements.get(2)).x,
+ ((Point3d)elements.get(2)).y,
+ ((Point3d)elements.get(2)).z) ;
+ }
+
+ // If the first argument is a Point4d, then we should be a Matrix4d.
+ if (elements.get(0) instanceof Point4d) {
+ if (elements.size() == 3) {
+ if (!(elements.get(1) instanceof Point4d) ||
+ !(elements.get(2) instanceof Point4d))
+ syntaxError(st, file, "All rows must have four elements") ;
+
+ return new Matrix4d(((Point4d)elements.get(0)).x,
+ ((Point4d)elements.get(0)).y,
+ ((Point4d)elements.get(0)).z,
+ ((Point4d)elements.get(0)).w,
+ ((Point4d)elements.get(1)).x,
+ ((Point4d)elements.get(1)).y,
+ ((Point4d)elements.get(1)).z,
+ ((Point4d)elements.get(1)).w,
+ ((Point4d)elements.get(2)).x,
+ ((Point4d)elements.get(2)).y,
+ ((Point4d)elements.get(2)).z,
+ ((Point4d)elements.get(2)).w,
+ 0.0, 0.0, 0.0, 1.0) ;
+ }
+ else if (elements.size() != 4)
+ syntaxError(st, file, "Matrix must have three or four rows") ;
+
+ if (!(elements.get(1) instanceof Point4d) ||
+ !(elements.get(2) instanceof Point4d) ||
+ !(elements.get(3) instanceof Point4d))
+ syntaxError(st, file, "All rows must have four elements") ;
+
+ return new Matrix4d(((Point4d)elements.get(0)).x,
+ ((Point4d)elements.get(0)).y,
+ ((Point4d)elements.get(0)).z,
+ ((Point4d)elements.get(0)).w,
+ ((Point4d)elements.get(1)).x,
+ ((Point4d)elements.get(1)).y,
+ ((Point4d)elements.get(1)).z,
+ ((Point4d)elements.get(1)).w,
+ ((Point4d)elements.get(2)).x,
+ ((Point4d)elements.get(2)).y,
+ ((Point4d)elements.get(2)).z,
+ ((Point4d)elements.get(2)).w,
+ ((Point4d)elements.get(3)).x,
+ ((Point4d)elements.get(3)).y,
+ ((Point4d)elements.get(3)).z,
+ ((Point4d)elements.get(3)).w) ;
+ }
+
+ // Anything else is an error.
+ syntaxError(st, file, "Syntax error") ;
+ return null ;
+ }
+
+ /**
+ * Scan for Java properties in the specified string. Nested properties are
+ * not supported.
+ *
+ * @param st stream tokenizer in use
+ * @param f current file name
+ * @param s string containing non-nested Java properties possibly
+ * interspersed with arbitrary text.
+ * @return scanned string with Java properties replaced with values
+ */
+ private String scanJavaProperties(StreamTokenizer st, String f, String s) {
+ int open = s.indexOf("${") ;
+ if (open == -1) return s ;
+
+ int close = 0 ;
+ StringBuffer buf = new StringBuffer() ;
+ while (open != -1) {
+ buf.append(s.substring(close, open)) ;
+ close = s.indexOf('}', open) ;
+ if (close == -1) {
+ elements.add(s) ; // so that the bad element prints out
+ syntaxError(st, f, "Java property substitution syntax error") ;
+ return null ;
+ }
+
+ String property = s.substring(open + 2, close) ;
+ String value = ConfigCommand.evaluateJavaProperty(property) ;
+ if (value == null) {
+ elements.add(s) ; // so that the bad element prints out
+ syntaxError(st, f, "Java property \"" + property +
+ "\" has a null value") ;
+ return null ;
+ }
+
+ buf.append(value) ;
+ open = s.indexOf("${", close) ;
+ close++ ;
+ }
+
+ buf.append(s.substring(close)) ;
+ return buf.toString() ;
+ }
+
+ /**
+ * This method gets called from the s-expression parser to evaluate a
+ * built-in command.
+ *
+ * @param elements tokenized list of sexp elements
+ * @return object representing result of evaluation
+ */
+ private Object evaluateBuiltIn(ConfigContainer configContainer,
+ ArrayList elements, int lineNumber) {
+ int argc ;
+ String functionName ;
+
+ argc = elements.size() ;
+ functionName = (String)elements.get(0) ;
+
+ if (functionName.equals("Rotate")) {
+ return makeRotate(elements) ;
+ }
+ else if (functionName.equals("Translate")) {
+ return makeTranslate(elements) ;
+ }
+ else if (functionName.equals("RotateTranslate") ||
+ functionName.equals("TranslateRotate") ||
+ functionName.equals("Concatenate")) {
+
+ return concatenate(elements) ;
+ }
+ else if (functionName.equals("BoundingSphere")) {
+ return makeBoundingSphere(elements) ;
+ }
+ else {
+ // This built-in can't be evaluated immediately or contains an
+ // unknown command. Create a ConfigCommand for later evaluation.
+ return new ConfigCommand
+ (elements, configContainer.currentFileName, lineNumber) ;
+ }
+ }
+
+ /**
+ * Processes the built-in command (Translate x y z).
+ *
+ * @param elements ArrayList containing Doubles wrapping x, y, and z
+ * translation components at indices 1, 2, and 3 respectively
+ *
+ * @return matrix that translates by the given x, y, and z components
+ */
+ private Matrix4d makeTranslate(ArrayList elements) {
+ if (elements.size() != 4) {
+ throw new IllegalArgumentException
+ ("Incorrect number of arguments to Translate") ;
+ }
+
+ if (!(elements.get(1) instanceof Double) ||
+ !(elements.get(2) instanceof Double) ||
+ !(elements.get(3) instanceof Double)) {
+ throw new IllegalArgumentException
+ ("All arguments to Translate must be numbers") ;
+ }
+
+ Matrix4d m4d = new Matrix4d() ;
+ m4d.set(new Vector3d(((Double)elements.get(1)).doubleValue(),
+ ((Double)elements.get(2)).doubleValue(),
+ ((Double)elements.get(3)).doubleValue())) ;
+
+ return m4d ;
+ }
+
+ /**
+ * Processes the (Rotate x y z) built-in command.
+ *
+ * @param elements ArrayList containing Doubles wrapping x, y, and z Euler
+ * angles at indices 1, 2, and 3 respectively
+ *
+ * @return matrix that rotates by the given Euler angles around static X,
+ * Y, and Z basis vectors: first about X, then Y, and then Z
+ *
+ * @see Transform3D#setEuler()
+ */
+ private Matrix4d makeRotate(ArrayList elements) {
+ if (elements.size() != 4) {
+ throw new IllegalArgumentException
+ ("Incorrect number of arguments to Rotate") ;
+ }
+
+ if (!(elements.get(1) instanceof Double) ||
+ !(elements.get(2) instanceof Double) ||
+ !(elements.get(3) instanceof Double)) {
+ throw new IllegalArgumentException
+ ("All arguments to Rotate must be numbers") ;
+ }
+
+ double x = Math.toRadians(((Double)elements.get(1)).doubleValue()) ;
+ double y = Math.toRadians(((Double)elements.get(2)).doubleValue()) ;
+ double z = Math.toRadians(((Double)elements.get(3)).doubleValue()) ;
+
+ Transform3D t3d = new Transform3D() ;
+ t3d.setEuler(new Vector3d(x, y, z)) ;
+
+ Matrix4d m4d = new Matrix4d() ;
+ t3d.get(m4d) ;
+
+ return m4d ;
+ }
+
+ /**
+ * Processes the (RotateTranslate m1 m2), (TranslateRotate m1 m2), and
+ * (Concatenate m1 m2) built-in commands. Although these do exactly the
+ * same thing, using the appropriate command is recommended in order to
+ * explicitly describe the sequence of transforms and their intent.
+ *
+ * @param elements ArrayList containing Matrix4d objects m1 and m2 at
+ * indices 1 and 2 respectively
+ *
+ * @return matrix that concatenates m1 and m2 in that order: if a point is
+ * transformed by the resulting matrix, then in effect the points are
+ * first transformed by m1 and then m2
+ */
+ private Matrix4d concatenate(ArrayList elements) {
+ String functionName = (String)elements.get(0) ;
+
+ if (elements.size() != 3) {
+ throw new IllegalArgumentException
+ ("Incorrect number of arguments to " + functionName) ;
+ }
+
+ if (!(elements.get(1) instanceof Matrix4d) ||
+ !(elements.get(2) instanceof Matrix4d)) {
+ throw new IllegalArgumentException
+ ("Both arguments to " + functionName + " must be Matrix4d") ;
+ }
+
+ // Multiply the matrices in the order such that the result, when
+ // transforming a 3D point, will apply the transform represented by
+ // the 1st matrix and then apply the transform represented by the 2nd
+ // matrix.
+ Matrix4d m4d = new Matrix4d((Matrix4d)elements.get(2)) ;
+ m4d.mul((Matrix4d)elements.get(1)) ;
+
+ return m4d ;
+ }
+
+ /**
+ * Processes the built-in command (BoundingSphere center radius).
+ * This is used when configuring behaviors.
+ *
+ * @param elements ArrayList containing Point3d at index 1 for the sphere
+ * center and Double at index 2 wrapping the sphere radius, or the String
+ * "infinite" at index 2.
+ *
+ * @return BoundingSphere with the given center and radius
+ */
+ private BoundingSphere makeBoundingSphere(ArrayList elements) {
+ if (elements.size() != 3) {
+ throw new IllegalArgumentException
+ ("Incorrect number of arguments to BoundingSphere") ;
+ }
+
+ if (! (elements.get(1) instanceof Point3d) ||
+ ! (elements.get(2) instanceof Double ||
+ elements.get(2) instanceof String))
+ throw new IllegalArgumentException
+ ("BoundingSphere needs a Point3d center " +
+ "followed by a Double radius or the String \"infinite\"") ;
+
+ double r ;
+ if (elements.get(2) instanceof Double)
+ r = ((Double)elements.get(2)).doubleValue() ;
+ else
+ r = Double.POSITIVE_INFINITY ;
+
+ return new BoundingSphere((Point3d)elements.get(1), r) ;
+ }
+
+ void print() {
+ System.out.print("(") ;
+ int argc = elements.size() ;
+ for (int i = 0 ; i < argc ; i++) {
+ if (elements.get(i) instanceof Matrix3d) {
+ String[] rows = ConfigCommand.formatMatrixRows
+ ((Matrix3d)elements.get(i)) ;
+ System.out.println("\n ((" + rows[0] + ")") ;
+ System.out.println(" (" + rows[1] + ")") ;
+ System.out.print(" (" + rows[2] + "))") ;
+ if (i != (argc - 1)) System.out.println() ;
+ }
+ else if (elements.get(i) instanceof Matrix4d) {
+ String[] rows = ConfigCommand.formatMatrixRows
+ ((Matrix4d)elements.get(i)) ;
+ System.out.println("\n ((" + rows[0] + ")") ;
+ System.out.println(" (" + rows[1] + ")") ;
+ System.out.println(" (" + rows[2] + ")") ;
+ System.out.print(" (" + rows[3] + "))") ;
+ if (i != (argc - 1)) System.out.println() ;
+ }
+ else if (elements.get(i) instanceof ConfigSexpression) {
+ if (i > 0) System.out.print(" ") ;
+ ((ConfigSexpression)elements.get(i)).print() ;
+ if (i != (argc - 1)) System.out.println() ;
+ }
+ else if (elements.get(i) instanceof ConfigCommand) {
+ if (i > 0) System.out.print(" ") ;
+ System.out.print(elements.get(i).toString()) ;
+ if (i != (argc - 1)) System.out.println() ;
+ }
+ else {
+ if (i > 0) System.out.print(" ") ;
+ System.out.print(elements.get(i).toString()) ;
+ }
+ }
+ System.out.print(")") ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfigView.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigView.java
new file mode 100644
index 0000000..01b0047
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigView.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe ;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.jogamp.java3d.PhysicalBody;
+import org.jogamp.java3d.PhysicalEnvironment;
+import org.jogamp.java3d.View;
+import org.jogamp.vecmath.Point3d;
+
+class ConfigView extends ConfigObject {
+ /**
+ * The corresponding View and Viewer instances. These are set when
+ * createJ3dView() is called after parsing the configuration file.
+ */
+ View j3dView = null ;
+ Viewer j3dViewer = null ;
+
+ /**
+ * Set of ConfigScreen instances added to this view.
+ */
+ Set screens = new HashSet() ;
+
+ /**
+ * Indicates whether or not stereo viewing should be enabled for this
+ * ConfigView. This is set during parsing of the configuration file.
+ */
+ boolean stereoEnable = false ;
+
+ /**
+ * Indicates whether or not antialiasing is enabled for this ConfigView.
+ * This is set during parsing of the configuration file.
+ */
+ boolean antialiasingEnable = false;
+
+ /**
+ * Reference to the PhysicalBody associated with this ConfigView. This is
+ * set when createJ3dView() is called after parsing the configuration
+ * file.
+ */
+ PhysicalBody physicalBody = null ;
+
+ /**
+ * Reference to the PhysicalEnvironment associated with this ConfigView.
+ * This is set when createJ3dView() is called after parsing the
+ * configuration file.
+ */
+ PhysicalEnvironment physicalEnvironment = null ;
+
+ // All other configurable attributes.
+ private double fieldOfView = Math.PI/4.0 ;
+ private int backClipPolicy = View.PHYSICAL_EYE ;
+ private int frontClipPolicy = View.PHYSICAL_EYE ;
+ private double backClipDistance = 10.0 ;
+ private double frontClipDistance = 0.1 ;
+ private int screenScalePolicy = View.SCALE_SCREEN_SIZE ;
+ private double screenScale = 1.0 ;
+ private boolean trackingEnable = false ;
+ private int viewPolicy = View.SCREEN_VIEW ;
+ private int windowEyepointPolicy = -1 ;
+ private int windowMovementPolicy = -1 ;
+ private int windowResizePolicy = -1 ;
+ private boolean coeCenteringEnableSet = false ;
+ private boolean coeCenteringEnable = false ;
+ private Point3d centerEyeInCoexistence = null ;
+
+ private ConfigPhysicalBody configBody = null ;
+ private ConfigPhysicalEnvironment configEnv = null ;
+ private ConfigViewPlatform configViewPlatform = null ;
+
+ /**
+ * Overrides initialize() to do nothing.
+ */
+ @Override
+ protected void initialize(ConfigCommand command) {
+ }
+
+ /**
+ * Processes properties for this object. Handles commands of the form:
+ * (ViewAttribute {instanceName} {attrName} {attrValue})
+ *
+ * @param command the command that invoked this method
+ */
+ @Override
+ protected void setProperty(ConfigCommand command) {
+
+ int argc = command.argc ;
+ Object[] argv = command.argv ;
+ String attr = null ;
+ Object val = null ;
+ String sval = null ;
+ ConfigScreen cs = null ;
+
+ // Check that arg[1] and arg[2] are strings
+ if (argc != 4) {
+ syntaxError("Incorrect number of arguments to " +
+ command.commandName) ;
+ }
+
+ if (!isName(argv[1])) {
+ syntaxError("The first argument to " + command.commandName +
+ " must be the instance name") ;
+ }
+
+ if (!isName(argv[2])) {
+ syntaxError("The second argument to " + command.commandName +
+ " must be a property name") ;
+ }
+
+ attr = (String) argv[2] ;
+ val = argv[3] ;
+
+ if (attr.equals("Screen") || attr.equals("Window")) {
+ if (!(val instanceof String)) {
+ syntaxError("Value for " + attr + " must be a name") ;
+ }
+ cs = (ConfigScreen)
+ configContainer.findConfigObject("Screen", (String)val) ;
+
+ if (!screens.add(cs)) {
+ syntaxError(attr + " \"" + ((String)val) +
+ "\" has already been added to " + instanceName) ;
+ }
+ }
+ else if (attr.equals("ViewPlatform")) {
+ if (!(val instanceof String)) {
+ syntaxError("value for ViewPlatform " +
+ " must be an instance name") ;
+ }
+ configViewPlatform =
+ (ConfigViewPlatform)configContainer.findConfigObject
+ ("ViewPlatform", (String)val) ;
+
+ configViewPlatform.addConfigView(this) ;
+ }
+ else if (attr.equals("PhysicalEnvironment")) {
+ if (!(val instanceof String)) {
+ syntaxError("value for PhysicalEnvironment " +
+ "must be an instance name") ;
+ }
+ configEnv =
+ (ConfigPhysicalEnvironment)configContainer.findConfigObject
+ ("PhysicalEnvironment", (String)val) ;
+ }
+ else if (attr.equals("PhysicalBody")) {
+ if (!(val instanceof String)) {
+ syntaxError("value for PhysicalBody " +
+ "must be an instance name") ;
+ }
+ configBody = (ConfigPhysicalBody)
+ configContainer.findConfigObject("PhysicalBody", (String)val) ;
+ }
+ else if (attr.equals("BackClipPolicy")) {
+ if (!(val instanceof String)) {
+ syntaxError("value for BackClipPolicy must be a string") ;
+ }
+ sval = (String) val ;
+ if (sval.equals("PHYSICAL_EYE"))
+ backClipPolicy = View.PHYSICAL_EYE ;
+ else if (sval.equals("PHYSICAL_SCREEN"))
+ backClipPolicy = View.PHYSICAL_SCREEN ;
+ else if (sval.equals("VIRTUAL_EYE"))
+ backClipPolicy = View.VIRTUAL_EYE ;
+ else if (sval.equals("VIRTUAL_SCREEN"))
+ backClipPolicy = View.VIRTUAL_SCREEN ;
+ else
+ syntaxError("Invalid value for BackClipPolicy " + sval) ;
+ }
+ else if (attr.equals("FrontClipPolicy")) {
+ if (!(val instanceof String)) {
+ syntaxError("value for FrontClipPolicy must be a string") ;
+ }
+ sval = (String) val ;
+ if (sval.equals("PHYSICAL_EYE"))
+ frontClipPolicy = View.PHYSICAL_EYE ;
+ else if (sval.equals("PHYSICAL_SCREEN"))
+ frontClipPolicy = View.PHYSICAL_SCREEN ;
+ else if (sval.equals("VIRTUAL_EYE"))
+ frontClipPolicy = View.VIRTUAL_EYE ;
+ else if (sval.equals("VIRTUAL_SCREEN"))
+ frontClipPolicy = View.VIRTUAL_SCREEN ;
+ else
+ syntaxError("Invalid value for FrontClipPolicy " + sval) ;
+ }
+ else if (attr.equals("ScreenScalePolicy")) {
+ if (!(val instanceof String)) {
+ syntaxError("value for ScreenScalePolicy must be a string") ;
+ }
+ sval = (String) val ;
+ if (sval.equals("SCALE_SCREEN_SIZE"))
+ screenScalePolicy = View.SCALE_SCREEN_SIZE ;
+ else if (sval.equals("SCALE_EXPLICIT"))
+ screenScalePolicy = View.SCALE_EXPLICIT ;
+ else
+ syntaxError("Invalid value for ScreenScalePolicy " + sval) ;
+ }
+ else if (attr.equals("FieldOfView")) {
+ if (!(val instanceof Double)) {
+ syntaxError("value for FieldOfView must be a number") ;
+ }
+ fieldOfView = ((Double)val).doubleValue() ;
+ }
+ else if (attr.equals("BackClipDistance")) {
+ if (!(val instanceof Double)) {
+ syntaxError("value for BackClipDistance must be a number") ;
+ }
+ backClipDistance = ((Double)val).doubleValue() ;
+ }
+ else if (attr.equals("FrontClipDistance")) {
+ if (!(val instanceof Double)) {
+ syntaxError("value for FrontClipDistance must be a number") ;
+ }
+ frontClipDistance = ((Double)val).doubleValue() ;
+ }
+ else if (attr.equals("ScreenScale")) {
+ if (!(val instanceof Double)) {
+ syntaxError("value for ScreenScale must be a number") ;
+ }
+ screenScale = ((Double)val).doubleValue() ;
+ }
+ else if (attr.equals("TrackingEnable")) {
+ if (!(val instanceof Boolean)) {
+ syntaxError("value for TrackingEnable must be a boolean") ;
+ }
+ trackingEnable = ((Boolean)val).booleanValue() ;
+ }
+ else if (attr.equals("CoexistenceCenteringEnable")) {
+ if (!(val instanceof Boolean)) {
+ syntaxError("value for CoexistenceCenteringEnable " +
+ "must be a boolean") ;
+ }
+ coeCenteringEnable = ((Boolean)val).booleanValue() ;
+ coeCenteringEnableSet = true ;
+ }
+ else if (attr.equals("ViewPolicy")) {
+ if (!(val instanceof String)) {
+ syntaxError("value for ViewPolicy must be a string") ;
+ }
+ sval = (String) val ;
+ if (sval.equals("SCREEN_VIEW"))
+ viewPolicy = View.SCREEN_VIEW ;
+ else if (sval.equals("HMD_VIEW"))
+ viewPolicy = View.HMD_VIEW ;
+ else
+ syntaxError("Invalid value for ViewPolicy " + sval) ;
+ }
+ else if (attr.equals("WindowEyepointPolicy")) {
+ if (!(val instanceof String)) {
+ syntaxError("value for WindowEyepointPolicy " +
+ "must be a string") ;
+ }
+ sval = (String) val ;
+ if (sval.equals("RELATIVE_TO_SCREEN"))
+ windowEyepointPolicy = View.RELATIVE_TO_SCREEN ;
+ else if (sval.equals("RELATIVE_TO_COEXISTENCE"))
+ windowEyepointPolicy = View.RELATIVE_TO_COEXISTENCE ;
+ else if (sval.equals("RELATIVE_TO_WINDOW"))
+ windowEyepointPolicy = View.RELATIVE_TO_WINDOW ;
+ else if (sval.equals("RELATIVE_TO_FIELD_OF_VIEW"))
+ windowEyepointPolicy = View.RELATIVE_TO_FIELD_OF_VIEW ;
+ else
+ syntaxError("Invalid value for WindowEyepointPolicy " + sval) ;
+ }
+ else if (attr.equals("WindowMovementPolicy")) {
+ if (!(val instanceof String)) {
+ syntaxError("value for WindowEyeMovementPolicy " +
+ "must be a string") ;
+ }
+ sval = (String) val ;
+ if (sval.equals("VIRTUAL_WORLD"))
+ windowMovementPolicy = View.VIRTUAL_WORLD ;
+ else if (sval.equals("PHYSICAL_WORLD"))
+ windowMovementPolicy = View.PHYSICAL_WORLD ;
+ else
+ syntaxError("Invalid value for WindowMovementPolicy " + sval) ;
+ }
+ else if (attr.equals("WindowResizePolicy")) {
+ if (!(val instanceof String)) {
+ syntaxError("value for WindowResizePolicy " +
+ "must be a string") ;
+ }
+ sval = (String) val ;
+ if (sval.equals("VIRTUAL_WORLD"))
+ windowResizePolicy = View.VIRTUAL_WORLD ;
+ else if (sval.equals("PHYSICAL_WORLD"))
+ windowResizePolicy = View.PHYSICAL_WORLD ;
+ else
+ syntaxError("Invalid value for WindowResizePolicy " + sval) ;
+ }
+ else if (attr.equals("CenterEyeInCoexistence")) {
+ if (val instanceof Point3d)
+ centerEyeInCoexistence = (Point3d)val ;
+ else
+ syntaxError("value for CenterEyeInCoexistence " +
+ "must be a Point3d") ;
+ }
+ else if (attr.equals("StereoEnable")) {
+ if (!(val instanceof Boolean)) {
+ syntaxError("value for StereoEnable must be a boolean") ;
+ }
+ stereoEnable = ((Boolean)val).booleanValue() ;
+ }
+ else if (attr.equals("AntialiasingEnable")) {
+ if (!(val instanceof Boolean)) {
+ syntaxError("value for AntialiasingEnable must be a boolean") ;
+ }
+ antialiasingEnable = ((Boolean)val).booleanValue() ;
+ }
+ else {
+ syntaxError("Unknown " + command.commandName +
+ " \"" + attr + "\"") ;
+ }
+ }
+
+ /**
+ * Create a core Java 3D View instance and a utility Viewer instance using
+ * the attributes gathered by this object.
+ */
+ protected Viewer createViewer(boolean setVisible) {
+ Point3d leftEyeCoe, rightEyeCoe ;
+
+ j3dView = new View() ;
+ j3dView.setViewPolicy(viewPolicy) ;
+
+ if (configBody == null)
+ physicalBody = new PhysicalBody() ;
+ else
+ physicalBody = configBody.j3dPhysicalBody ;
+
+ if (configEnv == null)
+ physicalEnvironment = new PhysicalEnvironment() ;
+ else
+ physicalEnvironment = configEnv.j3dPhysicalEnvironment ;
+
+ j3dView.setPhysicalBody(physicalBody) ;
+ j3dView.setPhysicalEnvironment(physicalEnvironment) ;
+
+ boolean standardDefaults = true ;
+ if (coeCenteringEnableSet && !coeCenteringEnable) {
+ standardDefaults = false ;
+ }
+ if (configEnv != null && configEnv.coexistenceToTrackerBase != null) {
+ standardDefaults = false ;
+ }
+ else {
+ Iterator i = screens.iterator() ;
+ while (i.hasNext()) {
+ ConfigScreen s = (ConfigScreen)i.next() ;
+ if (s.trackerBaseToImagePlate != null) {
+ standardDefaults = false ;
+ break ;
+ }
+ }
+ }
+
+ if (standardDefaults) {
+ // Coexistence centering has not been explicitly set false, and
+ // the tracker base to image plate and coexistence to tracker base
+ // transforms are unset, so use the standard Java 3D defaults.
+ if (windowEyepointPolicy == -1)
+ windowEyepointPolicy = View.RELATIVE_TO_FIELD_OF_VIEW ;
+ if (windowMovementPolicy == -1)
+ windowMovementPolicy = View.PHYSICAL_WORLD ;
+ if (windowResizePolicy == -1)
+ windowResizePolicy = View.PHYSICAL_WORLD ;
+ if (!coeCenteringEnableSet)
+ coeCenteringEnable = true ;
+ }
+ else {
+ // Use multi-screen or calibrated coexistence defaults.
+ if (windowEyepointPolicy == -1)
+ windowEyepointPolicy = View.RELATIVE_TO_COEXISTENCE ;
+ if (windowMovementPolicy == -1)
+ windowMovementPolicy = View.VIRTUAL_WORLD ;
+ if (windowResizePolicy == -1)
+ windowResizePolicy = View.VIRTUAL_WORLD ;
+ if (!coeCenteringEnableSet)
+ coeCenteringEnable = false ;
+ }
+
+ j3dView.setWindowEyepointPolicy(windowEyepointPolicy) ;
+ j3dView.setWindowMovementPolicy(windowMovementPolicy) ;
+ j3dView.setWindowResizePolicy(windowResizePolicy) ;
+ j3dView.setCoexistenceCenteringEnable(coeCenteringEnable) ;
+
+ if (centerEyeInCoexistence == null) {
+ centerEyeInCoexistence = new Point3d(0.0, 0.0, 0.4572) ;
+ }
+
+ leftEyeCoe = new Point3d(centerEyeInCoexistence) ;
+ rightEyeCoe = new Point3d(centerEyeInCoexistence) ;
+
+ if (stereoEnable) {
+ Point3d leftEyeBody = new Point3d() ;
+ Point3d rightEyeBody = new Point3d() ;
+
+ physicalBody.getLeftEyePosition(leftEyeBody) ;
+ physicalBody.getRightEyePosition(rightEyeBody) ;
+
+ leftEyeCoe.add(leftEyeBody) ;
+ rightEyeCoe.add(rightEyeBody) ;
+ }
+
+ j3dView.setLeftManualEyeInCoexistence(leftEyeCoe) ;
+ j3dView.setRightManualEyeInCoexistence(rightEyeCoe) ;
+
+ j3dView.setBackClipPolicy(backClipPolicy) ;
+ j3dView.setFrontClipPolicy(frontClipPolicy) ;
+ j3dView.setBackClipDistance(backClipDistance) ;
+ j3dView.setFrontClipDistance(frontClipDistance) ;
+
+ j3dView.setScreenScalePolicy(screenScalePolicy) ;
+ j3dView.setScreenScale(screenScale) ;
+
+ j3dView.setFieldOfView(fieldOfView) ;
+ j3dView.setTrackingEnable(trackingEnable) ;
+ j3dView.setSceneAntialiasingEnable(antialiasingEnable) ;
+
+ if (screens.size() == 0) {
+ throw new IllegalStateException
+ (errorMessage(creatingCommand, "View \"" + instanceName +
+ "\" has no canvases or screens")) ;
+ }
+
+ ConfigScreen[] cs = new ConfigScreen[screens.size()] ;
+ screens.toArray(cs) ;
+
+ j3dViewer = new Viewer(cs, this, setVisible) ;
+ return j3dViewer ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfigViewPlatform.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigViewPlatform.java
new file mode 100644
index 0000000..2fdc593
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigViewPlatform.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe ;
+
+import java.util.ArrayList;
+
+import org.jogamp.java3d.Node;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.java3d.View;
+import org.jogamp.java3d.ViewPlatform;
+import org.jogamp.vecmath.Matrix4d;
+
+class ConfigViewPlatform extends ConfigObject {
+
+ private boolean allowPolicyRead = false ;
+ private boolean allowLocalToVworldRead = false ;
+ private boolean nominalViewingTransform = false ;
+ private Transform3D initialViewingTransform = null ;
+ private ArrayList configViews = new ArrayList() ;
+ private Viewer[] viewers = null ;
+
+ /**
+ * The corresponding ViewingPlatform instance.
+ */
+ ViewingPlatform viewingPlatform = null ;
+
+ /**
+ * Indicates the view attach policy specified in the configuration file.
+ * If none is set, it remains -1 even though a default may be in effect.
+ */
+ int viewAttachPolicy = -1 ;
+
+ /**
+ * The associated ConfigViewPlatformBehavior, if any.
+ */
+ ConfigViewPlatformBehavior configBehavior = null ;
+
+ /**
+ * Overrides initialize() to do nothing.
+ */
+ @Override
+ protected void initialize(ConfigCommand command) {
+ }
+
+ /**
+ * Processes attributes for this object. Handles commands of the form:
+ * (ViewPlatformAttribute {instanceName} {attrName} {attrValue})
+ * (ViewPlatformBehaviorProperty {instanceName} {attrName} {arg} ...)
+ *
+ * @param command the command that invoked this method
+ */
+ @Override
+ protected void setProperty(ConfigCommand cmd) {
+
+ int argc = cmd.argc ;
+ Object[] argv = cmd.argv ;
+
+ if (argc < 4) {
+ syntaxError("Wrong number of arguments to " + cmd.commandName) ;
+ }
+
+ if (! isName(argv[2])) {
+ syntaxError("The second argument to " + cmd.commandName +
+ " must be a property name");
+ }
+
+ String attribute = (String)argv[2] ;
+ if (attribute.equals("HomeTransform")) {
+ if (! (argv[3] instanceof Matrix4d)) {
+ syntaxError("HomeTransform must be a Matrix4d") ;
+ }
+ homeTransform = new Transform3D((Matrix4d)argv[3]) ;
+ }
+ else if (attribute.equals("SchedulingBounds")) {
+ if (! (argv[3] instanceof Bounds)) {
+ syntaxError("SchedulingBounds must be an instance of Bounds") ;
+ }
+ schedulingBounds = (Bounds)argv[3] ;
+ }
+ else if (attribute.equals("SchedulingInterval")) {
+ if (! (argv[3] instanceof Double)) {
+ syntaxError("SchedulingInterval must be a priority (number)") ;
+ }
+ schedulingInterval = ((Double)argv[3]).intValue() ;
+ }
+ else {
+ // It's not any of the pre-defined attributes. Add it to the
+ // properties list for the behavior instance itself to evaluate.
+ properties.add(cmd) ;
+ }
+ }
+
+ /**
+ * Instantiate a ViewPlatformBehavior of the given class name.
+ *
+ * NOTE: All ConfigView and ConfigSensor objects must be processed before
+ * calling this method.
+ *
+ * @return the configured ViewPlatformBehavior, or null if error
+ */
+ ViewPlatformBehavior createViewPlatformBehavior() {
+
+ viewPlatformBehavior = (ViewPlatformBehavior)createTargetObject() ;
+
+ // Set known attributes.
+ if (homeTransform != null)
+ viewPlatformBehavior.setHomeTransform(homeTransform) ;
+
+ if (schedulingBounds != null)
+ viewPlatformBehavior.setSchedulingBounds(schedulingBounds) ;
+
+ if (schedulingInterval != -1)
+ viewPlatformBehavior.setSchedulingInterval(schedulingInterval) ;
+
+ // Unknown properties in the concrete instance are evaluated later.
+ return viewPlatformBehavior ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfiguredUniverse.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfiguredUniverse.java
new file mode 100644
index 0000000..96bc119
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfiguredUniverse.java
@@ -0,0 +1,789 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe;
+
+import java.net.URL;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.HiResCoord;
+import org.jogamp.java3d.Locale;
+import org.jogamp.java3d.View;
+
+/**
+ * This utility class creates all the necessary objects on the view side of
+ * the scene graph. Specifically, it creates a Locale, one or more
+ * ViewingPlatforms, and at least one Viewer object.
+ *
+ * ConfiguredUniverse can set up a viewing environment based upon the contents
+ * of a configuration file. This allows an application to run without change
+ * across a broad range of viewing configurations, such as windows on
+ * conventional desktops, stereo-enabled views, full screen immersive displays
+ * on single or multiple screens, or virtual reality installations including
+ * cave and head-mounted displays incorporating 6 degree of freedom sensor
+ * devices.
+ *
+ * A configuration file may create InputDevice, Sensor, and
+ * ViewPlatformBehavior instances as well as Viewers and ViewingPlatforms. At
+ * least one Viewer must be provided by the configuration. If a
+ * ViewingPlatform is not provided, a default one will be created and the
+ * Viewer will be attached to it.
+ *
+ * A configuration file may be specified directly by passing a URL to a
+ * ConfiguredUniverse constructor. Alternatively, a ConfigContainer may be
+ * created from a configuration file first, and then passed to an appropriate
+ * ConfiguredUniverse constructor. The latter technique allows Java system
+ * properties that affect Java 3D to be specified in the configuration file,
+ * as long as no references to a VirtualUniverse are made before creating the
+ * container.
+ *
+ * If a configuration file or container is not provided, then
+ * ConfiguredUniverse creates a default viewing environment in the same way as
+ * SimpleUniverse. If one or more Canvas3D objects are provided, it will use
+ * them instead of creating new ones. All of the constructors provided by
+ * SimpleUniverse are also available here.
+ *
+ * The syntax and description of the configuration file may be found
+ * here. Example config files can
+ * be found here.
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see ConfigContainer
+ * @see
+ * The Java 3D Configuration File
+ * @see
+ * Example Configuration Files
+ *
+ * @since Java 3D 1.3
+ */
+public class ConfiguredUniverse extends SimpleUniverse {
+
+ /**
+ * The configuration instance for this universe.
+ */
+ private ConfigContainer configContainer = null;
+
+ /**
+ * Equivalent to
+ *
+ * This constructor and
+ *
+ *
+ *
+ *
+ *
+ * @param visible boolean to be passed to the
+ *
+ * With the sole exception of the Sensor assigned to the head tracker,
+ * none of the Sensors defined in the configuration file are placed into
+ * the Sensor array maintained by PhysicalEnvironment. The head tracker
+ * Sensor is the only one read by the Java 3D core and must generate reads
+ * with a full 6 degrees of freedom (3D position and 3D orientation).
+ *
+ * Other Sensors need not generate reads with a full 6 degrees of freedom,
+ * although their reads must be expressed using Transform3D. Some
+ * joysticks may provide only 2D relative X and Y axis movement; dials,
+ * levers, and sliders are 1D devices, and some devices may combine dials
+ * and levers to generate 3D positional data.
+ *
+ * The index names to identify left / right / dominant / non-dominant hand
+ * Sensors in the PhysicalEnvironement Sensor array are not adequate to
+ * distinguish these differences, so this method allows applications to
+ * look up Sensors based on the names bound to them in the configuration
+ * file. There are no set rules on naming. Applications that use Sensors
+ * may set up conventions for generic devices such as "mouse6D" or
+ * "joystick2D" or specific product names.
+ *
+ * @return read-only Map which maps Sensor names to the associated Sensors,
+ * or null if no Sensors have been named
+ */
+ public Map getNamedSensors() {
+ if (configContainer == null)
+ return null;
+ else
+ return configContainer.getNamedSensors();
+ }
+
+ /**
+ * Returns all named ViewPlatformBehaviors defined by the configuration
+ * file used to create the ConfiguredUniverse, if any. Equivalent
+ * to
+ *
+ * @return read-only Map which maps behavior names to the associated
+ * ViewPlatformBehavior instances, or null if none have been named.
+ * @since Java 3D 1.3.1
+ */
+ public Map getNamedBehaviors() {
+ if (configContainer == null)
+ return null;
+ else
+ return configContainer.getNamedViewPlatformBehaviors();
+ }
+
+ /**
+ * Returns a container holding all the objects defined by the
+ * configuration file used to create the ConfiguredUniverse.
+ *
+ * @return the container
+ * @since Java 3D 1.3.1
+ */
+ public ConfigContainer getConfigContainer() {
+ return configContainer;
+ }
+
+ /**
+ * Cleanup memory references used by ConfiguredUniverse.
+ * @since Java 3D 1.3.1
+ */
+ @Override
+ public void cleanup() {
+ if (viewer != null) {
+ for (int i = 0 ; i < viewer.length ; i++) {
+ viewer[i].getView().removeAllCanvas3Ds();
+ viewer[i].setViewingPlatform(null);
+ viewer[i] = null;
+ }
+ }
+
+ locale = null;
+ removeAllLocales();
+
+ configContainer.clear();
+ configContainer = null;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/LocaleFactory.java b/src/classes/share/org/jogamp/java3d/utils/universe/LocaleFactory.java
new file mode 100644
index 0000000..721787c
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/LocaleFactory.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe;
+
+import org.jogamp.java3d.HiResCoord;
+import org.jogamp.java3d.Locale;
+import org.jogamp.java3d.VirtualUniverse;
+
+/**
+ * This interface defines a factory for creating Locale objects in a
+ * SimpleUniverse. Implementations of the createLocale methods in
+ * this interface should construct a new Locale object from the
+ * specified parameters. This class is used by the SimpleUniverse
+ * class to construct the default Locale used to hold the view and
+ * content branch graphs.
+ *
+ * @see Locale
+ * @see ConfiguredUniverse
+ * @see SimpleUniverse
+ *
+ * @since Java 3D 1.3
+ */
+public interface LocaleFactory {
+ /**
+ * Creates a new Locale object at the specified high resolution
+ * coordinate in the specified universe.
+ *
+ * @param universe the VirtualUniverse in which to create the Locale
+ * @param hiRes the high resolution coordinate that defines the origin
+ * of the Locale
+ */
+ public Locale createLocale(VirtualUniverse universe, HiResCoord hiRes);
+
+ /**
+ * Creates a new Locale object at (0, 0, 0) in the specified universe.
+ *
+ * @param universe the VirtualUniverse in which to create the Locale
+ */
+ public Locale createLocale(VirtualUniverse universe);
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/MultiTransformGroup.java b/src/classes/share/org/jogamp/java3d/utils/universe/MultiTransformGroup.java
new file mode 100644
index 0000000..0998a9d
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/MultiTransformGroup.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe;
+
+import org.jogamp.java3d.TransformGroup;
+
+/**
+ * A convenience class that effectively creates a series of TransformGroup
+ * nodes connected one to another hierarchically. For most applications,
+ * creating a MultiTransformGroup containing one transform will suffice.
+ * More sophisticated applications that use a complex portal/head tracking
+ * viewing system may find that more transforms are needed.
+ *
+ * When more than one transform is needed, transform[0] is considered the
+ * "top most" transform with repsect to the scene graph, (attached to the
+ * ViewingPlatform node) and transform[numTransforms - 1] is the "bottom
+ * most" transform (the ViewPlatorm object is attached to this transform).
+ */
+public class MultiTransformGroup {
+
+ // For now just have an array of TransformGroup nodes.
+ TransformGroup[] transforms;
+
+ /**
+ * Creates a MultiTransformGroup node that contains a single transform.
+ * This is effectively equivalent to creating a single TransformGroup
+ * node.
+ */
+ public MultiTransformGroup() {
+ this(1);
+ }
+
+ /**
+ * Creates a MultiTransformGroup node that contains the specified
+ * number of transforms.
+ *
+ * When more than one transform is needed, transform[0] is considered the
+ * "top most" transform with repsect to the scene graph, (attached to the
+ * ViewingPlatform node) and transform[numTransforms - 1] is the "bottom
+ * most" transform (the ViewPlatorm object is attached to this transform).
+ *
+ * @param numTransforms The number of transforms for this node to
+ * contain. If this number is less than one, one is assumed.
+ */
+ public MultiTransformGroup(int numTransforms) {
+ if (numTransforms < 1)
+ numTransforms = 1;
+
+ transforms = new TransformGroup[numTransforms];
+
+ // there is always at least one TransformGroup
+ transforms[0] = new TransformGroup();
+ transforms[0].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+ transforms[0].setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
+ transforms[0].setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
+ transforms[0].setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
+
+ for (int i = 1; i < numTransforms; i++) {
+ transforms[i] = new TransformGroup();
+ transforms[i].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+ transforms[i].setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
+ transforms[i].setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
+ transforms[i].setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
+ transforms[i-1].addChild(transforms[i]);
+ }
+ }
+
+ /**
+ * Returns the selected TransformGroup node.
+ *
+ * @param transform The index of the transform to return. The indices
+ * are in the range [0..(n - 1)] - where n was the number of transforms
+ * created. transform[0] is considered the
+ * "top most" transform with repsect to the scene graph, (attached to the
+ * ViewingPlatform node) and transform[numTransforms - 1] is the "bottom
+ * most" transform (the ViewPlatorm object is attached to this transform).
+ *
+ * @return The TransformGroup node at the designated index. If an out of
+ * range index is given, null is returned.
+ */
+ public TransformGroup getTransformGroup(int transform) {
+ if (transform >= transforms.length || transform < 0)
+ return null;
+
+ return transforms[transform];
+ }
+
+ /**
+ * Returns the number of transforms in this MultiTransformGroup object.
+ *
+ * @return The number of transforms in this object.
+ */
+ public int getNumTransforms() {
+ return transforms.length;
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/PlatformGeometry.java b/src/classes/share/org/jogamp/java3d/utils/universe/PlatformGeometry.java
new file mode 100644
index 0000000..351ad48
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/PlatformGeometry.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe;
+
+import org.jogamp.java3d.BranchGroup;
+
+/**
+ * This class holds any geometry that should be associated with the
+ * ViewingPlatform object. To create a scene with a dashboard, for
+ * instance, a programmer would place the dashboard geometry under
+ * the PlatformGeometry node.
+ *
+ * @see ViewingPlatform
+ */
+public class PlatformGeometry extends BranchGroup {
+
+ /**
+ * Constructs an instance of the PlatformGeometry node.
+ */
+ public PlatformGeometry() {
+ setCapability(ALLOW_DETACH);
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/SimpleUniverse.java b/src/classes/share/org/jogamp/java3d/utils/universe/SimpleUniverse.java
new file mode 100644
index 0000000..4e55b94
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/SimpleUniverse.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe;
+
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.net.URL;
+
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.GraphicsConfigTemplate3D;
+import org.jogamp.java3d.HiResCoord;
+import org.jogamp.java3d.Locale;
+import org.jogamp.java3d.View;
+import org.jogamp.java3d.VirtualUniverse;
+
+import org.jogamp.java3d.utils.geometry.Primitive;
+
+
+/**
+ * This class sets up a minimal user environment to quickly and easily
+ * get a Java 3D program up and running. This utility class creates
+ * all the necessary objects on the "view" side of the scene graph.
+ * Specifically, this class creates a locale, a single ViewingPlatform,
+ * and a Viewer object (both with their default values).
+ * Many basic Java 3D applications
+ * will find that SimpleUniverse provides all necessary functionality
+ * needed by their applications. More sophisticated applications
+ * may find that they need more control in order to get extra functionality
+ * and will not be able to use this class.
+ *
+ * @see Viewer
+ * @see ViewingPlatform
+ */
+public class SimpleUniverse extends VirtualUniverse {
+
+ /**
+ * Locale reference needed to create the "view" portion
+ * of the scene graph.
+ */
+ protected Locale locale;
+
+ /**
+ * Viewer reference needed to create the "view" portion
+ * of the scene graph.
+ */
+ protected Viewer[] viewer = null;
+
+ /**
+ * Creates a locale, a single ViewingPlatform, and
+ * and a Viewer object (both with their default values).
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ */
+ public SimpleUniverse() {
+ // call main constructor with default values.
+ this(null, 1, null, null);
+ }
+
+ /**
+ * Creates a locale, a single ViewingPlatform, and a Viewer object
+ * (with default values). The ViewingPlatform is created with the
+ * specified number of TransformGroups.
+ *
+ * @param numTransforms The number of transforms to be in the
+ * MultiTransformGroup object.
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ *
+ * @since Java 3D 1.2.1
+ */
+ public SimpleUniverse(int numTransforms) {
+ // call main constructor with default values except numTransforms
+ this(null, numTransforms, null, null);
+ }
+
+ /**
+ * Creates a locale, a single ViewingPlatform (with default values), and
+ * and a Viewer object. The Viewer object uses default values for
+ * everything but the canvas.
+ *
+ * @param canvas The canvas to associate with the Viewer object. Passing
+ * in null will cause this parameter to be ignored and a canvas to be
+ * created by the utility.
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ */
+ public SimpleUniverse(Canvas3D canvas) {
+ // call main constructor with default values for everything but
+ // the canvas parameter.
+ this(null, 1, canvas, null);
+ }
+
+ /**
+ * Creates a locale, a single ViewingPlatform, and a Viewer object
+ * The Viewer object uses default values for everything but the canvas.
+ * The ViewingPlatform is created with the specified number of
+ * TransformGroups.
+ *
+ * @param canvas The canvas to associate with the Viewer object. Passing
+ * in null will cause this parameter to be ignored and a canvas to be
+ * created by the utility.
+ * @param numTransforms The number of transforms to be in the
+ * MultiTransformGroup object.
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ *
+ * @since Java 3D 1.2.1
+ */
+ public SimpleUniverse(Canvas3D canvas, int numTransforms) {
+ // call main constructor with default values except canvas
+ // and numTransforms
+ this(null, numTransforms, canvas, null);
+ }
+
+ /**
+ * Creates a locale, a single ViewingPlatform, and a Viewer object
+ * The Viewer object uses default values for everything but the canvas.
+ * The ViewingPlatform is created with the specified number of
+ * TransformGroups.
+ *
+ * @param canvas The canvas to associate with the Viewer object. Passing
+ * in null will cause this parameter to be ignored and a canvas to be
+ * created by the utility.
+ * @param numTransforms The number of transforms to be in the
+ * MultiTransformGroup object.
+ * @param localeFactory Factory for creating the locale
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ *
+ * @since Java 3D 1.5.1
+ */
+ public SimpleUniverse(Canvas3D canvas, int numTransforms, LocaleFactory localeFactory) {
+ // call main constructor with default values except canvas,
+ // numTransforms and localeFactory
+ this(null, numTransforms, canvas, null, localeFactory);
+ }
+
+ /**
+ * Creates the "view" side of the scene graph. The passed in parameters
+ * override the default values where appropriate.
+ *
+ * @param origin The origin used to set the origin of the Locale object.
+ * If this object is null, then 0.0 is used.
+ * @param numTransforms The number of transforms to be in the
+ * MultiTransformGroup object.
+ * @param canvas The canvas to draw into. If this is null, it is
+ * ignored and a canvas will be created by the utility.
+ * @param userConfig The URL to the user's configuration file, used
+ * by the Viewer object. This is never examined and default values are
+ * always taken.
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ * @deprecated use ConfiguredUniverse constructors to read a
+ * configuration file
+ */
+ public SimpleUniverse(HiResCoord origin, int numTransforms,
+ Canvas3D canvas, URL userConfig) {
+ this( origin, numTransforms, canvas, userConfig, null );
+ }
+
+ /**
+ * Creates the "view" side of the scene graph. The passed in parameters
+ * override the default values where appropriate.
+ *
+ * @param origin The origin used to set the origin of the Locale object.
+ * If this object is null, then 0.0 is used.
+ * @param numTransforms The number of transforms to be in the
+ * MultiTransformGroup object.
+ * @param canvas The canvas to draw into. If this is null, it is
+ * ignored and a canvas will be created by the utility.
+ * @param userConfig The URL to the user's configuration file, used
+ * by the Viewer object. This is never examined and default values are
+ * always taken.
+ * @param localeFactory The Locale Factory which will instantiate the
+ * locale(s) for this universe.
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ * @deprecated use ConfiguredUniverse constructors to read a
+ * configuration file
+ */
+ public SimpleUniverse(HiResCoord origin, int numTransforms,
+ Canvas3D canvas, URL userConfig, LocaleFactory localeFactory ) {
+ ViewingPlatform vwp;
+
+ createLocale( origin, localeFactory );
+
+ // Create the ViewingPlatform and Viewer objects, passing
+ // down the appropriate parameters.
+ vwp = new ViewingPlatform(numTransforms);
+ vwp.setUniverse( this );
+ viewer = new Viewer[1];
+ // viewer[0] = new Viewer(canvas, userConfig);
+ viewer[0] = new Viewer(canvas);
+ viewer[0].setViewingPlatform(vwp);
+
+ // Add the ViewingPlatform to the locale - the scene
+ // graph is now "live".
+ locale.addBranchGraph(vwp);
+ }
+
+
+ /**
+ * Creates the "view" side of the scene graph. The passed in parameters
+ * override the default values where appropriate.
+ *
+ * @param viewingPlatform The viewingPlatform to use to create
+ * the "view" side of the scene graph.
+ * @param viewer The viewer object to use to create
+ * the "view" side of the scene graph.
+ */
+ public SimpleUniverse(ViewingPlatform viewingPlatform, Viewer viewer) {
+ this( viewingPlatform, viewer, null );
+ }
+
+ /**
+ * Creates the "view" side of the scene graph. The passed in parameters
+ * override the default values where appropriate.
+ *
+ * @param viewingPlatform The viewingPlatform to use to create
+ * the "view" side of the scene graph.
+ * @param viewer The viewer object to use to create
+ * the "view" side of the scene graph.
+ * @param localeFactory The factory used to create the Locale Object
+ */
+ public SimpleUniverse(ViewingPlatform viewingPlatform, Viewer viewer,
+ LocaleFactory localeFactory ) {
+ createLocale( null, localeFactory );
+ viewingPlatform.setUniverse( this );
+
+ // Assign object references.
+ this.viewer = new Viewer[1];
+ this.viewer[0] = viewer;
+
+ // Add the ViewingPlatform to the Viewer object.
+ this.viewer[0].setViewingPlatform(viewingPlatform);
+
+ // Add the ViewingPlatform to the locale - the scene
+ // graph is now "live".
+ locale.addBranchGraph(viewingPlatform);
+ }
+
+ /**
+ * Constructor for use by Configured Universe
+ */
+ SimpleUniverse( HiResCoord origin, LocaleFactory localeFactory ) {
+ createLocale( origin, localeFactory );
+ }
+
+ /**
+ * Create the Locale using the LocaleFactory and HiRes origin,
+ * if specified.
+ */
+ private void createLocale( HiResCoord origin,
+ LocaleFactory localeFactory ) {
+
+ if (localeFactory != null) {
+ if (origin != null)
+ locale = localeFactory.createLocale(this, origin);
+ else
+ locale = localeFactory.createLocale(this);
+ }
+ else {
+ if (origin != null)
+ locale = new Locale(this, origin);
+ else
+ locale = new Locale(this);
+ }
+ }
+
+ /**
+ * Returns the Locale object associated with this scene graph.
+ *
+ * @return The Locale object used in the construction of this scene
+ * graph.
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Returns the Viewer object associated with this scene graph.
+ * SimpleUniverse creates a single Viewer object for use in the
+ * scene graph.
+ *
+ * @return The Viewer object associated with this scene graph.
+ */
+ public Viewer getViewer() {
+ return viewer[0];
+ }
+
+ /**
+ * Returns the ViewingPlatform object associated with this scene graph.
+ *
+ * @return The ViewingPlatform object of this scene graph.
+ */
+ public ViewingPlatform getViewingPlatform() {
+ return viewer[0].getViewingPlatform();
+ }
+
+ /**
+ * Returns the Canvas3D object associated with this Java 3D Universe.
+ *
+ * @return A reference to the Canvas3D object associated with the
+ * Viewer object. This method is equivalent to calling getCanvas(0).
+ *
+ * @see Viewer
+ */
+ public Canvas3D getCanvas() {
+ return getCanvas(0);
+ }
+
+ /**
+ * Returns the Canvas3D object at the specified index associated with
+ * this Java 3D Universe.
+ *
+ * @param canvasNum The index of the Canvas3D object to retrieve.
+ * If there is no Canvas3D object for the given index, null is returned.
+ *
+ * @return A reference to the Canvas3D object associated with the
+ * Viewer object.
+ */
+ public Canvas3D getCanvas(int canvasNum) {
+ return viewer[0].getCanvas3D(canvasNum);
+ }
+
+ /**
+ * Used to add Nodes to the geometry side (as opposed to the view side)
+ * of the scene graph. This is a short cut to getting the Locale object
+ * and calling that object's addBranchGraph() method.
+ *
+ * @param bg The BranchGroup to attach to this Universe's Locale.
+ */
+ public void addBranchGraph(BranchGroup bg) {
+ locale.addBranchGraph(bg);
+ }
+
+ /**
+ * Finds the preferred
+ *
+ * The architecture of the Java 3D 1.3 sample implementation introduces a
+ * frame latency between updates to the application scene graph structure and
+ * their effects on internal Java 3D state.
+ *
+ * The methods in this class work around this problem at the expense of
+ * querying the application state of the scene graph to get the current
+ * transform from view platform to virtual world coordinates. This can
+ * involve a potential performance degradation, however, since the application
+ * scene graph state is not designed for high performance queries. The view
+ * platform must also have
+ *
+ * On the other hand, application behaviors that create the view platform
+ * transformation directly will have access to it without the need to query it
+ * from the scene graph; in that case, the transforms from physical
+ * coordinates to view platform coordinates provided by this class are all
+ * that are needed. The
+ *
+ * Other Synchronization Issues
+ *
+ * Scene graph updates are guaranteed to take effect in the same frame only
+ * if run from the processStimulus() method of a Behavior. Updates from
+ * multiple behaviors are only guaranteed to take effect in the same frame if
+ * they're responding to a WakeupOnElapsedFrames(0) condition. Use a single
+ * behavior to perform view dependent updates if possible; otherwise, use
+ * WakeupOnElapsedFrames(0) and set behavior scheduling intervals to ensure
+ * that behaviors that need the current view platform transform are run after
+ * it's set. Updating scene graph elements from anything other than the
+ * Behavior thread, such as an external input thread or a renderer callback
+ * in Canvas3D, will not necessarily be synchronized with rendering.
+ *
+ * Direct updates to geometry data have a different frame latency than
+ * updates to scene graph transforms and structure. In the Java 3D 1.3
+ * architecture, updates to by-reference geometry arrays and texture data have
+ * a 1-frame latency, while updates to transforms and scene graph structure
+ * have a 2-frame latency. Because of bug 4799494, which is outstanding
+ * in Java 3D 1.3.1, updates to by-copy geometry arrays also have a 1-frame
+ * latency. It is therefore recommended that view dependent scene graph
+ * updates be limited to transforms and scene graph structure only.
+ *
+ * If it is not possible to avoid updating geometry directly, then these
+ * updates must be delayed by one frame in order to remain synchronized with
+ * the view platform. This can be accomplished by creating an additional
+ * behavior to actually update the geometry, separate from the behavior that
+ * computes the changes that need to be made based on current view state. If
+ * the update behavior is awakened by a behavior post from the computing
+ * behavior then the update will be delayed by a single frame.
+ *
+ * Implementation Notes
+ *
+ * This utility is essentially a rewrite of a few private Java 3D core
+ * classes, but designed for public use and source code availability. The
+ * source code may be helpful in understanding some of the more complex
+ * aspects of the view model, especially with regards to various interactions
+ * between attributes which are not adequately documented. None of the actual
+ * core Java 3D source code is used, but the code is designed to comply with
+ * the view model as defined by the Java 3D Specification, so it can be
+ * considered an alternative implementation. This class will produce the
+ * same results as the Java 3D core implementation except for:
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * The last item deserves some mention. Java 3D provides no way to directly
+ * query the tracked head position being used by the renderer. The View's
+ *
+ *
+ * Thread Safety
+ *
+ * All transforms are lazily evaluated. The
+ *
+ * Screens and view platforms can be shared between separate views in the Java
+ * 3D view model. To remain accurate, ViewInfo also allows this sharing.
+ * Since it is likely that a multi-view application has separate threads
+ * managing each view, potential concurrent modification of data associated
+ * with a screen or a view platform is internally synchronized in this class.
+ * It is safe for each thread to use its own instance of a ViewInfo
+ * corresponding to the view it is managing.
+ *
+ * Otherwise, none of the other methods in this class are internally
+ * synchronized. Except for the update methods mentioned above, a single
+ * instance of ViewInfo should not be used by more than one concurrent thread
+ * without external synchronization.
+ *
+ * @since Java 3D 1.3.1
+ */
+public class ViewInfo {
+ private final static boolean verbose = false ;
+
+ /**
+ * Indicates that updates to a Screen3D associated with the View should
+ * be automatically checked with each call to a public method in this
+ * class.
+ */
+ public final static int SCREEN_AUTO_UPDATE = 1 ;
+
+ /**
+ * Indicates that updates to a Canvas3D associated with the View should
+ * be automatically checked with each call to a public method in this
+ * class.
+ */
+ public final static int CANVAS_AUTO_UPDATE = 2 ;
+
+ /**
+ * Indicates that updates to the View should be automatically checked
+ * with each call to a public method in this class.
+ */
+ public final static int VIEW_AUTO_UPDATE = 4 ;
+
+ /**
+ * Indicates that updates to the tracked head position should be
+ * automatically checked with each call to a public method in this class.
+ */
+ public final static int HEAD_AUTO_UPDATE = 8 ;
+
+ /**
+ * Indicates that updates to the ViewPlatform
+ *
+ * Applications are responsible for informing this class of changes to the
+ * View, its Canvas3D and Screen3D components, the tracked head position,
+ * and the ViewPlatform's
+ *
+ * The View must be attached to a ViewPlatform. If the ViewPlatform is
+ * attached to a live scene graph, then
+ * @param autoUpdateFlags a logical
+ *
+ * ViewInfo caches Screen3D and ViewPlatform data, but Screen3D and
+ * ViewPlatform instances are shared across multiple Views in the Java 3D
+ * view model. Since ViewInfo is per-View, all ViewInfo constructors
+ * except for this one use static references to manage the shared Screen3D
+ * and ViewPlatform objects. In this constructor, however, the caller
+ * supplies two Map instances to hold these references for all ViewInfo
+ * instances, so static references can be avoided; it can be used to wrap
+ * this class into a multi-view context that provides the required
+ * maps.
+ *
+ * Alternatively, the other constructors can be used by calling
+ *
+ *
+ * @param view the View to use
+ * @param autoUpdateFlags a logical
+ * @param screenMap a writeable Map to hold Screen3D information
+ * @param viewPlatformMap a writeable Map to hold ViewPlatform information
+ */
+ public ViewInfo(View view, int autoUpdateFlags,
+ Map screenMap, Map viewPlatformMap) {
+
+ if (verbose)
+ System.err.println("ViewInfo: init " + hashCode()) ;
+ if (view == null)
+ throw new IllegalArgumentException("View is null") ;
+ if (screenMap == null)
+ throw new IllegalArgumentException("screenMap is null") ;
+ if (viewPlatformMap == null)
+ throw new IllegalArgumentException("viewPlatformMap is null") ;
+
+ this.view = view ;
+ this.screenMap = screenMap ;
+ this.viewPlatformMap = viewPlatformMap ;
+
+ if (autoUpdateFlags == 0) {
+ this.autoUpdate = false ;
+ }
+ else {
+ this.autoUpdate = true ;
+ this.autoUpdateFlags = autoUpdateFlags ;
+ }
+
+ getViewInfo() ;
+ }
+
+ /**
+ * Gets the current transforms from image plate coordinates to view
+ * platform coordinates and copies them into the given Transform3Ds.
+ *
+ * With a monoscopic canvas the image plate transform is copied to the
+ * first argument and the second argument is not used. For a stereo
+ * canvas the first argument receives the left image plate transform, and
+ * if the second argument is non-null it receives the right image plate
+ * transform. These transforms are always the same unless a head mounted
+ * display driven by a single stereo canvas is in use.
+ *
+ * @param c3d the Canvas3D associated with the image plate
+ * @param ip2vpl the Transform3D to receive the left transform
+ * @param ip2vpr the Transform3D to receive the right transform, or null
+ */
+ public void getImagePlateToViewPlatform(Canvas3D c3d,
+ Transform3D ip2vpl,
+ Transform3D ip2vpr) {
+
+ CanvasInfo ci = updateCache
+ (c3d, "getImagePlateToViewPlatform", false) ;
+
+ getImagePlateToViewPlatform(ci) ;
+ ip2vpl.set(ci.plateToViewPlatform) ;
+ if (ci.useStereo && ip2vpr != null)
+ ip2vpr.set(ci.rightPlateToViewPlatform) ;
+ }
+
+ private void getImagePlateToViewPlatform(CanvasInfo ci) {
+ if (ci.updatePlateToViewPlatform) {
+ if (verbose) System.err.println("updating PlateToViewPlatform") ;
+ if (ci.plateToViewPlatform == null)
+ ci.plateToViewPlatform = new Transform3D() ;
+
+ getCoexistenceToImagePlate(ci) ;
+ getViewPlatformToCoexistence(ci) ;
+
+ ci.plateToViewPlatform.mul(ci.coeToPlate, ci.viewPlatformToCoe) ;
+ ci.plateToViewPlatform.invert() ;
+
+ if (ci.useStereo) {
+ if (ci.rightPlateToViewPlatform == null)
+ ci.rightPlateToViewPlatform = new Transform3D() ;
+
+ ci.rightPlateToViewPlatform.mul(ci.coeToRightPlate,
+ ci.viewPlatformToCoe) ;
+ ci.rightPlateToViewPlatform.invert() ;
+ }
+ ci.updatePlateToViewPlatform = false ;
+ if (verbose) t3dPrint(ci.plateToViewPlatform, "plateToVp") ;
+ }
+ }
+
+ /**
+ * Gets the current transforms from image plate coordinates to virtual
+ * world coordinates and copies them into the given Transform3Ds.
+ *
+ * With a monoscopic canvas the image plate transform is copied to the
+ * first argument and the second argument is not used. For a stereo
+ * canvas the first argument receives the left image plate transform, and
+ * if the second argument is non-null it receives the right image plate
+ * transform. These transforms are always the same unless a head mounted
+ * display driven by a single stereo canvas is in use.
+ *
+ * The View must be attached to a ViewPlatform which is part of a live
+ * scene graph, and the ViewPlatform node must have its
+ *
+ *
+ * If coexistence centering is turned off, then canvases and screens can
+ * have arbitrary positions with respect to coexistence, set through the
+ * the Screen3D
+ *
+ * With a monoscopic canvas the image plate transform is copied to the
+ * first argument and the second argument is not used. For a stereo
+ * canvas the first argument receives the left image plate transform, and
+ * if the second argument is non-null it receives the right image plate
+ * transform. These transforms are always the same unless a head mounted
+ * display driven by a single stereo canvas is in use.
+ *
+ * @param c3d the Canvas3D associated with the image plate
+ * @param coe2ipl the Transform3D to receive the left transform
+ * @param coe2ipr the Transform3D to receive the right transform, or null
+ */
+ public void getCoexistenceToImagePlate(Canvas3D c3d,
+ Transform3D coe2ipl,
+ Transform3D coe2ipr) {
+
+ CanvasInfo ci = updateCache(c3d, "getCoexistenceToImagePlate", false) ;
+ getCoexistenceToImagePlate(ci) ;
+ coe2ipl.set(ci.coeToPlate) ;
+ if (ci.useStereo && coe2ipr != null)
+ coe2ipr.set(ci.coeToRightPlate) ;
+ }
+
+ private void getCoexistenceToImagePlate(CanvasInfo ci) {
+ //
+ // This method will always set coeToRightPlate even if stereo is not
+ // in use. This is necessary so that getEyeToImagePlate() can handle
+ // a monoscopic view policy of CYCLOPEAN_EYE_VIEW (which averages the
+ // left and right eye positions) when the eyepoints are expressed in
+ // coexistence coordinates or are derived from the tracked head.
+ //
+ if (ci.updateCoeToPlate) {
+ if (verbose) System.err.println("updating CoeToPlate") ;
+ if (ci.coeToPlate == null) {
+ ci.coeToPlate = new Transform3D() ;
+ ci.coeToRightPlate = new Transform3D() ;
+ }
+ if (viewPolicy == View.HMD_VIEW) {
+ // Head mounted displays have their image plates fixed with
+ // respect to the head, so get the head position in
+ // coexistence.
+ ci.coeToPlate.mul(ci.si.headTrackerToLeftPlate,
+ coeToHeadTracker) ;
+ if (ci.useStereo)
+ // This is the only case in the view model in which the
+ // right plate transform could be different from the left.
+ ci.coeToRightPlate.mul(ci.si.headTrackerToRightPlate,
+ coeToHeadTracker) ;
+ else
+ ci.coeToRightPlate.set(ci.coeToPlate) ;
+ }
+ else if (coeCentering) {
+ // The default, for fixed single screen displays with no
+ // motion tracking. The transform is just a translation.
+ if (movementPolicy == View.PHYSICAL_WORLD)
+ // The default. Coexistence is centered in the window.
+ v3d.set(ci.canvasX + (ci.canvasWidth / 2.0),
+ ci.canvasY + (ci.canvasHeight / 2.0), 0.0) ;
+ else
+ // Coexistence is centered in the screen.
+ v3d.set(ci.si.screenWidth / 2.0,
+ ci.si.screenHeight / 2.0, 0.0) ;
+
+ ci.coeToPlate.set(v3d) ;
+ ci.coeToRightPlate.set(v3d) ;
+ }
+ else {
+ // Coexistence centering should be false for multiple fixed
+ // screens and/or motion tracking. trackerBaseToImagePlate
+ // and coexistenceToTrackerBase are used explicitly.
+ ci.coeToPlate.mul(ci.si.trackerBaseToPlate, coeToTrackerBase) ;
+ ci.coeToRightPlate.set(ci.coeToPlate) ;
+ }
+ ci.updateCoeToPlate = false ;
+ if (verbose) t3dPrint(ci.coeToPlate, "coeToPlate") ;
+ }
+ }
+
+ /**
+ * Gets the current transform from view platform coordinates to
+ * coexistence coordinates and copies it into the given transform. View
+ * platform coordinates are always aligned with coexistence coordinates
+ * but may differ in scale and in Y and Z offset. The scale is derived
+ * from the window resize and screen scale policies, while the offset is
+ * derived from the view attach policy.
+ *
+ * Java 3D constructs a view from the physical position of the eyes
+ * relative to the physical positions of the image plates; it then uses a
+ * view platform to position that physical configuration into the virtual
+ * world and from there computes the correct projections of the virtual
+ * world onto the physical image plates. Coexistence coordinates are used
+ * to place the physical positions of the view platform, eyes, head, image
+ * plate, sensors, and tracker base in relation to each other. The view
+ * platform is positioned with respect to the virtual world through the
+ * scene graph, so the view platform to coexistence transform defines the
+ * space in which the virtual world and physical world coexist.
+ *
+ * This method requires a Canvas3D. A different transform may be returned
+ * for each canvas in the view if any of the following apply:
+ *
+ *
+ *
+ *
+ *
+ * This method requires a Canvas3D. The returned transform may differ
+ * across canvases for the same reasons as discussed in the description of
+ *
+ *
+ * @param c3d the Canvas3D to use
+ * @param coe2vp the Transform3D to receive the transform
+ * @see #getViewPlatformToCoexistence
+ * getViewPlatformToCoexistence(Canvas3D, Transform3D)
+ */
+ public void getCoexistenceToViewPlatform(Canvas3D c3d,
+ Transform3D coe2vp) {
+
+ CanvasInfo ci = updateCache
+ (c3d, "getCoexistenceToViewPlatform", false) ;
+
+ getCoexistenceToViewPlatform(ci) ;
+ coe2vp.set(ci.coeToViewPlatform) ;
+ }
+
+ private void getCoexistenceToViewPlatform(CanvasInfo ci) {
+ if (ci.updateCoeToViewPlatform) {
+ if (verbose) System.err.println("updating CoeToViewPlatform") ;
+ if (ci.coeToViewPlatform == null)
+ ci.coeToViewPlatform = new Transform3D() ;
+
+ getViewPlatformToCoexistence(ci) ;
+ ci.coeToViewPlatform.invert(ci.viewPlatformToCoe) ;
+
+ ci.updateCoeToViewPlatform = false ;
+ if (verbose) t3dPrint(ci.coeToViewPlatform, "coeToVp") ;
+ }
+ }
+
+ /**
+ * Gets the current transform from coexistence coordinates to virtual
+ * world coordinates and copies it into the given transform.
+ *
+ * The View must be attached to a ViewPlatform which is part of a live
+ * scene graph, and the ViewPlatform node must have its
+ *
+ *
+ * This method requires a Canvas3D. The returned transform may differ
+ * across canvases for the same reasons as discussed in the description of
+ *
+ *
+ * @param c3d the Canvas3D to use
+ * @param coe2vw the Transform3D to receive the transform
+ * @see #getViewPlatformToCoexistence
+ * getViewPlatformToCoexistence(Canvas3D, Transform3D)
+ */
+ public void getCoexistenceToVworld(Canvas3D c3d,
+ Transform3D coe2vw) {
+
+ CanvasInfo ci = updateCache(c3d, "getCoexistenceToVworld", true) ;
+ getCoexistenceToVworld(ci) ;
+ coe2vw.set(ci.coeToVworld) ;
+ }
+
+ private void getCoexistenceToVworld(CanvasInfo ci) {
+ if (ci.updateCoeToVworld) {
+ if (verbose) System.err.println("updating CoexistenceToVworld") ;
+ if (ci.coeToVworld == null) ci.coeToVworld = new Transform3D() ;
+
+ getCoexistenceToViewPlatform(ci) ;
+ ci.coeToVworld.mul(vpi.viewPlatformToVworld,
+ ci.coeToViewPlatform) ;
+
+ ci.updateCoeToVworld = false ;
+ }
+ }
+
+ /**
+ * Gets the transforms from eye coordinates to image plate coordinates and
+ * copies them into the Transform3Ds specified.
+ *
+ * When head tracking is used the eye positions are taken from the head
+ * position and set in relation to the image plates with each Screen3D's
+ *
+ *
+ * Eye coordinates are always aligned with image plate coordinates, so
+ * these transforms are always just translations. With a monoscopic
+ * canvas the eye transform is copied to the first argument and the second
+ * argument is not used. For a stereo canvas the first argument receives
+ * the left eye transform, and if the second argument is non-null it
+ * receives the right eye transform.
+ *
+ * @param c3d the Canvas3D associated with the image plate
+ * @param e2ipl the Transform3D to receive left transform
+ * @param e2ipr the Transform3D to receive right transform, or null
+ */
+ public void getEyeToImagePlate(Canvas3D c3d,
+ Transform3D e2ipl, Transform3D e2ipr) {
+
+ CanvasInfo ci = updateCache(c3d, "getEyeToImagePlate", false) ;
+ getEyeToImagePlate(ci) ;
+ e2ipl.set(ci.eyeToPlate) ;
+ if (ci.useStereo && e2ipr != null)
+ e2ipr.set(ci.rightEyeToPlate) ;
+ }
+
+ private void getEyeToImagePlate(CanvasInfo ci) {
+ if (ci.updateEyeInPlate) {
+ if (verbose) System.err.println("updating EyeInPlate") ;
+ if (ci.eyeToPlate == null)
+ ci.eyeToPlate = new Transform3D() ;
+
+ if (viewPolicy == View.HMD_VIEW) {
+ getEyesHMD(ci) ;
+ }
+ else if (useTracking) {
+ getEyesTracked(ci) ;
+ }
+ else {
+ getEyesFixedScreen(ci) ;
+ }
+ ci.updateEyeInPlate = false ;
+ if (verbose) System.err.println("eyeInPlate: " + ci.eyeInPlate) ;
+ }
+ }
+
+ //
+ // Get physical eye positions for head mounted displays. These are
+ // determined solely by the headTrackerToImagePlate and headToHeadTracker
+ // calibration constants defined by Screen3D and the PhysicalBody.
+ //
+ // Note that headTrackerLeftToImagePlate and headTrackerToRightImagePlate
+ // should be set according to the *apparent* position and orientation of
+ // the image plates, relative to the head and head tracker, as viewed
+ // through the HMD optics. This is also true of the "physical" screen
+ // width and height specified by the Screen3D -- they should be the
+ // *apparent* width and height as viewed through the HMD optics. They
+ // must be set directly through the Screen3D methods; the default pixel
+ // metrics of 90 pixels/inch used by Java 3D aren't appropriate for HMD
+ // optics.
+ //
+ // Most HMDs have 100% overlap between the left and right displays; in
+ // that case, headTrackerToLeftImagePlate and headTrackerToRightImagePlate
+ // should be identical. The HMD manufacturer's specifications of the
+ // optics in terms of field of view, image overlap, and distance to the
+ // focal plane should be used to derive these parameters.
+ //
+ private void getEyesHMD(CanvasInfo ci) {
+ if (ci.useStereo) {
+ // This case is for head mounted displays driven by a single
+ // stereo canvas on a single screen. These use a field sequential
+ // stereo signal to split the left and right images.
+ leftEye.set(leftEyeInHead) ;
+ headToHeadTracker.transform(leftEye) ;
+ ci.si.headTrackerToLeftPlate.transform(leftEye,
+ ci.eyeInPlate) ;
+ rightEye.set(rightEyeInHead) ;
+ headToHeadTracker.transform(rightEye) ;
+ ci.si.headTrackerToRightPlate.transform(rightEye,
+ ci.rightEyeInPlate) ;
+ if (ci.rightEyeToPlate == null)
+ ci.rightEyeToPlate = new Transform3D() ;
+
+ v3d.set(ci.rightEyeInPlate) ;
+ ci.rightEyeToPlate.set(v3d) ;
+ }
+ else {
+ // This case is for 2-channel head mounted displays driven by two
+ // monoscopic screens, one for each eye.
+ switch (ci.monoscopicPolicy) {
+ case View.LEFT_EYE_VIEW:
+ leftEye.set(leftEyeInHead) ;
+ headToHeadTracker.transform(leftEye) ;
+ ci.si.headTrackerToLeftPlate.transform(leftEye,
+ ci.eyeInPlate) ;
+ break ;
+ case View.RIGHT_EYE_VIEW:
+ rightEye.set(rightEyeInHead) ;
+ headToHeadTracker.transform(rightEye) ;
+ ci.si.headTrackerToRightPlate.transform(rightEye,
+ ci.eyeInPlate) ;
+ break ;
+ case View.CYCLOPEAN_EYE_VIEW:
+ default:
+ throw new IllegalStateException
+ ("Illegal monoscopic view policy for 2-channel HMD") ;
+ }
+ }
+ v3d.set(ci.eyeInPlate) ;
+ ci.eyeToPlate.set(v3d) ;
+ }
+
+ private void getEyesTracked(CanvasInfo ci) {
+ leftEye.set(leftEyeInHead) ;
+ rightEye.set(rightEyeInHead) ;
+ headToTrackerBase.transform(leftEye) ;
+ headToTrackerBase.transform(rightEye) ;
+ if (coeCentering) {
+ // Coexistence and tracker base coordinates are the same.
+ // Centering is normally turned off for tracking.
+ getCoexistenceToImagePlate(ci) ;
+ ci.coeToPlate.transform(leftEye) ;
+ ci.coeToRightPlate.transform(rightEye) ;
+ }
+ else {
+ // The normal policy for head tracking.
+ ci.si.trackerBaseToPlate.transform(leftEye) ;
+ ci.si.trackerBaseToPlate.transform(rightEye) ;
+ }
+ setEyeScreenRelative(ci, leftEye, rightEye) ;
+ }
+
+ private void getEyesFixedScreen(CanvasInfo ci) {
+ switch (eyePolicy) {
+ case View.RELATIVE_TO_FIELD_OF_VIEW:
+ double z = ci.getFieldOfViewOffset() ;
+ setEyeWindowRelative(ci, z, z) ;
+ break ;
+ case View.RELATIVE_TO_WINDOW:
+ setEyeWindowRelative(ci,
+ ci.leftManualEyeInPlate.z,
+ ci.rightManualEyeInPlate.z) ;
+ break ;
+ case View.RELATIVE_TO_SCREEN:
+ setEyeScreenRelative(ci,
+ ci.leftManualEyeInPlate,
+ ci.rightManualEyeInPlate) ;
+ break ;
+ case View.RELATIVE_TO_COEXISTENCE:
+ view.getLeftManualEyeInCoexistence(leftEye) ;
+ view.getRightManualEyeInCoexistence(rightEye) ;
+
+ getCoexistenceToImagePlate(ci) ;
+ ci.coeToPlate.transform(leftEye) ;
+ ci.coeToRightPlate.transform(rightEye) ;
+ setEyeScreenRelative(ci, leftEye, rightEye) ;
+ break ;
+ }
+ }
+
+ private void setEyeWindowRelative(CanvasInfo ci,
+ double leftZ, double rightZ) {
+
+ // Eye position X is offset from the window center.
+ double centerX = (ci.canvasX + (ci.canvasWidth / 2.0)) ;
+ leftEye.x = centerX + leftEyeInHead.x ;
+ rightEye.x = centerX + rightEyeInHead.x ;
+
+ // Eye position Y is always the canvas center.
+ leftEye.y = rightEye.y = ci.canvasY + (ci.canvasHeight / 2.0) ;
+
+ // Eye positions Z are as given.
+ leftEye.z = leftZ ;
+ rightEye.z = rightZ ;
+
+ setEyeScreenRelative(ci, leftEye, rightEye) ;
+ }
+
+ private void setEyeScreenRelative(CanvasInfo ci,
+ Point3d leftEye, Point3d rightEye) {
+ if (ci.useStereo) {
+ ci.eyeInPlate.set(leftEye) ;
+ ci.rightEyeInPlate.set(rightEye) ;
+
+ if (ci.rightEyeToPlate == null)
+ ci.rightEyeToPlate = new Transform3D() ;
+
+ v3d.set(ci.rightEyeInPlate) ;
+ ci.rightEyeToPlate.set(v3d) ;
+ }
+ else {
+ switch (ci.monoscopicPolicy) {
+ case View.CYCLOPEAN_EYE_VIEW:
+ ci.eyeInPlate.set((leftEye.x + rightEye.x) / 2.0,
+ (leftEye.y + rightEye.y) / 2.0,
+ (leftEye.z + rightEye.z) / 2.0) ;
+ break ;
+ case View.LEFT_EYE_VIEW:
+ ci.eyeInPlate.set(leftEye) ;
+ break ;
+ case View.RIGHT_EYE_VIEW:
+ ci.eyeInPlate.set(rightEye) ;
+ break ;
+ }
+ }
+ v3d.set(ci.eyeInPlate) ;
+ ci.eyeToPlate.set(v3d) ;
+ }
+
+ /**
+ * Gets the current transforms from eye coordinates to view platform
+ * coordinates and copies them into the given Transform3Ds.
+ *
+ * With a monoscopic canvas the eye transform is copied to the first
+ * argument and the second argument is not used. For a stereo canvas the
+ * first argument receives the left eye transform, and if the second
+ * argument is non-null it receives the right eye transform.
+ *
+ * This method requires a Canvas3D. When using a head mounted display,
+ * head tracking with fixed screens, or a window eyepoint policy of
+ *
+ *
+ * With window eyepoint policies of
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * With a monoscopic canvas the eye transform is copied to the first
+ * argument and the second argument is not used. For a stereo canvas the
+ * first argument receives the left eye transform, and if the second
+ * argument is non-null it receives the right eye transform.
+ *
+ * This method requires a Canvas3D. The transforms returned may differ
+ * across canvases for all the same reasons discussed in the description
+ * of
+ *
+ * With a monoscopic canvas the eye transform is copied to the first
+ * argument and the second argument is not used. For a stereo canvas the
+ * first argument receives the left eye transform, and if the second
+ * argument is non-null it receives the right eye transform.
+ *
+ * The View must be attached to a ViewPlatform which is part of a live
+ * scene graph, and the ViewPlatform node must have its
+ *
+ *
+ * This method requires a Canvas3D. The transforms returned may differ
+ * across canvases for all the same reasons discussed in the description
+ * of
+ *
+ * With a monoscopic canvas the projection transform is copied to the
+ * first argument and the second argument is not used. For a stereo
+ * canvas the first argument receives the left projection transform,
+ * and if the second argument is non-null it receives the right
+ * projection transform.
+ *
+ * If either of the clip policies
+ *
+ * With a monoscopic canvas the projection transform is copied to the
+ * first argument and the second argument is not used. For a stereo
+ * canvas the first argument receives the left projection transform, and
+ * if the second argument is non-null it receives the right projection
+ * transform.
+ *
+ * If either of the clip policies
+ *
+ * With a monoscopic canvas the projection transform is copied to the
+ * first argument and the second argument is not used. For a stereo
+ * canvas the first argument receives the left projection transform, and
+ * if the second argument is non-null it receives the right projection
+ * transform.
+ *
+ * If either of the clip policies
+ *
+ * With a monoscopic canvas the projection transform is copied to the
+ * first argument and the second argument is not used. For a stereo
+ * canvas the first argument receives the left projection transform, and
+ * if the second argument is non-null it receives the right projection
+ * transform.
+ *
+ * The View must be attached to a ViewPlatform which is part of a live
+ * scene graph, and the ViewPlatform node must have its
+ *
+ *
+ * Note that this is not necessarily the clip distance as set by
+ *
+ *
+ * If either of the clip policies
+ *
+ * Note that this is not necessarily the clip distance as set by
+ *
+ *
+ * If either of the clip policies
+ *
+ * This method requires a Canvas3D. A different scale may be returned
+ * for each canvas in the view if any of the following apply:
+ *
+ *
+ *
+ * This method requires a Canvas3D. A different scale may be returned
+ * across canvases for the same reasons as discussed in the description of
+ *
+ *
+ * The View must be attached to a ViewPlatform which is part of a live
+ * scene graph, and the ViewPlatform node must have its
+ *
+ *
+ * This method requires a Canvas3D. The returned transform may differ
+ * across canvases for the same reasons as discussed in the description of
+ *
+ *
+ * This method requires a Canvas3D. The returned transform may differ
+ * across canvases for the same reasons as discussed in the description of
+ *
+ *
+ * This method requires a Canvas3D. The returned transform may differ
+ * across canvases for the same reasons as discussed in the description of
+ *
+ *
+ * It is safe to continue using existing ViewInfo instances after calling
+ * this method; the data in the released maps will be re-derived as
+ * needed.
+ */
+ public static synchronized void clear() {
+ Iterator i = staticVpMap.values().iterator() ;
+ while (i.hasNext()) ((ViewPlatformInfo)i.next()).clear() ;
+ staticVpMap.clear() ;
+
+ i = staticSiMap.values().iterator() ;
+ while (i.hasNext()) ((ScreenInfo)i.next()).clear() ;
+ staticSiMap.clear() ;
+ }
+
+ /**
+ * Arrange for an update of cached screen parameters. If automatic update
+ * has not been enabled, then this method should be called if any of the
+ * attributes of the Screen3D have changed. This method should also be
+ * called if the screen changes pixel resolution.
+ *
+ * @param s3d the Screen3D to update
+ */
+ public void updateScreen(Screen3D s3d) {
+ if (verbose) System.err.println("updateScreen") ;
+ ScreenInfo si = (ScreenInfo)screenMap.get(s3d) ;
+ if (si != null) si.updateScreen = true ;
+ }
+
+ /**
+ * Arrange for an update of cached canvas parameters. If automatic update
+ * has not been enabled, then this method should be called if any of the
+ * attributes of the Canvas3D have changed. These attributes include the
+ * canvas position and size, but do not include the attributes of
+ * the associated Screen3D, which are cached separately.
+ *
+ * @param c3d the Canvas3D to update
+ */
+ public void updateCanvas(Canvas3D c3d) {
+ if (verbose) System.err.println("updateCanvas") ;
+ CanvasInfo ci = (CanvasInfo)canvasMap.get(c3d) ;
+ if (ci != null) ci.updateCanvas = true ;
+ }
+
+ /**
+ * Arrange for an update of cached view parameters. If automatic update
+ * has not been enabled for the View, then this method should be called if
+ * any of the attributes of the View associated with this object have
+ * changed.
+ *
+ * These do not include the attributes of the existing Canvas3D or
+ * Screen3D components of the View, but do include the attributes of all
+ * other components such as the PhysicalEnvironment and PhysicalBody, and
+ * all attributes of the attached ViewPlatform except for its
+ *
+ *
+ * This method should also be called if the ViewPlatform is replaced with
+ * another using the View's
+ *
+ * Calling this method causes most transforms to be re-derived. It should
+ * be used only when necessary.
+ */
+ public void updateView() {
+ if (verbose) System.err.println("updateView") ;
+ this.updateView = true ;
+ }
+
+ /**
+ * Arrange for an update of the cached head position if head tracking is
+ * enabled. If automatic update has not enabled for the head position,
+ * then this method should be called anytime a new head position is to be
+ * read.
+ */
+ public void updateHead() {
+ if (verbose) System.err.println("updateHead") ;
+ this.updateHead = true ;
+ }
+
+ /**
+ * Arrange for an update of the cached
+ *
+ * The View must be attached to a ViewPlatform which is part of a live
+ * scene graph, and the ViewPlatform node must have its
+ *
+ *
+ * The default implementation uses the head tracking sensor specified by
+ * the View's PhysicalEnvironment, and reads it by calling the sensor's
+ *
+ *
+ * The default implementation returns
+ * @see Canvas3D
+ * @see PhysicalEnvironment
+ * @see PhysicalBody
+ * @see View
+ * @see ViewerAvatar
+ */
+public class Viewer {
+ private static final boolean debug = false;
+ private static PhysicalBody physicalBody = null;
+ private static PhysicalEnvironment physicalEnvironment = null;
+ private View view = null;
+ private ViewerAvatar avatar = null;
+ private Canvas3D[] canvases = null;
+ private JFrame[] j3dJFrames = null;
+ private JPanel[] j3dJPanels = null;
+ private Window[] j3dWindows = null;
+ private ViewingPlatform viewingPlatform = null;
+
+ /**
+ * Creates a default viewer object. The default values are used to create
+ * the PhysicalBody and PhysicalEnvironment. A single RGB, double buffered
+ * and depth buffered Canvas3D object is created. The View is created
+ * with a front clip distance of 0.1f and a back clip distance of 10.0f.
+ */
+ public Viewer() {
+ // Call main constructor with default values.
+ this(null, null, null, true);
+ }
+
+ /**
+ * Creates a default viewer object. The default values are used to create
+ * the PhysicalBody and PhysicalEnvironment. The View is created
+ * with a front clip distance of 0.1f and a back clip distance of 10.0f.
+ *
+ * @param userCanvas the Canvas3D object to be used for rendering;
+ * if this is null then a single RGB, double buffered and depth buffered
+ * Canvas3D object is created
+ * @since Java3D 1.1
+ */
+ public Viewer(Canvas3D userCanvas) {
+ // Call main constructor.
+ this(userCanvas == null ? null : new Canvas3D[] {userCanvas},
+ null, null, true);
+ }
+
+
+ /**
+ * Creates a default viewer object. The default values are used to create
+ * the PhysicalBody and PhysicalEnvironment. The View is created
+ * with a front clip distance of 0.1f and a back clip distance of 10.0f.
+ *
+ * @param userCanvases the Canvas3D objects to be used for rendering;
+ * if this is null then a single RGB, double buffered and depth buffered
+ * Canvas3D object is created
+ * @since Java3D 1.3
+ */
+ public Viewer(Canvas3D[] userCanvases) {
+ this(userCanvases, null, null, true);
+ }
+
+ /**
+ * Creates a viewer object. The Canvas3D objects, PhysicalEnvironment, and
+ * PhysicalBody are taken from the arguments.
+ *
+ * @param userCanvases the Canvas3D objects to be used for rendering;
+ * if this is null then a single RGB, double buffered and depth buffered
+ * Canvas3D object is created
+ * @param userBody the PhysicalBody to use for this Viewer; if it is
+ * null, a default PhysicalBody object is created
+ * @param userEnvironment the PhysicalEnvironment to use for this Viewer;
+ * if it is null, a default PhysicalEnvironment object is created
+ * @param setVisible determines if the Frames should be set to visible once created
+ * @since Java3D 1.3
+ */
+ public Viewer(Canvas3D[] userCanvases, PhysicalBody userBody,
+ PhysicalEnvironment userEnvironment, boolean setVisible ) {
+
+ if (userBody == null) {
+ physicalBody = new PhysicalBody();
+ } else {
+ physicalBody = userBody;
+ }
+
+ if (userEnvironment == null) {
+ physicalEnvironment = new PhysicalEnvironment();
+ } else {
+ physicalEnvironment = userEnvironment;
+ }
+
+ // Create Canvas3D object if none was passed in.
+ if (userCanvases == null) {
+ GraphicsConfiguration config =
+ ConfiguredUniverse.getPreferredConfiguration();
+
+ canvases = new Canvas3D[1];
+ canvases[0] = new Canvas3D(config);
+ canvases[0].setFocusable(true);
+ createFramesAndPanels(setVisible);
+ }
+ else {
+ canvases = new Canvas3D[userCanvases.length];
+ for (int i=0; i
+ * NOTE: When running under JDK 1.4 or newer, the JFrame always directly
+ * contains the JPanel which contains the Canvas3D. When running under
+ * JDK 1.3.1 and creating a borderless full screen through a configuration
+ * file, the JFrame will instead contain a JWindow which will contain the
+ * JPanel and Canvas3D.
+ *
+ * @param frameNum the index of the JFrame object to retrieve;
+ * if there is no JFrame object for the given index, null is returned
+ * @return a reference to JFrame object created by this Viewer object
+ * @since Java3D 1.3
+ */
+ public JFrame getJFrame(int frameNum) {
+ if (j3dJFrames == null || frameNum > j3dJFrames.length) {
+ return(null);
+ }
+ return j3dJFrames[frameNum];
+ }
+
+ /**
+ * Returns all the JFrames created by this Viewer object. If a Viewer is
+ * constructed without any Canvas3D objects then the Viewer object will
+ * create a Canva3D object, a JPanel containing the Canvas3D object, and a
+ * JFrame to place the JPanel in.
+ *
+ * NOTE: When running under JDK 1.4 or newer, the JFrame always directly
+ * contains the JPanel which contains the Canvas3D. When running under
+ * JDK 1.3.1 and creating a borderless full screen through a configuration
+ * file, the JFrame will instead contain a JWindow which will contain the
+ * JPanel and Canvas3D.
+ *
+ * @return an array of references to the JFrame objects created by
+ * this Viewer object, or null if no JFrame objects were created
+ * @since Java3D 1.3
+ */
+ public JFrame[] getJFrames() {
+ if (j3dJFrames == null)
+ return null;
+
+ JFrame[] ret = new JFrame[j3dJFrames.length];
+ for (int i = 0; i < j3dJFrames.length; i++) {
+ ret[i] = j3dJFrames[i];
+ }
+ return ret;
+ }
+
+ /**
+ * This method is no longer supported since Java 3D 1.3.
+ * @exception UnsupportedOperationException if called.
+ * @deprecated AWT Panel components are no longer created by the
+ * Viewer class.
+ */
+ public Panel getPanel() {
+ throw new UnsupportedOperationException(
+ "AWT Panel components are not created by the Viewer class");
+ }
+
+ /**
+ * Returns the JPanel object created by this Viewer object at the
+ * specified index. If a Viewer is constructed without any Canvas3D
+ * objects then the Viewer object will create a Canva3D object and a
+ * JPanel into which to place the Canvas3D object.
+ *
+ * @param panelNum the index of the JPanel object to retrieve;
+ * if there is no JPanel object for the given index, null is returned
+ * @return a reference to a JPanel object created by this Viewer object
+ * @since Java3D 1.3
+ */
+ public JPanel getJPanel(int panelNum) {
+ if (j3dJPanels == null || panelNum > j3dJPanels.length) {
+ return(null);
+ }
+ return j3dJPanels[panelNum];
+ }
+
+ /**
+ * Returns all the JPanel objects created by this Viewer object. If a
+ * Viewer is constructed without any Canvas3D objects then the Viewer
+ * object will create a Canva3D object and a JPanel into which to place
+ * the Canvas3D object.
+ *
+ * @return an array of references to the JPanel objects created by
+ * this Viewer object, or null or no JPanel objects were created
+ * @since Java3D 1.3
+ */
+ public JPanel[] getJPanels() {
+ if (j3dJPanels == null)
+ return null;
+
+ JPanel[] ret = new JPanel[j3dJPanels.length];
+ for (int i = 0; i < j3dJPanels.length; i++) {
+ ret[i] = j3dJPanels[i];
+ }
+ return ret;
+ }
+
+ /**
+ * Used to create and initialize a default AudioDevice3D used for sound
+ * rendering.
+ *
+ * @return reference to created AudioDevice, or null if error occurs.
+ */
+ public AudioDevice createAudioDevice() {
+ if (physicalEnvironment == null) {
+ System.err.println("Java 3D: createAudioDevice: physicalEnvironment is null");
+ return null;
+ }
+
+ try {
+ String audioDeviceClassName =
+ (String) java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ @Override
+ public Object run() {
+ return System.getProperty("j3d.audiodevice");
+ }
+ });
+
+ if (audioDeviceClassName == null) {
+ throw new UnsupportedOperationException("No AudioDevice specified");
+ }
+
+ // Issue 341: try the current class loader first before trying the
+ // system class loader
+ Class audioDeviceClass = null;
+ try {
+ audioDeviceClass = Class.forName(audioDeviceClassName);
+ } catch (ClassNotFoundException ex) {
+ // Ignore excpetion and try system class loader
+ }
+
+ if (audioDeviceClass == null) {
+ ClassLoader audioDeviceClassLoader =
+ (ClassLoader) java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ @Override
+ public Object run() {
+ return ClassLoader.getSystemClassLoader();
+ }
+ });
+
+ if (audioDeviceClassLoader == null) {
+ throw new IllegalStateException("System ClassLoader is null");
+ }
+
+ audioDeviceClass = Class.forName(audioDeviceClassName, true, audioDeviceClassLoader);
+ }
+
+ Class physEnvClass = PhysicalEnvironment.class;
+ Constructor audioDeviceConstructor =
+ audioDeviceClass.getConstructor(new Class[] {physEnvClass});
+ PhysicalEnvironment[] args = new PhysicalEnvironment[] { physicalEnvironment };
+ AudioEngine3DL2 mixer =
+ (AudioEngine3DL2) audioDeviceConstructor.newInstance((Object[])args);
+ mixer.initialize();
+ return mixer;
+ }
+ catch (Throwable e) {
+ e.printStackTrace();
+ physicalEnvironment.setAudioDevice(null);
+ System.err.println("Java 3D: audio is disabled");
+ return null;
+ }
+ }
+
+ /**
+ * Returns the Universe to which this Viewer is attached
+ *
+ * @return the Universe to which this Viewer is attached
+ * @since Java 3D 1.3
+ */
+ public SimpleUniverse getUniverse() {
+ return getViewingPlatform().getUniverse();
+ }
+
+
+ /*
+ * Exit if run as an application
+ */
+ void addWindowCloseListener(Window win) {
+ SecurityManager sm = System.getSecurityManager();
+ boolean doExit = true;
+
+ if (sm != null) {
+ try {
+ sm.checkExit(0);
+ } catch (SecurityException e) {
+ doExit = false;
+ }
+ }
+ final boolean _doExit = doExit;
+
+ win.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent winEvent) {
+ Window w = winEvent.getWindow();
+ w.setVisible(false);
+ try {
+ w.dispose();
+ } catch (IllegalStateException e) {}
+ if (_doExit) {
+ System.exit(0);
+ }
+ }
+ });
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ViewerAvatar.java b/src/classes/share/org/jogamp/java3d/utils/universe/ViewerAvatar.java
new file mode 100644
index 0000000..36fe76f
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ViewerAvatar.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe;
+
+import org.jogamp.java3d.BranchGroup;
+
+/**
+ * This class holds geomtry that should be associated with the View's
+ * avatar. An avatar is how the user's "virtual self" appears in the
+ * virtual world.
+ *
+ * @see Viewer
+ */
+public class ViewerAvatar extends BranchGroup {
+
+ /**
+ * Constructs an instance of the ViewerAvatar node.
+ */
+ public ViewerAvatar() {
+ setCapability(ALLOW_DETACH);
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ViewingPlatform.java b/src/classes/share/org/jogamp/java3d/utils/universe/ViewingPlatform.java
new file mode 100644
index 0000000..cf116a0
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ViewingPlatform.java
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Group;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.java3d.View;
+import org.jogamp.java3d.ViewPlatform;
+import org.jogamp.vecmath.Vector3d;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+import org.jogamp.java3d.utils.behaviors.vp.ViewPlatformBehavior;
+
+/**
+ * This class is used to set up the "view" side of a Java 3D scene graph.
+ * The ViewingPlatform object contains a MultiTransformGroup node to allow
+ * for a series of transforms to be linked together. To this structure
+ * the ViewPlatform is added as well as any geometry to associate with this
+ * view platform.
+ *
+ * @see ViewPlatform
+ */
+public class ViewingPlatform extends BranchGroup {
+
+ /**
+ * Cached ViewPlatform associated with this ViewingPlatform object.
+ */
+ protected ViewPlatform viewPlatform;
+
+ /**
+ * MultiTransformGroup that holds all TransformGroups between
+ * the BranchGroup and the View object.
+ */
+ protected MultiTransformGroup mtg;
+
+ /**
+ * Used to keep track of added geometry. When geometry
+ * is added to the view platform, an addChild to this BranchGroup
+ * is performed.
+ */
+ protected BranchGroup platformGeometryRoot;
+
+ /**
+ * Used to keep track of added geometry. When geometry
+ * is added for an avatar, an addChild to this BranchGroup
+ * is performed.
+ */
+ protected BranchGroup avatarRoot;
+
+ /**
+ * Cached PlatformGeometry object.
+ */
+ protected PlatformGeometry platformGeometry = null;
+
+ /**
+ * Table of the Viewer objects.
+ */
+ protected Hashtable viewerList;
+
+ /**
+ * Used to keep track of behaviors.
+ *
+ * @since Java 3D 1.2.1
+ */
+ protected BranchGroup behaviors;
+
+ /**
+ * The universe to which this viewing platform is attached
+ *
+ * @since Java 3D 1.3
+ */
+ protected SimpleUniverse universe;
+
+ /**
+ * Creates a default ViewingPlatform object. This consists of a
+ * MultiTransfromGroup node with one transform and a ViewPlatform
+ * object. The ViewPlatform is positioned at (0.0, 0.0, 0.0).
+ */
+ public ViewingPlatform() {
+ // Call main constructor with default values.
+ this(1);
+ }
+
+ /**
+ * Creates the ViewingPlatform object. This consists of a
+ * MultiTransfromGroup node with the specified number of transforms
+ * (all initialized to the identity transform).
+ * and a ViewPlatform object.
+ *
+ * @param numTransforms The number of transforms the MultiTransformGroup
+ * node should contain. If this number is less than 1, 1 is assumed.
+ */
+ public ViewingPlatform(int numTransforms) {
+ viewerList = new Hashtable();
+
+ // Set default capabilities for this node.
+ setCapability(Group.ALLOW_CHILDREN_WRITE);
+ setCapability(Group.ALLOW_CHILDREN_EXTEND);
+ setCapability(BranchGroup.ALLOW_DETACH);
+
+ // Create MultiTransformGroup node.
+ if (numTransforms < 1)
+ numTransforms = 1;
+ mtg = new MultiTransformGroup(numTransforms);
+
+ // Get first transform and add it to the scene graph.
+ TransformGroup tg = mtg.getTransformGroup(0);
+ addChild(tg);
+
+ // Create ViewPlatform and add it to the last transform in the
+ // MultiTransformGroup node.
+ tg = mtg.getTransformGroup(numTransforms - 1);
+ viewPlatform = new ViewPlatform();
+ viewPlatform.setCapability(ViewPlatform.ALLOW_POLICY_READ);
+ viewPlatform.setCapability(ViewPlatform.ALLOW_POLICY_WRITE);
+ tg.addChild(viewPlatform);
+
+ // Set capabilities to allow for changes when live.
+ tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
+ tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+
+ // Initialize the avatarRoot BranchGroup node and add it to the
+ // last transform in the MultiTransformGroup node.
+ avatarRoot = new BranchGroup();
+ avatarRoot.setCapability(Group.ALLOW_CHILDREN_READ);
+ avatarRoot.setCapability(Group.ALLOW_CHILDREN_WRITE);
+ avatarRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND);
+ tg.addChild(avatarRoot);
+
+ // Initialize the platformGeometry BranchGroup node and add it to the
+ // last transform in the MultiTransformGroup node.
+ platformGeometryRoot = new BranchGroup();
+ platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_READ);
+ platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_WRITE);
+ platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND);
+ tg.addChild(platformGeometryRoot);
+ }
+
+ /**
+ * Sets the ViewPlatform node for this ViewingPlatform object.
+ *
+ * @param vp The ViewPlatform node to associate with this ViewingPlatform
+ * object.
+ */
+ public void setViewPlatform(ViewPlatform vp) {
+ TransformGroup tg = getViewPlatformTransform();
+ tg.removeChild(viewPlatform);
+ tg.addChild(vp);
+ viewPlatform = vp;
+ // Assign this to all Viewers.
+ Enumeration e = viewerList.keys();
+
+ while (e.hasMoreElements())
+ ((Viewer)e.nextElement()).setViewingPlatform(this);
+ }
+
+ /**
+ * Returns the ViewPlatform node for this ViewingPlatform object.
+ *
+ * @return The ViewPlatform node associated with this ViewingPlatform
+ * object.
+ */
+ public ViewPlatform getViewPlatform() {
+ return viewPlatform;
+ }
+
+ /**
+ * Assigns the geometry to associate with the ViewingPlatform.
+ * PlatformGeometry is used to hold any geometry to be associated
+ * with the ViewingPlatform. If the ViewingPlatform is to be the
+ * inside of a car, for instance, than the PlatformGeometry could be
+ * the dashboard of the car.
+ *
+ * @param pg The geometry to be associated with this ViewingPlatform.
+ * Passing in null has the effect of deleting any geometry associated
+ * with this ViewingPlatform.
+ */
+ public void setPlatformGeometry(PlatformGeometry pg) {
+ // Just return if trying to set the same PlatformGeometry object.
+ if (platformGeometry == pg)
+ return;
+
+ // If the PlatformGeometry is null, will be removing any geometry
+ // already present.
+ if (pg == null) {
+ if (platformGeometryRoot.numChildren() != 0)
+ platformGeometryRoot.removeChild(0);
+ }
+ else {
+
+ // See if there is an old PlatformGeometry to replace.
+ if (platformGeometryRoot.numChildren() != 0)
+ platformGeometryRoot.setChild(pg, 0);
+ else {
+ platformGeometryRoot.addChild(pg);
+ }
+ }
+ platformGeometry = pg;
+ }
+
+ /**
+ * Returns the PlatformGeometry associated with this ViewingPlatform
+ *
+ * @return The PlatformGeometry associated with this ViewingPlatform
+ */
+ public PlatformGeometry getPlatformGeometry() {
+ return platformGeometry;
+ }
+
+ /**
+ * Returns the MultitransformGroup object for this
+ * ViewingPlatform object.
+ *
+ * @return The MultitransformGroup object.
+ */
+ public MultiTransformGroup getMultiTransformGroup() {
+ return mtg;
+ }
+
+ /**
+ * Returns a reference to the "bottom most" transform in the
+ * MultiTransformGroup that is above the ViewPlatform node.
+ *
+ * @return The TransformGroup that is immediately above the
+ * ViewPlatform object.
+ */
+ public TransformGroup getViewPlatformTransform() {
+ return mtg.getTransformGroup(mtg.getNumTransforms() - 1);
+ }
+
+ /**
+ * Sets the nominal viewing distance in the ViewPlatform transform based
+ * on the current field of view. If the ViewAttachPolicy is not the
+ * default of View.NOMINAL_HEAD, then this method has no effect.
+ *
+ * The ViewPlatform is moved back along Z so that objects at the origin
+ * spanning the normalized X range of -1.0 to +1.0 can be fully viewed
+ * across the width of the window. This is done by setting a translation
+ * of 1/(tan(fieldOfView/2)) in the ViewPlatform transform.
+ *
+ * If there is no Viewer object associated with this ViewingPlatform
+ * object the default field of view of PI/4.0 is used.
+ *
+ * NOTE: Support for multiple Viewer objects is not available. If
+ * multiple viewers are attached to this ViewingPlatform than a
+ * RuntimeException will be thrown.
+ */
+ public void setNominalViewingTransform() {
+ if (viewPlatform.getViewAttachPolicy() == View.NOMINAL_HEAD) {
+ double fieldOfView;
+
+ if (viewerList.size() == 0) {
+ // No Viewer associated with this ViewingPlatform, so use the
+ // default field of view value to move the ViewingPlatform.
+ fieldOfView = Math.PI/4.0;
+ }
+ else {
+ if (viewerList.size() > 1) {
+ throw new RuntimeException
+ (J3dUtilsI18N.getString("ViewingPlatform0"));
+ }
+
+ Viewer viewer = (Viewer)viewerList.keys().nextElement();
+ View view = viewer.getView();
+ fieldOfView = view.getFieldOfView();
+ }
+
+ Transform3D t3d = new Transform3D();
+ double viewDistance = 1.0/Math.tan(fieldOfView/2.0);
+ t3d.set(new Vector3d(0.0, 0.0, viewDistance));
+ getViewPlatformTransform().setTransform(t3d);
+ }
+ }
+
+ /**
+ * Returns the avatarRoot child number of the ViewerAvatar object.
+ * All the children of the avatarRoot are compared with the passed
+ * in ViewerAvatar. If a match is found, the index is returned.
+ *
+ * @param avatar The ViewerAvatar object to look for in the avatarRoot's
+ * child nodes.
+ * @return The index of the child that corresponds to the ViewerAvatar.
+ * If the avatarRoot does not contain the ViewerAvatar -1 is returned.
+ */
+ private int findAvatarChild(ViewerAvatar avatar) {
+ // Search the avatarRoot for the ViewerAvatar associated with
+ // with the Viewer object
+ for (int i = 0; i < avatarRoot.numChildren(); i++) {
+ if (((ViewerAvatar)avatarRoot.getChild(i)) == avatar)
+ return i;
+ }
+
+ // Should never get here.
+ System.err.println("ViewingPlatform.findAvatarChild:Child not found.");
+ return -1;
+ }
+
+ /**
+ * Adds the ViewerAvatar to the scene graph. An avatar (geometry)
+ * can be associated with a Viewer object and displayed by Java 3D.
+ *
+ * @param viewer The viewer object to associate with this avatar.
+ * @param avatar The avatar to add to the scene graph. Passing in
+ * null removes any currently assigned avatar.
+ */
+ void setAvatar(Viewer viewer, ViewerAvatar avatar) {
+ Object oldAvatar = viewerList.get(viewer);
+
+ // A position of -1 means the avatar is not a child of the avatarRoot.
+ int avatarPosition = -1;
+
+ // Because "null" cannot be used in a put the avatarRoot object
+ // is used to signify that there is no ViewerAvatar associated
+ // with this Viewer.
+ if (oldAvatar != avatarRoot)
+ avatarPosition = findAvatarChild((ViewerAvatar)oldAvatar);
+
+ // If the avatar is null, will be removing any geometry already present.
+ if (avatar == null) {
+ if (avatarPosition != -1) {
+ avatarRoot.removeChild(avatarPosition);
+
+ // Reset hashtable entry - avatarRoot == null.
+ viewerList.put(viewer, avatarRoot);
+ }
+ }
+ else {
+ // see if there is an old ViewerAvater to replace
+ if (avatarPosition != -1)
+ avatarRoot.setChild(avatar, avatarPosition);
+ else
+ avatarRoot.addChild(avatar);
+
+ // Update hashtable with new avatar.
+ viewerList.put(viewer, avatar);
+ }
+ }
+
+ /**
+ * When a ViewingPlatform is set by a Viewer, the ViewingPlatform
+ * needs to be informed, via a call to this method. This will add
+ * the Viewer to the ViewingPlatform's viewerList for use when
+ * things such as the PlatformGeometry are changed and all Viewer
+ * scene graphs need to be modified.
+ */
+ void addViewer(Viewer viewer) {
+ // Because the viewerList is also used to associate ViewerAvatars
+ // with Viewer objects a hashtable is used. This routine does not
+ // check for the presence of a ViewerAvatar but the Viewer still
+ // needs to be added to the hashtable. Because "null" cannot be
+ // used in a put the avatarRoot object is used to signify that there
+ // is no ViewerAvatar associated with this Viewer.
+ viewerList.put(viewer, avatarRoot);
+ }
+
+ /*
+ * Cleanup when Viewer set another ViewingPlatform
+ */
+ void removeViewer(Viewer viewer) {
+ viewerList.remove(viewer);
+ }
+
+ /**
+ * Adds a new ViewPlatformBehavior to the ViewingPlatform
+ */
+ void addViewPlatformBehavior(ViewPlatformBehavior behavior) {
+ behavior.setViewingPlatform(this);
+ if (behaviors == null) {
+ behaviors = new BranchGroup();
+ behaviors.setCapability(BranchGroup.ALLOW_DETACH);
+ behaviors.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
+ }
+ // otherwise detach the BranchGroup so we can add to it
+ else {
+ behaviors.detach();
+ }
+ behaviors.addChild(behavior);
+ this.addChild(behaviors);
+ }
+
+ /**
+ * Sets the ViewPlatformBehavior which will operate on the ViewPlatform
+ * transform (the TransformGroup returned by
+ * ViewingPlatform.getViewPlatformTransform()). The ViewPlatformBehavior
+ * may be set after the ViewingPlatform is setLive().
+ * If a behavior is already present, it will be detached and it's
+ * setViewingPlatform method will be called with a parameter of null.
+ * @param behavior The ViewPlatformBehavior to add to the ViewingPlatform.
+ * null will remove the ViewingPlatform behavior.
+ * @since Java 3D 1.2.1
+ */
+ public void setViewPlatformBehavior(ViewPlatformBehavior behavior) {
+ if (behaviors != null) {
+ removeViewPlatformBehavior((ViewPlatformBehavior)behaviors.getChild(0));
+ }
+ if (behavior != null) {
+ addViewPlatformBehavior(behavior);
+ }
+ }
+
+ /**
+ * Removes the specified ViewPlatformBehavior
+ */
+ void removeViewPlatformBehavior(ViewPlatformBehavior behavior) {
+ // remove from the behaviors branch group
+ if (behaviors != null) {
+ behaviors.detach();
+ for (int i = 0; i < behaviors.numChildren(); i++) {
+ if (behaviors.getChild(i) == behavior) {
+ behavior.setViewingPlatform( null );
+ behaviors.removeChild(i);
+ break;
+ }
+ }
+ if (behaviors.numChildren() == 0) behaviors = null;
+ else this.addChild(behaviors);
+ }
+ }
+
+ /**
+ * Returns the number of ViewPlatformBehaviors on the ViewingPlatform
+ */
+ int getViewPlatformBehaviorCount() {
+ return behaviors.numChildren();
+ }
+
+ /**
+ * Returns the ViewPlatformBehavior at the specified index
+ */
+ ViewPlatformBehavior getViewPlatformBehavior(int index) {
+ return (ViewPlatformBehavior)behaviors.getChild(index);
+ }
+
+ /**
+ * Returns the ViewPlatformBehavior
+ * @return the ViewPlatformBehavior for the ViewingPlatform.
+ * Returns null if there is no ViewPlatformBehavior set.
+ * @since Java 3D 1.2.1
+ */
+ public ViewPlatformBehavior getViewPlatformBehavior() {
+ if (behaviors == null) {
+ return null;
+ }
+ return getViewPlatformBehavior(0);
+ }
+
+ /**
+ * Returns the Viewers attached to this ViewingPlatform
+ *
+ * @return the Viewers attached to this viewing platform
+ * @since Java 3D 1.3
+ */
+ public Viewer[] getViewers() {
+ if (viewerList.size() == 0) return null;
+ return (Viewer[])viewerList.keySet().toArray( new Viewer[0] );
+ }
+
+ /**
+ * Returns the Universe to which this ViewingPlatform is attached
+ *
+ * @return the Universe to which this ViewingPlatform is attached
+ * @since Java 3D 1.3
+ */
+ public SimpleUniverse getUniverse() {
+ return universe;
+ }
+
+ /**
+ * Sets the Universe to which this ViewingPlatform is attached
+ *
+ * @param universe the Universe to which this ViewingPlatform is attached
+ * @since Java 3D 1.3
+ */
+ public void setUniverse( SimpleUniverse universe ) {
+ this.universe = universe;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/config-examples.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/config-examples.html
new file mode 100644
index 0000000..bab913b
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/config-examples.html
@@ -0,0 +1,85 @@
+
+
+
+
+
+ j3d1x1-behavior A single
+fullscreen desktop configuration with a configurable view platform behavior.
+ j3d1x1-stereo A single
+fullscreen desktop configuration with stereo viewing.
+ j3d1x1-vr A single fullscreen
+desktop configuration with head tracker, stereo viewing, and 6 degree of
+freedom mouse.
+ j3d1x1-window A single screen
+desktop configuration with a conventional window.
+ j3d1x2-flat A dual-screen planar
+desktop configuration.
+ j3d1x2-rot30 A dual-screen
+desktop configuration with each screen rotated toward the other by 30 degrees.
+ j3d1x3-cave A three-projector cave
+configuration.
+ j3d1x3-cave-vr A
+three-projector cave configuration with head tracking and stereo viewing.
+ j3d1x3-rot45 A three-screen
+desktop configuration with left and right screens rotated 45 degrees from the
+center screen.
+ j3d2x2-flat A four-projector
+configuration arranged in a 2x2 array.
+
+This document is an informal description of the syntax of the Java 3D
+configuration file and a tutorial of the semantics of its various commands.
+Such a file is written by a user or site administrator to describe the physical
+configuration of a local interactive viewing environment. Configuration
+properties that can be described in the file include the sizes, positions, and
+orientations of displays in either fixed screen environments or head mounted
+displays (HMD devices), as well as the input devices and sensors
+available for user interaction apart from the keyboard and mouse abstractions
+provided by the AWT.
+A configuration file is used by passing its URL to either a ConfigContainer or
+a ConfiguredUniverse constructor. The method by which a user specifies the
+file is up to the application, but the universe utilities do provide a few
+means to easily enable an application to perform this task. These depend upon
+a Java 3D property, j3d.configURL, that the user can set on the java
+command line with the -D option. Its value should be a URL string
+indicating the location of the desired file. The application can then either
+call the static ConfigContainer methods
+getConfigURL
+to retrieve the value of the property, or
+
+getConfigURL(String) to specify a default file to be used in case the
+property is not set. Applications are encouraged to devise their own
+user-friendly mechanisms to retrieve the configuration file, although the
+setting of the j3d.configURL property should be honored if at all
+possible.
+If the attempt to open the resource indicated by the URL is successful, then a
+parser will be invoked to read and evaluate the commands it contains and
+deposit the results in the ConfigContainer. The parser will detect syntax
+errors, invalid commands, and bad references, printing descriptive messages to
+System.out, including the line number and text of the offending command. In
+general the parser attempts to continue processing as much of the file as it
+can when encountering an error. Some errors can only be detected after the
+entire file has been evaluated; in those cases an exception will be thrown.
+An application may choose to override the settings of the configuration file by
+accessing view-side scenegraph components directly from the ConfigContainer
+once the file is evaluated. Applications should avoid this in general, as most
+settings are physical calibration constants specific to the local interactive
+viewing environment. Nonetheless, application overrides are still sometimes
+appropriate; for example, the application may have knowledge of the contents of
+the scenegraph that enables it to make a better judgement of where the view's
+clipping planes should be.
+The configuration file syntax is very simple; scanning any of the
+sample configuration files should provide
+the general idea. At the broadest level there are two main types of
+constructs: comments and commands.
+Comments can be either C or C++ style. In a C-style
+comment all text between successive occurances of /* and */ is ignored.
+A C++ comment begins with // and continues to the end of the line.
+A command begins with an opening parenthesis and ends with a closing
+parenthesis. The elements between the parentheses can be of four types:
+alphanumeric strings, numbers, quoted strings, or other commands. During the
+evaluation of a command, any nested command encountered is itself evaluated,
+and the result of that evaluation replaces the nested command within the
+original outer command.
+Strings that contain embedded white space, forward slashes, or invalid
+tokens must be enclosed in quotes (either single or double). Common cases are
+URL strings and Unix path names. Numbers are any non-quoted strings that can
+be parsed as double-precision floating point numbers. The strings true,
+True, false, and False are converted to their corresponding boolean
+values. Strings, quoted strings, and numbers are delimited from each other by
+white space.
+Commands in the configuration file have four special forms: point,
+matrix, top-level, and built-in commands.
+Don't pass 2D, 3D, or 4D points to commands that expect two, three, or four
+numbers instead. This will generate a syntax error indicating an invalid
+number of arguments.
+Command names can either specify top-level or built-in commands. Top-level
+commands generally configure Java 3D core and utility classes and can only
+appear at the outermost level of parentheses. Built-in commands are provided
+by the parser itself to help construct the arguments to top-level commands.
+Points, matrices, and built-in commands can only be nested within other
+commands.
+An error will result if points, matrices, or built-in commands are invoked at
+the outermost level of nesting. Sometimes this error is caused by prematurely
+closing the opening parenthesis of the current top-level command. Such an
+error is usually preceded by an error from the command indicating an invalid
+number of arguments.
+Similarly, errors will be generated if top-level commands are nested. Errors
+to this effect are sometimes caused by failing to close all the open
+parentheses of the preceding top-level command.
+(Include "file:${user.home}/myBody.cfg")
+would evaluate the contents of the file "myBody.cfg" in the user's home
+directory on Unix systems. An error is issued if no Java property exists with
+the specified name.
+Java property substitution happens early, after tokenization but before command
+evaluation. Substitution can occur any number of times anywhere within any
+quoted or non-quoted string, including command names, property names, and
+property values, as long as the property substitution syntax is not nested.
+Most top-level commands configure concrete Java 3D core and utility classes.
+These include PhysicalBody, PhysicalEnvironment, Screen, Sensor, View, and
+ViewPlatform. The Screen, View, and ViewPlatform commands also implicitly
+configure the Canvas3D core class and the Viewer and ViewingPlatform utility
+classes respectively.
+These commands come in two forms: the New<class name> and
+<class name>Property commands. All New commands except
+NewSensor create new class instances and bind names to
+them, while the Property commands refer to these names and configure
+their corresponding class instances with the parameters specified by the
+command arguments. All references must be to objects previously instantiated
+in the file; forward referencing is not supported. Names must be unique within
+each class.
+Implementations of the Java 3D InputDevice interface and concrete subclasses of
+the abstract ViewPlatformBehavior utility class can also be instantiated and
+configured with the same command forms. The New commands for these
+objects accept class names as command arguments and instantiate the objects
+through introspection. Since the details of the implementations are not known,
+configuration parameters are passed through methods which are invoked through
+introspection of the method names specified in the Property command
+arguments.
+A method invoked through introspection with a Property command gets its
+arguments as a single array of Objects. Boolean strings get wrapped into
+Boolean objects, and number strings get wrapped into Double. 2D, 3D, and 4D
+points get wrapped into Point2d, Point3d, and Point4d objects respectively,
+while 3D and 4D matrices get wrapped into Matrix3d and Matrix4d
+respectively.
+The sample configuration files are annotated to assist users in modifying them
+to suit their particular viewing environments, but it can be helpful to know
+some of the basics of the Java 3D view model that are relevant to writing a
+configuration file. This overview should only be considered an informal
+adjunct to the detailed description in the Java 3D Specification. Reading the
+source code to the ViewInfo utility (a public
+implementation of the Java 3D view model) may also be helpful in understanding
+the details of the view model.
+In the traditional camera model the camera or eyepoint is positioned and
+oriented with respect to the virtual world via a view transform. Objects
+contained within the field of view are projected onto an image plane, which is
+then mapped onto a display surface, usually a window on a desktop display
+system. While the view direction and camera position can be freely oriented
+and placed anywhere in the virtual world, the projection is accomplished using
+a static frustum defined by the field of view and a flat image plane centered
+about and normal to the view direction.
+This model emulates a typical physical camera quite well, but there are many
+viewing configurations that cannot be implemented using image planes that are
+fixed with respect to the view direction. In a multiple screen environment the
+projection frustum for each screen is skewed with respect to the image plane,
+based on the user's nominal viewing position. Realistic stereo views on fixed
+displays use skewed projection frustums derived from the offsets of the two
+eyes from the center of the image plane, while head tracking with fixed
+displays involves dynamically adjusting projection frustums in response to
+varying eye positions relative to the image plane.
+In a low-level API such as OpenGL these situations are handled by concatenating
+all defined model and viewing transforms into a single modelview matrix,
+and for a fixed-screen environment explicitly computing the projection
+matrix for each eye, each display surface, and each new head
+position. Every application handling such viewing configurations typically
+reimplements the framework for computing those matrices itself. In these cases
+it would be useful to be able to separate the projection components out of the
+view transform in some representation based on display and eye locations.
+Based on these requirements, a high-level view model should provide standard
+mechanisms to 1) define a screen's position and orientation in relation to
+other screens in the viewing environment; 2) specify the position of the user's
+eyes or an HMD relative to the physical space in which the screens or nominal
+user position are defined, and to have them updated automatically if tracking
+hardware exists; and 3) describe where the whole physical space is placed and
+oriented in the virtual world. In such a model the appropriate images could
+then be rendered without further computation in application code.
+In the Java 3D view model, screen (image plate) positions and
+orientations are defined relative to a fixed frame of reference in the physical
+world, the tracker base, through the
+TrackerBaseToImagePlate property. The
+tracker base is somewhat abstract in that it is always used to define that
+fixed frame of reference, even if no physical tracking hardware is being
+used. If the ViewPolicy is HMD_VIEW, then the left
+and right image plates for head mounted displays are defined relative to the
+head tracking sensor, which reports head orientation and position relative to
+the tracker base.
+Coexistence coordinates are defined with the
+CoexistenceToTrackerBase property. It
+provides a frame of reference in the physical world which can be set up by the
+user or application in whatever way is most convenient for positioning and
+orienting screens, physical body attributes, and sensing devices in the virtual
+world. If tracking is enabled, then the eye positions in coexistence are
+computed from the position and orientation of the head tracking sensor and the
+HeadToHeadTracker matrix; otherwise the eye
+positions in coexistence are set according to the
+CenterEyeInCoexistence property. In HMD
+mode the eye positions are fixed with respect to the image plates.
+The mapping of coexistence coordinates into the virtual world is accomplished
+through the ViewAttachPolicy, which specifies
+the point in coexistence coordinates to which the origin of the view
+platform should be mapped. The view platform is positioned in the virtual
+world by manipulating its view transform, the composite of all the
+transforms from the view platform up to its Locale. The basis vectors (X, Y,
+and Z directions) of the view platform are always aligned with coexistence
+coordinates, and the scaling between view platform coordinates and physical
+coordinates is specified by the
+ScreenScalePolicy, so this
+establishes the complete mapping of the physical world into the virtual world.
+The projection of the virtual world onto the physical display surfaces is then
+performed automatically by the Java 3D renderer.
+By default Java 3D tries to emulate the familiar camera model as much as
+possible to make it easy to run in a conventional windowed desktop display
+environment. It accomplishes this through the following default settings:
+Top-level commands can only appear at the outermost command nesting level.
+This command instantiates the InputDevice implementation specified by the fully
+qualified class name and binds it to instance name. The
+InputDevice is instantiated through introspection of the class name. The
+implementation must provide a parameterless constructor; this can usually be
+done by extending or wrapping available InputDevice implementations.
+The last two arguments are optional and define an alias for instance
+name. This is useful in providing a longer descriptive name for the
+application to recognize, or conversely, to provide a shorter alias for a
+longer instance name. Either name may be used to identify the instance.
+At the conclusion of configuration file processing all InputDevice
+implementations so defined will be initialized and registered with any
+PhysicalEnvironments that reference them.
+
+The details of the InputDevice implementation specified by instance name
+are not known to ConfigContainer, so any parameters to be set through the
+configuration file are passed to the InputDevice instance by invoking method
+name through introspection. The arguments following the method name are
+evaluated and the results passed to the method as an array of Objects.
+The required methods can usually be provided by extending or wrapping existing
+InputDevice implementations.
+Retrieves the Sensor at index sensor index in the InputDevice device
+name and binds it to the name specified by instance name. The
+sensor index is a number truncated to its integer value. The InputDevice
+implementation is responsible for creating its own Sensor objects, so this
+command does not create any new instances.
+Instance name is used by other commands to reference the indicated
+Sensor. In addition, the name and its associated Sensor instance is made
+available to applications through a Map returned by the ConfigContainer
+method
+getNamedSensors.
+
+The last two arguments are optional and define an alias for instance
+name. This is useful in providing a longer descriptive name for the
+application to recognize, or conversely, to provide a shorter alias for a
+longer instance name. Either name may be used to identify the instance.
+If the Sensor is to be used for head tracking, or tracking the position and
+orientation of other objects in the physical world, then it must generate 6
+degree of freedom data relative to the tracker base.
+Sets a Sensor property. The sensor instance is specified by instance
+name, the property to be set by property name, and the value to be
+set by property value. The following sole property may be
+configured:
+The above two commands are equivalent. Both create new window resources and
+associate them with the name specified by instance name. The device
+index is a number truncated to its integer value. This integer is the
+index at which the desired AWT GraphicsDevice appears in the array returned by
+the static getScreenDevices() method of GraphicsEnvironment, and specifies the
+physical screen upon which the window should be created. The GraphicsDevice
+order in the array is specific to the local viewing site and display
+system.
+The last two arguments are optional and define an alias for instance
+name. This is useful in providing a longer descriptive name for the
+application to recognize, or conversely, to provide a shorter alias for a
+longer instance name. Either name may be used to identify the instance.
+The above two commands are equivalent. The screen or window instance is
+specified by instance name, the property to be set by property
+name, and the value to be set by property value. The following
+properties are configurable:
+Image plate dimensions are expressed in meters. The origin of the image plate
+is the lower left corner of the screen's image area, with X increasing to the
+right, Y increasing to the top, and Z increasing away from the screen.
+The tracker base is somewhat abstract. It is used as a local fixed frame of
+reference for specifying the orientation and position of a screen even when
+tracking hardware is not being used. It is also the frame of reference for
+defining coexistence coordinates with the
+CoexistenceToTrackerBase matrix.
+The built-in commands Translate,
+Rotate, RotateTranslate, and TranslateRotate are available to make it easier
+to create transforms of this type.
+
+
+These are only used when a ViewPolicy of
+The HMD manufacturer's specifications in terms of angle of view, distance to
+the focal plane, aspect ratio, and percentage of image overlap between the left
+and right views can be used to derive the apparent screen positions with
+respect to the head, and from there the positions with respect to the head
+tracker mounted on the head. In most cases there is 100% overlap between the
+two stereo images, so the matrices for both the left and right screens should
+be identical.
+Some HMD devices support field-sequential stereo and are driven as if they were
+a single screen. In that case, only a single screen should be defined, but
+both the left and right head tracker to image plate transforms need to
+be specified for that same screen.
+Some HMD devices can be driven as a single screen if the HMD supports
+field-sequential stereo, so the default policy will work for them as well if a
+stereo view is enabled. If stereo is not enabled, an IllegalStateException will
+be thrown when the ViewPolicy is set to
+The
+Creates a new PhysicalEnvironment and binds it to the name given by instance
+name. This specifies the available input devices, which Sensor to use as
+the head tracker, and defines the coexistence coordinate system. Note that
+aside from the head tracker, the configuration file does not provide a way to
+place Sensors into the array maintained by the PhysicalEnvironment. See the
+getNamedSensors
+method of ConfigContainer.
+The last two arguments are optional and define an alias for instance
+name. This is useful in providing a longer descriptive name for the
+application to recognize, or conversely, to provide a shorter alias for a
+longer instance name. Either name may be used to identify the instance.
+Sets a PhysicalEnvironment property. The instance is specified by instance
+name, the property to be set by property name, and the value to be
+set by property value. The following properties are configurable:
+There is no actual method in the core PhysicalEnvironment class to set the head
+tracker. This property is a simplified interface for setting the
+PhysicalEnvironment head index and assigning the head tracking sensor to that
+index. Direct access to the PhysicalEnvironment Sensor array is not supported
+by the configuration file.
+The coexistence origin (center of coexistence) positions the physical
+world with respect to the origin of the ViewPlatform in the virtual world.
+This is established through the
+ViewAttachPolicy, which attaches the view
+platform to either the center of coexistence, the nominal head, or the nominal
+feet. Coexistence coordinates can essentially be thought of as physical
+coordinates, but the real purpose is to define the space in which coordinates
+systems in the physical world - such as tracker base, image plate, and physical
+body - coexist and interact with the virtual world coordinate systems.
+The basis vectors (X, Y, and Z directions) of coexistence coordinates are
+always aligned with the basis vectors of the ViewPlatform in the virtual world,
+and the scale factor going from ViewPlatform coordinates to coexistence
+coordinates is set by the ScreenScalePolicy.
+Together with the ViewPlatform's view attach policy and view transform this
+establishes the complete mapping of the physical world into the virtual
+world.
+The positioning and orientation of coexistence coordinates with respect to the
+physical environment is up to the user or application. In a fixed screen
+environment it usually makes most sense to define it in a convenient
+relationship to the primary screen or some intersection of the available
+screens, such that the coexistence origin is in front of and aligned with the
+user's nominal forward gaze direction. This is because the -Z axis of
+coexistence coordinates always points along the view direction defined by the
+view platform's -Z axis.
+For example, when using a single screen, the most common mapping puts the
+center of coexistence in the middle of the screen with its basis vectors
+aligned with the screen's image plate coordinate system. With a dual-screen
+system it is usually most convenient to place the center of coexistence in the
+middle of the edge shared by both screens, with its Z axis extending
+perpendicular to the shared edge and maintaining an equal angle to both
+screens. For a 2x2 array of four screens putting the center of coexistence at
+the center of the array is usually a good choice. In a cave configuration
+having the center of coexistence in the middle of the viewing environment can
+facilitate the sense of immersion.
+In HMD mode the view attach policy is ignored and is always effectively
+
+Note: the normal Java 3D default is to place the center of coexistence
+in the middle of the screen or canvas by setting
+CoexistenceCenteringEnable true by
+default. This only works for a single screen and if both the
+TrackerBaseToImagePlate and CoexistenceToTrackerBase matrices are identity. If
+either of these matrices are set from their default identity values in the
+configuration file, and CoexistenceCenteringEnable has not been set, then the
+centering property will be set false by default.
+
+Creates a new PhysicalBody and binds it to the name given by instance
+name. The PhysicalBody is essentiallly the users's head, with the origin
+halfway between the eyes in the plane of the face. Positive X extends to the
+right eye, positive Y up, and positive Z extends into the skull opposite to the
+forward gaze direction. Dimensions are expressed in meters.
+The last two arguments are optional and define an alias for instance
+name. This is useful in providing a longer descriptive name for the
+application to recognize, or conversely, to provide a shorter alias for a
+longer instance name. Either name may be used to identify the instance.
+Sets a PhysicalBody property. The instance is specified by instance
+name, the property to be set by property name, and the value to be
+set by property value. The following properties are configurable:
+This property is a simplified interface to setting the PhysicalBody's separate
+left and right eye positions; there is no actual method in PhysicalBody to set
+stereo eye separation, but the results are exactly equivalent.
+Creates a new view and binds it to the name given by instance name.
+In the configuration file the term view refers to an instance of the
+Viewer utility class, which contains both an
+instance of a core Java 3D View class and an array of Canvas3D instances into
+which to render.
+The last two arguments are optional and define an alias for instance
+name. This is useful in providing a longer descriptive name for the
+application to recognize, or conversely, to provide a shorter alias for a
+longer instance name. Either name may be used to identify the instance.
+ConfiguredUniverse requires that at least one view be defined. If a view
+platform is not provided, then ConfiguredUniverse will create a default one and
+attach the view to that. If multiple views are defined, then at least one view
+platform must be explicitly provided by the configuration, and the
+ViewPlatform property must be used to attach each view to a view platform.
+Sets a View property. The view instance is specified by instance name,
+the property to be set by property name, and the value to be set by
+property value. The following properties are configurable:
+This only works if a single screen is being used and if both the
+TrackerBaseToImagePlate and
+CoexistenceToTrackerBase matrices are
+identity. If CoexistenceCenteringEnable is not explicitly set, and either the
+CoexistenceToTrackerBase transform for the view has been set or
+TrackerBaseToImagePlate has been set for any screen, then the centering enable
+will be set to false by default; otherwise, the normal default is true. This
+property is also effectively false whenever the ViewPolicy is set to
+
+For the
+These polices are ignored if head tracking is enabled.
+This property is a simplified interface to setting the View's left
+and right manual eyes in coexistence; there is no actual method in View
+to set a center eye position.
+If the value is
+
+The view platform is positioned in the virtual world through a chain of
+transforms to the root of the scene graph; this composite transform is its
+localToVWorld transform and must be congruent. If we take the the inverse of
+the scale factor in this transform and call it the view platform scale,
+then the scale from virtual world units to physical world units can be computed
+as the product of this view platform scale, the screen scale, and, when using a
+resize policy of
+With the default clip policies of
+There is a quirk, however, with physical clip plane scaling when the
+
+This quirk applies only to scaling physical clip plane distances, and only with
+the
+There is no actual method in the core Java 3D View or utility Viewer class to
+enable stereo. A true value for this property causes ConfigContainer to
+attempt to create stereo-capable canvases for all the screens associated with
+this view. Stereo will then be enabled for each canvas successfully created
+with stereo capability.
+Setting this property true causes WindowEyepointPolicy to be ignored; it will
+effectively be
+A true value for this property causes ConfigContainer to attempt to create
+a canvas capable of scene antialiasing on each screen associated with this
+view. The scene will then be antialiased on each canvas successfully created
+with that capability.
+Line and point antialiasing are independent of scene antialiasing and are
+controlled by the LineAttribute and PointAttribute components of an Appearance.
+If line and point antialiasing is enabled, then they will be antialiased prior
+to scene antialiasing; if scene antialiasing is turned off, then antialiased
+lines and points will still be antialiased.
+Creates a new view platform and binds it to the name given by instance
+name. In the configuration file the term view platform refers to an
+instance of the ViewingPlatform utility
+class, which is an extension of BranchGroup containing an instance of a core
+Java 3D ViewPlatform class.
+The last two arguments are optional and define an alias for instance
+name. This is useful in providing a longer descriptive name for the
+application to recognize, or conversely, to provide a shorter alias for a
+longer instance name. Either name may be used to identify the instance.
+Sets a ViewPlatform property. The instance is specified by instance
+name, the property to be set by property name, and the value to be
+set by property value. The following properties are configurable:
+For a ViewAttachPolicy of
+For a ViewAttachPolicy of
+For a ViewAttachPolicy of
+Note: The normal Java 3D default is
+This command instantiates the concrete subclass of ViewPlatformBehavior
+specified by the fully qualified class name and binds it to instance
+name. The ViewPlatformBehavior is instantiated through introspection of
+the class name. The subclass must provide a parameterless constructor. If no
+such constructor is available, then the behavior must be extended or wrapped to
+provide one and the derived class used instead.
+The last two arguments are optional and define an alias for instance
+name. This is useful in providing a longer descriptive name for the
+application to recognize, or conversely, to provide a shorter alias for a
+longer instance name. Either name may be used to identify the instance.
+View platform behaviors often need sensors or canvases as event sources to
+drive the behavior action. A subclass of ViewPlatformBehavior always gets the
+current ViewingPlatform through its
+setViewingPlatform
+method. When the behavior is initialized, the canvases used by the
+ViewingPlatform can be retrieved by calling its
+getViewers method and
+then calling each Viewer's
+getCanvas3Ds method. Sensors
+can be retrieved by calling the ViewingPlatform method
+getUniverse, checking
+to see if the returned SimpleUniverse is a ConfiguredUniverse, and then calling
+its
+getNamedSensors
+method.
+Alternatively, the behavior implementation can define its own properties
+and receive canvas and sensor instances directly through the
+Canvas3D and Sensor built-in
+commands.
+Sets a property of a ViewPlatformBehavior. The instance is specified by
+instance name, the property to be set by property name, and the
+value to be set by property value. The following properties are
+pre-defined by the abstract ViewPlatformBehavior superclass and may be
+configured directly:
+
+
+The details of a concrete subclass of ViewPlatformBehavior are not known to
+ConfigContainer, so any properties specific to the subclass are set by
+using introspection to invoke property name as a method accepting an
+array of Objects as its single parameter. The arguments following the property
+name are evaluated and the results passed to the method through that array of
+Objects. Such methods can usually be provided by extending or wrapping
+existing ViewPlatformBehavior implementations.
+This command instantiates a generic object specified by class
+name and binds it to instance name. The object is instantiated
+through introspection of the class name. The object must provide a
+parameterless constructor; this can usually be done by extending or
+wrapping existing objects.
+The last two arguments are optional and define an alias for instance
+name. This is useful in providing a longer descriptive name for the
+application to recognize, or conversely, to provide a shorter alias for a
+longer instance name. Either name may be used to identify the instance.
+Objects so defined may be accessed from ConfigContainer through the
+getNamedGenericObjects method.
+Sets a property of a generic object. The details of the object specified by
+instance name are not known to ConfigContainer, so any parameters to be
+set through the configuration file are passed to the object instance by
+invoking method name through introspection. The arguments following the
+method name are evaluated and the results passed to the method as an array of
+Objects. The required methods can usually be provided by extending or wrapping
+existing objects.
+Sets the Java system property propertyName to the string
+propertyValue. If the optional Default keyword is supplied, then the
+property is set only if it doesn't currently have a value.
+Java system properties which affect Java 3D are evaluated at the first
+reference to a VirtualUniverse. Setting such properties in the configuration
+file is therefore ineffective if a ConfiguredUniverse constructor which accepts
+a URL directly is used; ConfigContainer must be used instead. Even then, care
+must be taken to avoid static references to VirtualUniverse from objects such
+as Transform3D.
+The special Java property substitution syntax ${<propertyName>}
+may be used to access the value of a Java system property anywhere within a
+configuration file.
+Retrieves the configuration file specified by URL string and includes it
+into the current configuration file at the current line. The content of the
+included file is evaluated exactly as if it were pasted into the current file
+at that line. Included files may be arbitrarily nested.
+URL strings must be quoted.
+
+Creates an alias for the object specified by originalName (which itself
+may be an alias). baseName may be Device, Object, PhysicalBody,
+PhysicalEnvironment, Screen, Window, Sensor, View, ViewPlatform, or
+ViewPlatformBehavior; it specifies the type of the object being aliased.
+Original names and aliases must be unique within a type. Note that there is no
+white space between baseName and Alias.
+Aliases are useful for providing shorter or longer descriptive names for an
+original name. This function is also provided by the optional Alias keyword
+available for all New top-level commands. This separate command can be
+used to substitute new names for objects created by generic include files in
+order to conform to the names expected by specific applications.
+Built-in commands are provided by the parser itself to help construct the
+arguments to top-level commands. They cannot appear at the top level of
+command nesting.
+Translate, Rotate, TranslateRotate, and RotateTranslate are useful for
+computing simple affine transforms of the form SourceToTarget
+(e.g., TrackerBaseToImagePlate). These transform points from the
+Source coordinate system to the Target coordinate system by
+concatenating translation and rotation matrices. Here is a general rule for
+creating such transforms:
+If instead it is easier to measure or compute the source origin relative to the
+target origin along the target basis vectors, rotate first with Euler angles
+that move the target basis vectors to their corresponding source basis vectors,
+and then add (translate) the source origin.
+The Canvas3D, Sensor, Device, PhysicalBody, PhysicalEnvironment, View,
+ViewPlatform, ViewPlatformBehavior, and Object built-in commands return
+references to the objects named by their arguments. These are mostly useful
+for InputDevice and ViewPlatformBehavior implementations that define their own
+properties. The return values of these built-in commands should not be passed
+to commands that expect strings.
+Returns a 4D matrix that translates by the given X, Y, and Z values.
+Returns a 4D matrix that rotates by the given Euler angles around static X, Y,
+and Z basis vectors: first about X, then Y, and then Z. See the
+setEuler
+method of Transform3D.
+Returns a 4D matrix that concatenates 4D matrices m1 and m2 in
+that order. If a point is transformed by the resulting matrix, then in effect
+the points are first transformed by m1 and then m2.
+An alias for the Concatenate command. This is useful to make the
+result of the concatenation explicit.
+An alias for the Concatenate command. This is useful to make the
+result of the concatenation explicit.
+Returns a BoundingSphere object using the 3D point center and the given
+radius in meters. radius may be either a number or the string
+Infinite.
+Returns the Canvas3D instance specified by the given name. A named Canvas3D is
+created whenever any of the following configuration commands are used:
+
+
+Note: the NewScreen and NewWindow commands do not create Canvas3D
+instances themselves; they are created only by the above configuration
+commands.
+Returns the Sensor instance specified by the given name.
+Returns the InputDevice instance specified by the given name.
+Returns the PhysicalBody instance specified by the given name.
+Returns the PhysicalEnvironment instance specified by the given name.
+Returns the Viewer instance specified by the given name.
+Returns the ViewingPlatform instance specified by the given name.
+Returns the ViewPlatformBehavior instance specified by the given name.
+Returns the generic object instance specified by the given name. A generic
+named object is created by the following configuration command:
+
+
+Returns a reference to the current ConfigContainer. Provides utility classes for setting up the Java 3D universe,
+including the viewing configuration.
+ * 1 ... if angle between 0 and 180 degrees
+ * 2 ... if angle is 0 degrees
+ * -1 ... if angle between 180 and 360 degrees
+ * -2 ... if angle is 360 degrees
+ */
+ static int isConvexAngle(Triangulator triRef, int i, int j, int k, int ind) {
+ int angle;
+ double numericsHDot;
+ int numericsHOri1;
+ Point2f numericsHP, numericsHQ;
+
+ // if((triRef.inPointsList(i)==false)||(triRef.inPointsList(j)==false)||
+ // (triRef.inPointsList(k)==false))
+ // System.out.println("Numerics.isConvexAngle: Not inPointsList " + i + " " + j
+ // + " " + k);
+
+ if (i == j) {
+ if (j == k) {
+ // all three vertices are identical; we set the angle to 1 in
+ // order to enable clipping of j.
+ return 1;
+ }
+ else {
+ // two of the three vertices are identical; we set the angle to 1
+ // in order to enable clipping of j.
+ return 1;
+ }
+ }
+ else if (j == k) {
+ // two vertices are identical. we could either determine the angle
+ // by means of yet another lengthy analysis, or simply set the
+ // angle to -1. using -1 means to err on the safe side, as all the
+ // incarnations of this vertex will be clipped right at the start
+ // of the ear-clipping algorithm. thus, eventually there will be no
+ // other duplicates at this vertex position, and the regular
+ // classification of angles will yield the correct answer for j.
+ return -1;
+ }
+ else {
+ numericsHOri1 = orientation(triRef, i, j, k);
+ // System.out.println("i " + i + " j " + j + " k " + k + " ind " + ind +
+ // ". In IsConvexAngle numericsHOri1 is " +
+ // numericsHOri1);
+ if (numericsHOri1 > 0) {
+ angle = 1;
+ }
+ else if (numericsHOri1 < 0) {
+ angle = -1;
+ }
+ else {
+ // 0, 180, or 360 degrees.
+ numericsHP = new Point2f();
+ numericsHQ = new Point2f();
+ Basic.vectorSub2D(triRef.points[i], triRef.points[j], numericsHP);
+ Basic.vectorSub2D(triRef.points[k], triRef.points[j], numericsHQ);
+ numericsHDot = Basic.dotProduct2D(numericsHP, numericsHQ);
+ if (numericsHDot < 0.0) {
+ // 180 degrees.
+ angle = 0;
+ }
+ else {
+ // 0 or 360 degrees? this cannot be judged locally, and more
+ // work is needed.
+
+ angle = spikeAngle(triRef, i, j, k, ind);
+ // System.out.println("SpikeAngle return is "+ angle);
+ }
+ }
+ }
+ return angle;
+ }
+
+
+ /**
+ * This method checks whether point i4 is inside of or on the boundary
+ * of the triangle i1, i2, i3.
+ */
+ static boolean pntInTriangle(Triangulator triRef, int i1, int i2, int i3, int i4) {
+ boolean inside;
+ int numericsHOri1;
+
+ inside = false;
+ numericsHOri1 = orientation(triRef, i2, i3, i4);
+ if (numericsHOri1 >= 0) {
+ numericsHOri1 = orientation(triRef, i1, i2, i4);
+ if (numericsHOri1 >= 0) {
+ numericsHOri1 = orientation(triRef, i3, i1, i4);
+ if (numericsHOri1 >= 0) inside = true;
+ }
+ }
+ return inside;
+ }
+
+
+ /**
+ * This method checks whether point i4 is inside of or on the boundary
+ * of the triangle i1, i2, i3. it also returns a classification if i4 is
+ * on the boundary of the triangle (except for the edge i2, i3).
+ */
+ static boolean vtxInTriangle(Triangulator triRef, int i1, int i2, int i3,
+ int i4, int[] type) {
+ boolean inside;
+ int numericsHOri1;
+
+ inside = false;
+ numericsHOri1 = orientation(triRef, i2, i3, i4);
+ if (numericsHOri1 >= 0) {
+ numericsHOri1 = orientation(triRef, i1, i2, i4);
+ if (numericsHOri1 > 0) {
+ numericsHOri1 = orientation(triRef, i3, i1, i4);
+ if (numericsHOri1 > 0) {
+ inside = true;
+ type[0] = 0;
+ }
+ else if (numericsHOri1 == 0) {
+ inside = true;
+ type[0] = 1;
+ }
+ }
+ else if (numericsHOri1 == 0) {
+ numericsHOri1 = orientation(triRef, i3, i1, i4);
+ if (numericsHOri1 > 0) {
+ inside = true;
+ type[0] = 2;
+ }
+ else if (numericsHOri1 == 0) {
+ inside = true;
+ type[0] = 3;
+ }
+ }
+ }
+ return inside;
+ }
+
+
+ /**
+ * Checks whether the line segments i1, i2 and i3, i4 intersect. no
+ * intersection is reported if they intersect at a common vertex.
+ * the function assumes that i1 <= i2 and i3 <= i4. if i3 or i4 lies
+ * on i1, i2 then an intersection is reported, but no intersection is
+ * reported if i1 or i2 lies on i3, i4. this function is not symmetric!
+ */
+ static boolean segIntersect(Triangulator triRef, int i1, int i2, int i3,
+ int i4, int i5) {
+ int ori1, ori2, ori3, ori4;
+
+ // if((triRef.inPointsList(i1)==false)||(triRef.inPointsList(i2)==false)||
+ // (triRef.inPointsList(i3)==false)||(triRef.inPointsList(i4)==false))
+ // System.out.println("Numerics.segIntersect Not inPointsList " + i1 + " " + i2
+ // + " " + i3 + " " + i4);
+ //
+ // if((i1 > i2) || (i3 > i4))
+ // System.out.println("Numerics.segIntersect i1>i2 or i3>i4 " + i1 + " " + i2
+ // + " " + i3 + " " + i4);
+
+ if ((i1 == i2) || (i3 == i4)) return false;
+ if ((i1 == i3) && (i2 == i4)) return true;
+
+ if ((i3 == i5) || (i4 == i5)) ++(triRef.identCntr);
+
+ ori3 = orientation(triRef, i1, i2, i3);
+ ori4 = orientation(triRef, i1, i2, i4);
+ if (((ori3 == 1) && (ori4 == 1)) ||
+ ((ori3 == -1) && (ori4 == -1))) return false;
+
+ if (ori3 == 0) {
+ if (strictlyInBetween(i1, i2, i3)) return true;
+ if (ori4 == 0) {
+ if (strictlyInBetween(i1, i2, i4)) return true;
+ }
+ else return false;
+ }
+ else if (ori4 == 0) {
+ if (strictlyInBetween(i1, i2, i4)) return true;
+ else return false;
+ }
+
+ ori1 = orientation(triRef, i3, i4, i1);
+ ori2 = orientation(triRef, i3, i4, i2);
+ if (((ori1 <= 0) && (ori2 <= 0)) ||
+ ((ori1 >= 0) && (ori2 >= 0))) return false;
+
+ return true;
+ }
+
+
+ /**
+ * this function computes a quality measure of a triangle i, j, k.
+ * it returns the ratio `base / height', where base is the length of the
+ * longest side of the triangle, and height is the normal distance
+ * between the vertex opposite of the base side and the base side. (as
+ * usual, we again use the l1-norm for distances.)
+ */
+ static double getRatio(Triangulator triRef, int i, int j, int k) {
+ double area, a, b, c, base, ratio;
+ Point2f p, q, r;
+
+ // if((triRef.inPointsList(i)==false)||(triRef.inPointsList(j)==false)||
+ // (triRef.inPointsList(k)==false))
+ // System.out.println("Numerics.getRatio: Not inPointsList " + i + " " + j
+ // + " " + k);
+
+ p = triRef.points[i];
+ q = triRef.points[j];
+ r = triRef.points[k];
+
+
+ a = baseLength(p, q);
+ b = baseLength(p, r);
+ c = baseLength(r, q);
+ base = max3(a, b, c);
+
+ if ((10.0 * a) < Math.min(b, c)) return 0.1;
+
+ area = stableDet2D(triRef, i, j, k);
+ if (lt(area, triRef.epsilon)) {
+ area = -area;
+ }
+ else if (!gt(area, triRef.epsilon)) {
+ if (base > a) return 0.1;
+ else return Double.MAX_VALUE;
+ }
+
+ ratio = base * base / area;
+
+ if (ratio < 10.0) return ratio;
+ else {
+ if (a < base) return 0.1;
+ else return ratio;
+ }
+ }
+
+
+ static int spikeAngle(Triangulator triRef, int i, int j, int k, int ind) {
+ int ind1, ind2, ind3;
+ int i1, i2, i3;
+
+ // if((triRef.inPointsList(i)==false)||(triRef.inPointsList(j)==false)||
+ // (triRef.inPointsList(k)==false))
+ // System.out.println("Numerics.spikeAngle: Not inPointsList " + i + " " + j
+ // + " " + k);
+
+ ind2 = ind;
+ i2 = triRef.fetchData(ind2);
+
+ // if(i2 != j)
+ // System.out.println("Numerics.spikeAngle: i2 != j " + i2 + " " + j );
+
+ ind1 = triRef.fetchPrevData(ind2);
+ i1 = triRef.fetchData(ind1);
+
+ // if(i1 != i)
+ // System.out.println("Numerics.spikeAngle: i1 != i " + i1 + " " + i );
+
+ ind3 = triRef.fetchNextData(ind2);
+ i3 = triRef.fetchData(ind3);
+
+ // if(i3 != k)
+ // System.out.println("Numerics.spikeAngle: i3 != k " + i3 + " " + k );
+
+ return recSpikeAngle(triRef, i, j, k, ind1, ind3);
+ }
+
+
+
+ static int recSpikeAngle(Triangulator triRef, int i1, int i2, int i3,
+ int ind1, int ind3) {
+ int ori, ori1, ori2, i0, ii1, ii2;
+ Point2f pq, pr;
+ double dot;
+
+ if (ind1 == ind3) {
+ // all points are collinear??? well, then it does not really matter
+ // which angle is returned. perhaps, -2 is the best bet as my code
+ // likely regards this contour as a hole.
+ return -2;
+ }
+
+ if (i1 != i3) {
+ if (i1 < i2) {
+ ii1 = i1;
+ ii2 = i2;
+ }
+ else {
+ ii1 = i2;
+ ii2 = i1;
+ }
+ if (inBetween(ii1, ii2, i3)) {
+ i2 = i3;
+ ind3 = triRef.fetchNextData(ind3);
+ i3 = triRef.fetchData(ind3);
+
+ if (ind1 == ind3) return 2;
+ ori = orientation(triRef, i1, i2, i3);
+ if (ori > 0) return 2;
+ else if (ori < 0) return -2;
+ else return recSpikeAngle(triRef, i1, i2, i3, ind1, ind3);
+ }
+ else {
+ i2 = i1;
+ ind1 = triRef.fetchPrevData(ind1);
+ i1 = triRef.fetchData(ind1);
+ if (ind1 == ind3) return 2;
+ ori = orientation(triRef, i1, i2, i3);
+ if (ori > 0) return 2;
+ else if (ori < 0) return -2;
+ else return recSpikeAngle(triRef, i1, i2, i3, ind1, ind3);
+ }
+ }
+ else {
+ i0 = i2;
+ i2 = i1;
+ ind1 = triRef.fetchPrevData(ind1);
+ i1 = triRef.fetchData(ind1);
+
+ if (ind1 == ind3) return 2;
+ ind3 = triRef.fetchNextData(ind3);
+ i3 = triRef.fetchData(ind3);
+ if (ind1 == ind3) return 2;
+ ori = orientation(triRef, i1, i2, i3);
+ if (ori > 0) {
+ ori1 = orientation(triRef, i1, i2, i0);
+ if (ori1 > 0) {
+ ori2 = orientation(triRef, i2, i3, i0);
+ if (ori2 > 0) return -2;
+ }
+ return 2;
+ }
+ else if (ori < 0) {
+ ori1 = orientation(triRef, i2, i1, i0);
+ if (ori1 > 0) {
+ ori2 = orientation(triRef, i3, i2, i0);
+ if (ori2 > 0) return 2;
+ }
+ return -2;
+ }
+ else {
+ pq = new Point2f();
+ Basic.vectorSub2D(triRef.points[i1], triRef.points[i2], pq);
+ pr = new Point2f();
+ Basic.vectorSub2D(triRef.points[i3], triRef.points[i2], pr);
+ dot = Basic.dotProduct2D(pq, pr);
+ if (dot < 0.0) {
+ ori = orientation(triRef, i2, i1, i0);
+ if (ori > 0) return 2;
+ else return -2;
+ }
+ else {
+ return recSpikeAngle(triRef, i1, i2, i3, ind1, ind3);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * computes the signed angle between p, p1 and p, p2.
+ *
+ * warning: this function does not handle a 180-degree angle correctly!
+ * (this is no issue in our application, as we will always compute
+ * the angle centered at the mid-point of a valid diagonal.)
+ */
+ static double angle(Triangulator triRef, Point2f p, Point2f p1, Point2f p2) {
+ int sign;
+ double angle1, angle2, angle;
+ Point2f v1, v2;
+
+ sign = Basic.signEps(Basic.det2D(p2, p, p1), triRef.epsilon);
+
+ if (sign == 0) return 0.0;
+
+ v1 = new Point2f();
+ v2 = new Point2f();
+ Basic.vectorSub2D(p1, p, v1);
+ Basic.vectorSub2D(p2, p, v2);
+
+ angle1 = Math.atan2(v1.y, v1.x);
+ angle2 = Math.atan2(v2.y, v2.x);
+
+ if (angle1 < 0.0) angle1 += 2.0*Math.PI;
+ if (angle2 < 0.0) angle2 += 2.0*Math.PI;
+
+ angle = angle1 - angle2;
+ if (angle > Math.PI) angle = 2.0*Math.PI - angle;
+ else if (angle < -Math.PI) angle = 2.0*Math.PI + angle;
+
+ if (sign == 1) {
+ if (angle < 0.0) return -angle;
+ else return angle;
+ }
+ else {
+ if (angle > 0.0) return -angle;
+ else return angle;
+ }
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Orientation.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Orientation.java
new file mode 100644
index 0000000..d532a81
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Orientation.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+
+class Orientation {
+
+ /**
+ * determine the outer polygon and the orientation of the polygons; the
+ * default orientation is CCW for the outer-most polygon, and CW for the
+ * inner polygons. the polygonal loops are referenced by loops[i1,..,i2-1].
+ */
+ static void adjustOrientation(Triangulator triRef, int i1, int i2) {
+
+ double area;
+ int i, outer;
+ int ind;
+
+ if(i1 >= i2)
+ System.out.println("Orientation:adjustOrientation Problem i1>=i2 !!!");
+
+ if (triRef.numLoops >= triRef.maxNumPolyArea) {
+ // System.out.println("Orientation:adjustOrientation Expanding polyArea array .");
+ triRef.maxNumPolyArea = triRef.numLoops;
+ double old[] = triRef.polyArea;
+ triRef.polyArea = new double[triRef.maxNumPolyArea];
+ if(old != null)
+ System.arraycopy(old, 0, triRef.polyArea, 0, old.length);
+ }
+
+ // for each contour, compute its signed area, i.e., its orientation. the
+ // contour with largest area is assumed to be the outer-most contour.
+ for (i = i1; i < i2; ++i) {
+ ind = triRef.loops[i];
+ triRef.polyArea[i] = polygonArea(triRef, ind);
+ }
+
+ // determine the outer-most contour
+ area = Math.abs(triRef.polyArea[i1]);
+ outer = i1;
+ for (i = i1 + 1; i < i2; ++i) {
+ if (area < Math.abs(triRef.polyArea[i])) {
+ area = Math.abs(triRef.polyArea[i]);
+ outer = i;
+ }
+ }
+
+ // default: the outer contour is referenced by loops[i1]
+ if (outer != i1) {
+ ind = triRef.loops[i1];
+ triRef.loops[i1] = triRef.loops[outer];
+ triRef.loops[outer] = ind;
+
+ area = triRef.polyArea[i1];
+ triRef.polyArea[i1] = triRef.polyArea[outer];
+ triRef.polyArea[outer] = area;
+ }
+
+ // adjust the orientation
+ if (triRef.polyArea[i1] < 0.0) triRef.swapLinks(triRef.loops[i1]);
+ for (i = i1 + 1; i < i2; ++i) {
+ if (triRef.polyArea[i] > 0.0) triRef.swapLinks(triRef.loops[i]);
+ }
+ }
+
+ /**
+ * This function computes twice the signed area of a simple closed polygon.
+ */
+ static double polygonArea(Triangulator triRef, int ind) {
+ int hook = 0;
+ int ind1, ind2;
+ int i1, i2;
+ double area = 0.0, area1 = 0;
+
+ ind1 = ind;
+ i1 = triRef.fetchData(ind1);
+ ind2 = triRef.fetchNextData(ind1);
+ i2 = triRef.fetchData(ind2);
+ area = Numerics.stableDet2D(triRef, hook, i1, i2);
+
+ ind1 = ind2;
+ i1 = i2;
+ while (ind1 != ind) {
+ ind2 = triRef.fetchNextData(ind1);
+ i2 = triRef.fetchData(ind2);
+ area1 = Numerics.stableDet2D(triRef, hook, i1, i2);
+ area += area1;
+ ind1 = ind2;
+ i1 = i2;
+ }
+
+ return area;
+ }
+
+
+ /**
+ * Determine the orientation of the polygon. The default orientation is CCW.
+ */
+ static void determineOrientation(Triangulator triRef, int ind) {
+ double area;
+
+ // compute the polygon's signed area, i.e., its orientation.
+ area = polygonArea(triRef, ind);
+
+ // adjust the orientation (i.e., make it CCW)
+ if (area < 0.0) {
+ triRef.swapLinks(ind);
+ triRef.ccwLoop = false;
+ }
+
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/PntNode.java b/src/classes/share/org/jogamp/java3d/utils/geometry/PntNode.java
new file mode 100644
index 0000000..cadd841
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/PntNode.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+// Placeholder list
+class PntNode extends Object {
+ int pnt;
+ int next;
+
+ PntNode() {
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Primitive.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Primitive.java
new file mode 100644
index 0000000..486a0a0
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Primitive.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry;
+
+import java.util.Hashtable;
+
+import org.jogamp.java3d.Appearance;
+import org.jogamp.java3d.Group;
+import org.jogamp.java3d.Material;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.vecmath.Color3f;
+
+/**
+ * Base class for all Java 3D primitives. By default all primitives
+ * with the same parameters share their geometry (e.g., you can have 50
+ * shperes in your scene, but the geometry is stored only once). A
+ * change to one primitive will effect all shared nodes. Another
+ * implication of this implementation is that the capabilities of the
+ * geometry are shared, and once one of the shared nodes is live, the
+ * capabilities cannot be set. Use the GEOMETRY_NOT_SHARED flag if
+ * you do not wish to share geometry among primitives with the same
+ * parameters.
+ */
+
+public abstract class Primitive extends Group {
+ /**
+ * Specifies that normals are generated along with the positions.
+ */
+ public static final int GENERATE_NORMALS = 0x01;
+
+ /**
+ * Specifies that texture coordinates are generated along with the
+ * positions.
+ */
+ public static final int GENERATE_TEXTURE_COORDS = 0x02;
+
+ /**
+ * Specifies that normals are to be flipped along the surface.
+ */
+ public static final int GENERATE_NORMALS_INWARD = 0x04;
+
+ /**
+ * Specifies that texture coordinates are to be Y up.
+ *
+ * @since Java 3D 1.5.1
+ */
+ // Fix to Issue 411. Java 3D prefers images used for texture mapping to be Y-up
+ public static final int GENERATE_TEXTURE_COORDS_Y_UP = 0x08;
+
+
+ /**
+ * Specifies that the geometry being created will not be shared by
+ * another scene graph node. By default all primitives created with
+ * the same parameters share their geometry (e.g., you can have 50
+ * spheres in your scene, but the geometry is stored only once). A
+ * change to one primitive will effect all shared nodes. You
+ * specify this flag if you do not wish to share any geometry among
+ * primitives of the same parameters. */
+ public static final int GEOMETRY_NOT_SHARED = 0x10;
+
+ /**
+ * Specifies that the ALLOW_INTERSECT
+ * capability bit should be set on the generated geometry.
+ * This allows the object
+ * to be picked using Geometry based picking.
+ */
+ public static final int ENABLE_GEOMETRY_PICKING = 0x20;
+
+ /**
+ * Specifies that the ALLOW_APPEARANCE_READ and
+ * ALLOW_APPEARANCE_WRITE bits are to be set on the generated
+ * geometry's Shape3D nodes.
+ */
+ public static final int ENABLE_APPEARANCE_MODIFY = 0x40;
+
+ static final int SPHERE = 0x01;
+ static final int CYLINDER = 0x02;
+ static final int CONE = 0x04;
+ static final int BOX = 0x08;
+
+ // used for cached geometries of Cone and Cylinder
+ static final int TOP_DISK = 0x10;
+ static final int BOTTOM_DISK = 0x20;
+ static final int CONE_DIVISIONS = 0x40;
+
+ int numTris = 0;
+ int numVerts = 0;
+
+ /**
+ * Primitive flags.
+ */
+ int flags;
+
+
+ /**
+ * Constructs a default primitive.
+ */
+ public Primitive()
+ {
+ flags = 0;
+ setCapability(ENABLE_PICK_REPORTING);
+ setCapability(ALLOW_CHILDREN_READ);
+ }
+
+ /**
+ * Returns the total number of triangles in this primitive.
+ * @return the total number of triangles in this primitive
+ */
+ public int getNumTriangles() {
+ return numTris;
+ }
+
+ /**
+ * @deprecated The number of triangles is an immutable attribute.
+ */
+ public void setNumTriangles(int num) {
+ System.err.println("Warning: setNumTriangles has no effect");
+ }
+
+ /**
+ * Returns the total number of vertices in this primitive.
+ * @return the total number of vertices in this primitive
+ */
+ public int getNumVertices() {
+ return numVerts;
+ }
+
+ /**
+ * @deprecated The number of vertices is an immutable attribute.
+ */
+ public void setNumVertices(int num) {
+ System.err.println("Warning: setNumVertices has no effect");
+ }
+
+ /** Returns the flags of primitive (generate normal, textures, caching, etc).
+ */
+ public int getPrimitiveFlags()
+ {
+ return flags;
+ }
+
+ /**
+ * @deprecated The primitive flags must be set at construction time
+ * via one of the subclass constructors.
+ */
+ public void setPrimitiveFlags(int fl) {
+ System.err.println("Warning: setPrimitiveFlags has no effect");
+ }
+
+ /** Obtains a shape node of a subpart of the primitive.
+ * @param partid identifier for a given subpart of the primitive.
+ */
+ public abstract Shape3D getShape(int partid);
+
+ /** Gets the appearance of the primitive (defaults to first subpart).
+ */
+ public Appearance getAppearance(){
+ return getShape(0).getAppearance();
+ }
+
+ /**
+ * Gets the appearance of the specified part of the primitive.
+ *
+ * @param partId identifier for a given subpart of the primitive
+ *
+ * @return The appearance object associated with the partID. If an
+ * invalid partId is passed in, null is returned.
+ *
+ * @since Java 3D 1.2.1
+ */
+ public abstract Appearance getAppearance(int partId);
+
+ /** Sets the appearance of a subpart given a partid.
+ */
+
+ public void setAppearance(int partid, Appearance ap)
+ {
+ getShape(partid).setAppearance(ap);
+ }
+
+ /** Sets the main appearance of the primitive (all subparts) to
+ * same appearance.
+ */
+ public abstract void setAppearance(Appearance ap);
+
+
+ /** Sets the main appearance of the primitive (all subparts) to
+ * a default white appearance.
+ */
+ public void setAppearance(){
+
+ Color3f aColor = new Color3f(0.1f, 0.1f, 0.1f);
+ Color3f eColor = new Color3f(0.0f, 0.0f, 0.0f);
+ Color3f dColor = new Color3f(0.6f, 0.6f, 0.6f);
+ Color3f sColor = new Color3f(1.0f, 1.0f, 1.0f);
+
+ Material m = new Material(aColor, eColor, dColor, sColor, 100.0f);
+ Appearance a = new Appearance();
+ m.setLightingEnable(true);
+ a.setMaterial(m);
+ setAppearance(a);
+ }
+
+ static Hashtable geomCache = new Hashtable();
+
+ String strfloat(float x)
+ {
+ return (new Float(x)).toString();
+ }
+
+ protected void cacheGeometry(int kind, float a, float b,
+ float c, int d, int e, int flags,
+ GeomBuffer geo)
+ {
+ String key = new String(kind+strfloat(a)+strfloat(b)+
+ strfloat(c)+d+e+flags);
+ geomCache.put(key, geo);
+ }
+
+ protected GeomBuffer getCachedGeometry(int kind, float a, float b, float c,
+ int d, int e, int flags)
+ {
+ String key = new String(kind+strfloat(a)+strfloat(b)+
+ strfloat(c)+d+e+flags);
+ Object cache = geomCache.get(key);
+
+ return((GeomBuffer) cache);
+ }
+
+ /**
+ * Clear the shared geometry cache for all Primitive types.
+ * Existing Shapes with shared geometry will continue to share
+ * the geometry. New Primitives will create new shared geometry.
+ *
+ * @since Java 3D 1.3.2
+ */
+ public static void clearGeometryCache() {
+ geomCache.clear();
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Project.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Project.java
new file mode 100644
index 0000000..1e39b7f
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Project.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+import org.jogamp.vecmath.Matrix4f;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Tuple3f;
+import org.jogamp.vecmath.Vector3f;
+
+class Project {
+
+ /**
+ * This function projects the vertices of the polygons referenced by
+ * loops[i1,..,i2-1] to an approximating plane.
+ */
+ static void projectFace(Triangulator triRef, int loopMin, int loopMax) {
+ Vector3f normal, nr;
+ int i, j;
+ double d;
+
+ normal = new Vector3f();
+ nr = new Vector3f();
+
+ // determine the normal of the plane onto which the points get projected
+ determineNormal(triRef, triRef.loops[loopMin], normal);
+ j = loopMin + 1;
+ if (j < loopMax) {
+ for (i = j; i < loopMax; ++i) {
+ determineNormal(triRef, triRef.loops[i], nr);
+ if (Basic.dotProduct(normal, nr) < 0.0) {
+ Basic.invertVector(nr);
+ }
+ Basic.vectorAdd(normal, nr, normal);
+ }
+ d = Basic.lengthL2(normal);
+ if (Numerics.gt(d, Triangulator.ZERO)) {
+ Basic.divScalar(d, normal);
+ }
+ else {
+ // System.out.println("*** ProjectFace: zero-length normal vector!? ***\n");
+ normal.x = normal.y = 0.0f;
+ normal.z = 1.0f;
+ }
+ }
+
+ // project the points onto this plane. the projected points are stored in
+ // the array `points[0,..,numPoints]'
+
+ // System.out.println("loopMin " + loopMin + " loopMax " + loopMax);
+ projectPoints(triRef, loopMin, loopMax, normal);
+
+ }
+
+
+ /**
+ * This function computes the average of all normals defined by triples of
+ * successive vertices of the polygon. we'll see whether this is a good
+ * heuristic for finding a suitable plane normal...
+ */
+ static void determineNormal(Triangulator triRef, int ind, Vector3f normal) {
+ Vector3f nr, pq, pr;
+ int ind0, ind1, ind2;
+ int i0, i1, i2;
+ double d;
+
+ ind1 = ind;
+ i1 = triRef.fetchData(ind1);
+ ind0 = triRef.fetchPrevData(ind1);
+ i0 = triRef.fetchData(ind0);
+ ind2 = triRef.fetchNextData(ind1);
+ i2 = triRef.fetchData(ind2);
+ pq = new Vector3f();
+ Basic.vectorSub((Tuple3f) triRef.vertices[i0], (Tuple3f) triRef.vertices[i1], (Vector3f) pq);
+ pr = new Vector3f();
+ Basic.vectorSub((Tuple3f) triRef.vertices[i2], (Tuple3f) triRef.vertices[i1], (Vector3f) pr);
+ nr = new Vector3f();
+ Basic.vectorProduct(pq, pr, nr);
+ d = Basic.lengthL2(nr);
+ if (Numerics.gt(d, Triangulator.ZERO)) {
+ Basic.divScalar(d, nr);
+ normal.set(nr);
+ }
+ else {
+ normal.x = normal.y = normal.z = 0.0f;
+ }
+
+ pq.set(pr);
+ ind1 = ind2;
+ ind2 = triRef.fetchNextData(ind1);
+ i2 = triRef.fetchData(ind2);
+ while (ind1 != ind) {
+ Basic.vectorSub((Tuple3f) triRef.vertices[i2], (Tuple3f) triRef.vertices[i1], pr);
+ Basic.vectorProduct(pq, pr, nr);
+ d = Basic.lengthL2(nr);
+ if (Numerics.gt(d, Triangulator.ZERO)) {
+ Basic.divScalar(d, nr);
+ if (Basic.dotProduct(normal, nr) < 0.0) {
+ Basic.invertVector(nr);
+ }
+ Basic.vectorAdd(normal, nr, normal);
+ }
+ pq.set(pr);
+ ind1 = ind2;
+ ind2 = triRef.fetchNextData(ind1);
+ i2 = triRef.fetchData(ind2);
+ }
+
+ d = Basic.lengthL2(normal);
+ if (Numerics.gt(d, Triangulator.ZERO)) {
+ Basic.divScalar(d, normal);
+ }
+ else {
+ //System.out.println("*** DetermineNormal: zero-length normal vector!? ***\n");
+ normal.x = normal.y = 0.0f; normal.z = 1.0f;
+
+ }
+ }
+
+
+ /**
+ * This function maps the vertices of the polygon referenced by `ind' to the
+ * plane n3.x * x + n3.y * y + n3.z * z = 0. every mapped vertex (x,y,z)
+ * is then expressed in terms of (x',y',z'), where z'=0. this is
+ * achieved by transforming the original vertices into a coordinate system
+ * whose z-axis coincides with n3, and whose two other coordinate axes n1
+ * and n2 are orthonormal on n3. note that n3 is supposed to be of unit
+ * length!
+ */
+ static void projectPoints(Triangulator triRef, int i1, int i2, Vector3f n3) {
+ Matrix4f matrix = new Matrix4f();
+ Point3f vtx = new Point3f();
+ Vector3f n1, n2;
+ double d;
+ int ind, ind1;
+ int i, j1;
+
+
+ n1 = new Vector3f();
+ n2 = new Vector3f();
+
+ // choose n1 and n2 appropriately
+ if ((Math.abs(n3.x) > 0.1) || (Math.abs(n3.y) > 0.1)) {
+ n1.x = -n3.y;
+ n1.y = n3.x;
+ n1.z = 0.0f;
+ }
+ else {
+ n1.x = n3.z;
+ n1.z = -n3.x;
+ n1.y = 0.0f;
+ }
+ d = Basic.lengthL2(n1);
+ Basic.divScalar(d, n1);
+ Basic.vectorProduct(n1, n3, n2);
+ d = Basic.lengthL2(n2);
+ Basic.divScalar(d, n2);
+
+ // initialize the transformation matrix
+ matrix.m00 = n1.x;
+ matrix.m01 = n1.y;
+ matrix.m02 = n1.z;
+ matrix.m03 = 0.0f; // translation of the coordinate system
+ matrix.m10 = n2.x;
+ matrix.m11 = n2.y;
+ matrix.m12 = n2.z;
+ matrix.m13 = 0.0f; // translation of the coordinate system
+ matrix.m20 = n3.x;
+ matrix.m21 = n3.y;
+ matrix.m22 = n3.z;
+ matrix.m23 = 0.0f; // translation of the coordinate system
+ matrix.m30 = 0.0f;
+ matrix.m31 = 0.0f;
+ matrix.m32 = 0.0f;
+ matrix.m33 = 1.0f;
+
+ // transform the vertices and store the transformed vertices in the array
+ // `points'
+ triRef.initPnts(20);
+ for (i = i1; i < i2; ++i) {
+ ind = triRef.loops[i];
+ ind1 = ind;
+ j1 = triRef.fetchData(ind1);
+ matrix.transform((Point3f)triRef.vertices[j1], vtx);
+ j1 = triRef.storePoint(vtx.x, vtx.y);
+ triRef.updateIndex(ind1, j1);
+ ind1 = triRef.fetchNextData(ind1);
+ j1 = triRef.fetchData(ind1);
+ while (ind1 != ind) {
+ matrix.transform(triRef.vertices[j1], vtx);
+ j1 = triRef.storePoint(vtx.x, vtx.y);
+ triRef.updateIndex(ind1, j1);
+ ind1 = triRef.fetchNextData(ind1);
+ j1 = triRef.fetchData(ind1);
+ }
+ }
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Quadrics.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Quadrics.java
new file mode 100644
index 0000000..18db75d
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Quadrics.java
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry;
+
+
+class Quadrics extends Object {
+
+ Quadrics(){ }
+
+ // new disk code to remove transforms in the primitive code
+ GeomBuffer disk(double r, int xdiv, double y, boolean outside, boolean texCoordYUp) {
+
+ double theta, dtheta, sign, sinTheta, cosTheta;
+
+ if (outside) sign = 1.0;
+ else sign = -1.0;
+
+ dtheta = 2.0*Math.PI / xdiv;
+
+ GeomBuffer gbuf = new GeomBuffer(xdiv+2);
+
+ gbuf.begin(GeomBuffer.TRIANGLE_FAN);
+ gbuf.normal3d(0.0, 1.0*sign, 0.0);
+ gbuf.texCoord2d(0.5, 0.5);
+ gbuf.vertex3d(0.0, y, 0.0);
+
+ // create the disk by evaluating points along the unit circle.
+ // theta is the angle around the y-axis. Then we obtain
+ // (cos(theta), sin(theta)) = (x,z) sample points. The y value
+ // was passed in as a parameter.
+ // texture coordinates are obtain from the unit circle centered at
+ // (.5, .5) in s, t space. thus portions of the texture are not used.
+
+ if (!outside) {
+ for (int i = 0; i <= xdiv; i++) {
+ theta = i * dtheta;
+ // add 90 degrees to theta so lines up wtih the body
+ sinTheta = Math.sin(theta - Math.PI/2.0);
+ cosTheta = Math.cos(theta - Math.PI/2.0);
+ gbuf.normal3d(0.0, 1.0*sign, 0.0);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(0.5+cosTheta*0.5, 1.0 - (0.5+sinTheta*0.5));
+ }
+ else {
+ gbuf.texCoord2d(0.5+cosTheta*0.5, 0.5+sinTheta*0.5);
+ }
+ gbuf.vertex3d(r*cosTheta, y, r*sinTheta);
+ }
+ } else {
+ for (int i = xdiv; i >= 0; i--) {
+ theta = i * dtheta;
+ // add 90 degrees to theta so lines up with the body
+ sinTheta = Math.sin(theta - Math.PI/2.0);
+ cosTheta = Math.cos(theta - Math.PI/2.0);
+ gbuf.normal3d(0.0, 1.0*sign, 0.0);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(0.5+cosTheta*0.5, 1.0 - (0.5-sinTheta*0.5));
+ }
+ else {
+ gbuf.texCoord2d(0.5+cosTheta*0.5, 0.5-sinTheta*0.5);
+ }
+ gbuf.vertex3d(cosTheta*r, y, sinTheta*r);
+ }
+ }
+
+ gbuf.end();
+ return gbuf;
+ }
+
+
+ // new cylinder to remove transforms in the cylinder code and to optimize
+ // by using triangle strip
+ GeomBuffer cylinder(double height, double radius,
+ int xdiv, int ydiv, boolean outside, boolean texCoordYUp) {
+
+ double sign;
+
+ if (outside) sign = 1.0;
+ else sign = -1.0;
+
+ // compute the deltas
+ double dtheta = 2.0*Math.PI / (double)xdiv;
+ double dy = height / (double)ydiv;
+ double du = 1.0/(double)xdiv;
+ double dv = 1.0/(double)ydiv;
+
+ GeomBuffer gbuf = new GeomBuffer(ydiv*2*(xdiv+1));
+
+ double s = 0.0, t = 0.0;
+ double px, pz, qx, qz;
+ double py = -height/2.0;
+ double qy;
+
+ gbuf.begin(GeomBuffer.QUAD_STRIP);
+
+ for (int i = 0; i < ydiv; i++) {
+ qy = py+dy;
+ if (outside) {
+ px = Math.cos(xdiv*dtheta - Math.PI/2.0);
+ pz = Math.sin(xdiv*dtheta - Math.PI/2.0);
+ qx = Math.cos((xdiv-1)*dtheta - Math.PI/2.0);
+ qz = Math.sin((xdiv-1)*dtheta - Math.PI/2.0);
+
+ // vert 2
+ gbuf.normal3d(px*sign, 0.0, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - (t + dv));
+ }
+ else {
+ gbuf.texCoord2d(s, t+dv);
+ }
+ gbuf.vertex3d(px*radius, qy, pz*radius);
+
+ // vert 1
+ gbuf.normal3d(px*sign, 0.0, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - t);
+ } else {
+ gbuf.texCoord2d(s, t);
+ }
+ gbuf.vertex3d(px*radius, py, pz*radius);
+
+ // vert 4
+ gbuf.normal3d(qx*sign, 0.0, qz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s+du, 1.0 - (t + dv));
+ }
+ else {
+ gbuf.texCoord2d(s+du, t+dv);
+ }
+ gbuf.vertex3d(qx*radius, qy, qz*radius);
+
+ // vert 3
+ gbuf.normal3d(qx*sign, 0.0, qz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s+du, 1.0 - t);
+ }
+ else {
+ gbuf.texCoord2d(s+du, t);
+ }
+ gbuf.vertex3d(qx*radius, py, qz*radius);
+
+ s += (du*2.0);
+
+ for (int j = xdiv-2; j >=0; j--) {
+ px = Math.cos(j*dtheta - Math.PI/2.0);
+ pz = Math.sin(j*dtheta - Math.PI/2.0);
+
+ // vert 6
+ gbuf.normal3d(px*sign, 0.0, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - (t + dv));
+ }
+ else {
+ gbuf.texCoord2d(s, t+dv);
+ }
+ gbuf.vertex3d(px*radius, qy, pz*radius);
+
+ // vert 5
+ gbuf.normal3d(px*sign, 0.0, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - t);
+ }
+ else {
+ gbuf.texCoord2d(s, t);
+ }
+ gbuf.vertex3d(px*radius, py, pz*radius);
+
+ s += du;
+ }
+
+ } else {
+// c = 0;
+ px = Math.cos(-Math.PI/2.0);
+ pz = Math.sin(-Math.PI/2.0);
+ qx = Math.cos(dtheta - Math.PI/2.0);
+ qz = Math.sin(dtheta - Math.PI/2.0);
+
+ gbuf.normal3d(px*sign, 0.0, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - (t + dv));
+ }
+ else {
+ gbuf.texCoord2d(s, t+dv);
+ }
+ gbuf.vertex3d(px*radius, qy, pz*radius);
+
+ // vert 1
+ gbuf.normal3d(px*sign, 0.0, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - t);
+ }
+ else {
+ gbuf.texCoord2d(s, t);
+ }
+ gbuf.vertex3d(px*radius, py, pz*radius);
+
+ gbuf.normal3d(qx*sign, 0.0, qz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s+du, 1.0 - (t + dv));
+ }
+ else {
+ gbuf.texCoord2d(s+du, t+dv);
+ }
+ gbuf.vertex3d(qx*radius, qy, qz*radius);
+
+ gbuf.normal3d(qx*sign, 0.0, qz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s+du, 1.0 - t);
+ }
+ else {
+ gbuf.texCoord2d(s+du, t);
+ }
+ gbuf.vertex3d(qx*radius, py, qz*radius);
+
+ s += (du*2.0);
+
+ for (int j = 2; j <= xdiv; j++) {
+ px = Math.cos(j*dtheta - Math.PI/2.0);
+ pz = Math.sin(j*dtheta - Math.PI/2.0);
+
+ gbuf.normal3d(px*sign, 0.0, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - (t + dv));
+ }
+ else {
+ gbuf.texCoord2d(s, t+dv);
+ }
+ gbuf.vertex3d(px*radius, qy, pz*radius);
+
+ gbuf.normal3d(px*sign, 0.0, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - t);
+ }
+ else {
+ gbuf.texCoord2d(s, t);
+ }
+ gbuf.vertex3d(px*radius, py, pz*radius);
+
+ s += du;
+ }
+
+ }
+ s = 0.0;
+ t += dv;
+ py += dy;
+ }
+
+ gbuf.end();
+
+ return gbuf;
+ }
+
+ // new coneBody method to remove transform in the Cone primitive
+ // and to optimize by using triangle strip
+ GeomBuffer coneBody(double bottom, double top, double bottomR, double topR,
+ int xdiv, int ydiv, double dv, boolean outside, boolean texCoordYUp) {
+
+ double r, sign;
+
+ if (outside) sign = 1.0;
+ else sign = -1.0;
+
+ // compute the deltas
+ double dtheta = 2.0*Math.PI/(double)xdiv;
+ double dr = (topR-bottomR)/(double)ydiv;
+ double height = top-bottom;
+ double dy = height/(double)ydiv;
+ double ynormal = (bottomR-topR)/height;
+ double du = 1.0/(double)xdiv;
+// double dv = 1.0/(double)(ydiv+1);
+
+ GeomBuffer gbuf = new GeomBuffer(ydiv*2*(xdiv+1));
+
+ double s = 0.0, t = 0.0;
+ double px, pz, qx, qz;
+ double py = bottom;
+ double qy;
+ r = bottomR;
+
+ gbuf.begin(GeomBuffer.QUAD_STRIP);
+
+ for (int i = 0; i < ydiv; i++) {
+ qy = py+dy;
+ if (outside) {
+ px = Math.cos(xdiv*dtheta - Math.PI/2.0);
+ pz = Math.sin(xdiv*dtheta - Math.PI/2.0);
+ qx = Math.cos((xdiv-1)*dtheta - Math.PI/2.0);
+ qz = Math.sin((xdiv-1)*dtheta - Math.PI/2.0);
+
+ // vert2
+ gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - (t + dv));
+ }
+ else {
+ gbuf.texCoord2d(s, t+dv);
+ }
+ gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr));
+
+ // vert1
+ gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - t);
+ }
+ else {
+ gbuf.texCoord2d(s, t);
+ }
+ gbuf.vertex3d(px*r, py, pz*r);
+
+ // vert4
+ gbuf.normal3d(qx*sign, ynormal*sign, qz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s+du, 1.0 - (t + dv));
+ }
+ else {
+ gbuf.texCoord2d(s+du, t+dv);
+ }
+ gbuf.vertex3d(qx*(r+dr), qy, qz*(r+dr));
+
+ // vert3
+ gbuf.normal3d(qx*sign, ynormal*sign, qz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s+du, 1.0 - t);
+ }
+ else {
+ gbuf.texCoord2d(s+du, t);
+ }
+ gbuf.vertex3d(qx*r, py, qz*r);
+
+ s += (du*2.0);
+
+ for (int j = xdiv-2; j >= 0; j--) {
+ px = Math.cos(j*dtheta - Math.PI/2.0);
+ pz = Math.sin(j*dtheta - Math.PI/2.0);
+
+ // vert 6
+ gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - (t + dv));
+ } else {
+ gbuf.texCoord2d(s, t+dv);
+ }
+ gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr));
+
+ // vert 5
+ gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - t);
+ }
+ else {
+ gbuf.texCoord2d(s, t);
+ }
+ gbuf.vertex3d(px*r, py, pz*r);
+
+ s += du;
+ }
+ } else {
+ px = Math.cos(-Math.PI/2.0);
+ pz = Math.sin(-Math.PI/2.0);
+ qx = Math.cos(dtheta - Math.PI/2.0);
+ qz = Math.sin(dtheta - Math.PI/2.0);
+
+ // vert1
+ gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - (t + dv));
+ }
+ else {
+ gbuf.texCoord2d(s, t+dv);
+ }
+ gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr));
+
+ gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - t);
+ }
+ else {
+ gbuf.texCoord2d(s, t);
+ }
+ gbuf.vertex3d(px*r, py, pz*r);
+
+ gbuf.normal3d(qx*sign, ynormal*sign, qz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s+du, 1.0 - (t + dv));
+ }
+ else {
+ gbuf.texCoord2d(s+du, t+dv);
+ }
+ gbuf.vertex3d(qx*(r+dr), qy, qz*(r+dr));
+
+ gbuf.normal3d(qx*sign, ynormal*sign, qz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s+du, 1.0 - t);
+ }
+ else {
+ gbuf.texCoord2d(s+du, t);
+ }
+ gbuf.vertex3d(qx*r, py, qz*r);
+
+ s += (du*2.0);
+
+ for (int j = 2; j <= xdiv; j++) {
+ px = Math.cos(j*dtheta - Math.PI/2.0);
+ pz = Math.sin(j*dtheta - Math.PI/2.0);
+
+ gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - (t + dv));
+ }
+ else {
+ gbuf.texCoord2d(s, t+dv);
+ }
+ gbuf.vertex3d(px*(r+dr), qy, pz*(r+dr));
+
+ gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - t);
+ }
+ else {
+ gbuf.texCoord2d(s, t);
+ }
+ gbuf.vertex3d(px*r, py, pz*r);
+
+ s += du;
+ }
+ }
+ s = 0.0;
+ t += dv;
+ py += dy;
+ r += dr;
+ }
+ gbuf.end();
+
+ return gbuf;
+ }
+
+ // new coneTop method to remove transforms in the cone code
+ GeomBuffer coneTop(double bottom, double radius, double height,
+ int xdiv,double t, boolean outside, boolean texCoordYUp) {
+
+ double sign;
+
+ if (outside) sign = 1.0;
+ else sign = -1.0;
+
+ // compute the deltas
+ double dtheta = 2.0*Math.PI/(double)xdiv;
+ double ynormal = radius/height;
+ double du = 1.0/(double)xdiv;
+ double top = bottom + height;
+
+ // initialize the geometry buffer
+ GeomBuffer gbuf = new GeomBuffer(xdiv + 2);
+ gbuf.begin(GeomBuffer.TRIANGLE_FAN);
+
+ // add the tip, which is the center of the fan
+ gbuf.normal3d(0.0, ynormal*sign, 0.0);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(.5, 0.0);
+ }
+ else {
+ gbuf.texCoord2d(.5, 1.0);
+ }
+ gbuf.vertex3d(0.0, top, 0.0);
+
+ // go around the circle and add the rest of the fan
+ double s = 0.0;
+ double px, pz;
+ if (outside) {
+ for (int i = xdiv; i >= 0; i--) {
+ px = Math.cos(i*dtheta - Math.PI/2.0);
+ pz = Math.sin(i*dtheta - Math.PI/2.0);
+ gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - t);
+ } else {
+ gbuf.texCoord2d(s, t);
+ }
+ gbuf.vertex3d(px*radius, bottom, pz*radius);
+
+ s += du;
+ }
+ } else {
+ for (int i = 0; i <= xdiv; i++) {
+ px = Math.cos(i*dtheta - Math.PI/2.0);
+ pz = Math.sin(i*dtheta - Math.PI/2.0);
+ gbuf.normal3d(px*sign, ynormal*sign, pz*sign);
+ if (texCoordYUp) {
+ gbuf.texCoord2d(s, 1.0 - t);
+ } else {
+ gbuf.texCoord2d(s, t);
+ }
+ gbuf.vertex3d(px*radius, bottom, pz*radius);
+ s += du;
+ }
+ }
+ gbuf.end();
+ return gbuf;
+ }
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Simple.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Simple.java
new file mode 100644
index 0000000..92020a9
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Simple.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+import org.jogamp.vecmath.Point3f;
+
+
+class Simple {
+
+ /**
+ * Handle a triangle or a quadrangle in a simple and efficient way. if the
+ * face is more complex than false is returned.
+ *
+ * warning: the correctness of this function depends upon the fact that
+ * `CleanPolyhedralFace' has not yet been executed; i.e., the
+ * vertex indices have not been changed since the execution of
+ * `CleanPolyhedron'! (otherwise, we would have to get the original
+ * indices via calls to `GetOriginal'...)
+ */
+ static boolean simpleFace(Triangulator triRef, int ind1) {
+ int ind0, ind2, ind3, ind4;
+ int i1, i2, i3, i0, i4;
+
+ Point3f pq, pr, nr;
+
+ double x, y, z;
+ int ori2, ori4;
+
+ ind0 = triRef.fetchPrevData(ind1);
+ i0 = triRef.fetchData(ind0);
+
+ if (ind0 == ind1) {
+ // this polygon has only one vertex! nothing to triangulate...
+ System.out.println("***** polygon with only one vertex?! *****\n");
+ return true;
+ }
+
+ ind2 = triRef.fetchNextData(ind1);
+ i2 = triRef.fetchData(ind2);
+ if (ind0 == ind2) {
+ // this polygon has only two vertices! nothing to triangulate...
+ System.out.println("***** polygon with only two vertices?! *****\n");
+ return true;
+ }
+
+ ind3 = triRef.fetchNextData(ind2);
+ i3 = triRef.fetchData(ind3);
+ if (ind0 == ind3) {
+ // this polygon is a triangle! let's triangulate it!
+ i1 = triRef.fetchData(ind1);
+ // triRef.storeTriangle(i1, i2, i3);
+ triRef.storeTriangle(ind1, ind2, ind3);
+ return true;
+ }
+
+ ind4 = triRef.fetchNextData(ind3);
+ i4 = triRef.fetchData(ind4);
+ if (ind0 == ind4) {
+ // this polygon is a quadrangle! not too hard to triangulate it...
+ // we project the corners of the quadrangle onto one of the coordinate
+ // planes
+ triRef.initPnts(5);
+ i1 = triRef.fetchData(ind1);
+
+ pq = new Point3f();
+ pr = new Point3f();
+ nr = new Point3f();
+ /*
+ System.out.println("ind0 " + ind0 + ", ind1 " + ind1 + ", ind2 " +
+ ind2 + ", ind3 " + ind3 + ", ind4 " + ind4);
+ System.out.println("i0 " + i0 +", i1 " + i1 + ", i2 " + i2 +
+ ", i3 " + i3 + ", i4 " + i4);
+
+ System.out.println("vert[i1] " + triRef.vertices[i1] +
+ "vert[i2] " + triRef.vertices[i2] +
+ "vert[i3] " + triRef.vertices[i3]);
+ */
+
+ Basic.vectorSub(triRef.vertices[i1], triRef.vertices[i2], pq);
+ Basic.vectorSub(triRef.vertices[i3], triRef.vertices[i2], pr);
+ Basic.vectorProduct(pq, pr, nr);
+
+ // System.out.println("pq " + pq + " pr " + pr + " nr " + nr);
+ x = Math.abs(nr.x);
+ y = Math.abs(nr.y);
+ z = Math.abs(nr.z);
+ if ((z >= x) && (z >= y)) {
+ // System.out.println("((z >= x) && (z >= y))");
+ triRef.points[1].x = triRef.vertices[i1].x;
+ triRef.points[1].y = triRef.vertices[i1].y;
+ triRef.points[2].x = triRef.vertices[i2].x;
+ triRef.points[2].y = triRef.vertices[i2].y;
+ triRef.points[3].x = triRef.vertices[i3].x;
+ triRef.points[3].y = triRef.vertices[i3].y;
+ triRef.points[4].x = triRef.vertices[i4].x;
+ triRef.points[4].y = triRef.vertices[i4].y;
+ }
+ else if ((x >= y) && (x >= z)) {
+ // System.out.println("((x >= y) && (x >= z))");
+ triRef.points[1].x = triRef.vertices[i1].z;
+ triRef.points[1].y = triRef.vertices[i1].y;
+ triRef.points[2].x = triRef.vertices[i2].z;
+ triRef.points[2].y = triRef.vertices[i2].y;
+ triRef.points[3].x = triRef.vertices[i3].z;
+ triRef.points[3].y = triRef.vertices[i3].y;
+ triRef.points[4].x = triRef.vertices[i4].z;
+ triRef.points[4].y = triRef.vertices[i4].y;
+ }
+ else {
+ triRef.points[1].x = triRef.vertices[i1].x;
+ triRef.points[1].y = triRef.vertices[i1].z;
+ triRef.points[2].x = triRef.vertices[i2].x;
+ triRef.points[2].y = triRef.vertices[i2].z;
+ triRef.points[3].x = triRef.vertices[i3].x;
+ triRef.points[3].y = triRef.vertices[i3].z;
+ triRef.points[4].x = triRef.vertices[i4].x;
+ triRef.points[4].y = triRef.vertices[i4].z;
+ }
+ triRef.numPoints = 5;
+
+ // find a valid diagonal
+ ori2 = Numerics.orientation(triRef, 1, 2, 3);
+ ori4 = Numerics.orientation(triRef, 1, 3, 4);
+
+ /*
+ for(int i=0; i<5; i++)
+ System.out.println("point " + i + ", " + triRef.points[i]);
+ System.out.println("ori2 : " + ori2 + " ori4 : " + ori4);
+ */
+
+ if (((ori2 > 0) && (ori4 > 0)) ||
+ ((ori2 < 0) && (ori4 < 0))) {
+
+ // i1, i3 is a valid diagonal;
+ //
+ // encode as a 2-triangle strip: the triangles are (2, 3, 1)
+ // and (1, 3, 4).
+
+ // triRef.storeTriangle(i1, i2, i3);
+ // triRef.storeTriangle(i1, i3, i4);
+ triRef.storeTriangle(ind1, ind2, ind3);
+ triRef.storeTriangle(ind1, ind3, ind4);
+ }
+ else {
+ // i2, i4 has to be a valid diagonal. (if this is no valid
+ // diagonal then the corners of the quad form a figure of eight;
+ // shall we apply any heuristics in order to guess which diagonal
+ // is more likely to be the better choice? alternatively, we could
+ // return false and subject it to the standard triangulation
+ // algorithm. well, let's see how this brute-force solution works.)
+
+ // encode as a 2-triangle strip: the triangles are (1, 2, 4)
+ // and (4, 2, 3).
+
+ // triRef.storeTriangle(i2, i3, i4);
+ // triRef.storeTriangle(i2, i4, i1);
+ triRef.storeTriangle(ind2, ind3, ind4);
+ triRef.storeTriangle(ind2, ind4, ind1);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Sphere.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Sphere.java
new file mode 100644
index 0000000..23bdf89
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Sphere.java
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry;
+
+import org.jogamp.java3d.Appearance;
+import org.jogamp.java3d.Node;
+import org.jogamp.java3d.NodeComponent;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.TexCoord2f;
+import org.jogamp.vecmath.Vector3f;
+
+/**
+ * Sphere is a geometry primitive created with a given radius and resolution.
+ * It is centered at the origin.
+ * getShape
.
+ *
+ * @see Sphere#getShape
+ */
+ public static final int BODY = 0;
+
+ static final int MID_REZ_DIV = 16;
+ float radius;
+ int divisions;
+
+ /**
+ * Constructs a Sphere of a given radius. Normals are generated
+ * by default, texture coordinates are not. The resolution defaults to
+ * 15 divisions along sphere's axes. Appearance defaults to white.
+ * @param radius Radius
+ */
+ public Sphere (float radius) {
+ this(radius, GENERATE_NORMALS, MID_REZ_DIV);
+ }
+
+ /**
+ * Constructs a default Sphere of radius of 1.0. Normals are generated
+ * by default, texture coordinates are not.
+ * Resolution defaults to 15 divisions. Appearance defaults to white.
+ */
+ public Sphere() {
+ this(1.0f, GENERATE_NORMALS, MID_REZ_DIV);
+ }
+
+ /**
+ * Constructs a Sphere of a given radius and appearance.
+ * Normals are generated by default, texture coordinates are not.
+ * @param radius Radius
+ * @param ap Appearance
+ */
+
+ public Sphere (float radius, Appearance ap) {
+ this(radius, GENERATE_NORMALS, MID_REZ_DIV, ap);
+ }
+
+ /**
+ * Constructs a Sphere of a given radius and appearance with
+ * additional parameters specified by the Primitive flags.
+ * @param radius Radius
+ * @param primflags
+ * @param ap appearance
+ */
+ public Sphere(float radius, int primflags, Appearance ap) {
+ this(radius, primflags, MID_REZ_DIV, ap);
+ }
+
+ /**
+ * Constructs a Sphere of a given radius and number of divisions
+ * with additional parameters specified by the Primitive flags.
+ * Appearance defaults to white.
+ * @param radius Radius
+ * @param divisions Divisions
+ * @param primflags Primflags
+ */
+ public Sphere(float radius, int primflags, int divisions) {
+ this(radius, primflags, divisions, null);
+ }
+
+
+ /**
+ * Obtains Sphere's shape node that contains the geometry.
+ * This allows users to modify the appearance or geometry.
+ * @param partId The part to return (must be BODY for Spheres)
+ * @return The Shape3D object associated with the partId. If an
+ * invalid partId is passed in, null is returned.
+ */
+ @Override
+ public Shape3D getShape(int partId) {
+ if (partId != BODY) return null;
+// return (Shape3D)((Group)getChild(0)).getChild(BODY);
+ return (Shape3D)getChild(BODY);
+ }
+
+ /** Obtains Sphere's shape node that contains the geometry.
+ */
+ public Shape3D getShape() {
+// return (Shape3D)((Group)getChild(0)).getChild(BODY);
+ return (Shape3D)getChild(BODY);
+ }
+
+ /** Sets appearance of the Sphere.
+ */
+ @Override
+ public void setAppearance(Appearance ap) {
+// ((Shape3D)((Group)getChild(0)).getChild(BODY)).setAppearance(ap);
+ ((Shape3D)getChild(BODY)).setAppearance(ap);
+ }
+
+ /**
+ * Gets the appearance of the specified part of the sphere.
+ *
+ * @param partId identifier for a given subpart of the sphere
+ *
+ * @return The appearance object associated with the partID. If an
+ * invalid partId is passed in, null is returned.
+ *
+ * @since Java 3D 1.2.1
+ */
+ @Override
+ public Appearance getAppearance(int partId) {
+ if (partId != BODY) return null;
+ return getShape(partId).getAppearance();
+ }
+
+
+ /**
+ * Constructs a customized Sphere of a given radius,
+ * number of divisions, and appearance, with additional parameters
+ * specified by the Primitive flags. The resolution is defined in
+ * terms of number of subdivisions along the sphere's axes. More
+ * divisions lead to more finely tesselated objects.
+ * cloneNode
should be overridden by any user subclassed
+ * objects. All subclasses must have their cloneNode
+ * method consist of the following lines:
+ *
+ * @param forceDuplicate when set to
+ * public Node cloneNode(boolean forceDuplicate) {
+ * UserSubClass usc = new UserSubClass();
+ * usc.duplicateNode(this, forceDuplicate);
+ * return usc;
+ * }
+ *
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.
+ *
+ * @see Node#cloneTree
+ * @see Node#duplicateNode
+ * @see NodeComponent#setDuplicateOnCloneTree
+ */
+ @Override
+ public Node cloneNode(boolean forceDuplicate) {
+ Sphere s = new Sphere(radius, flags, divisions, getAppearance());
+ s.duplicateNode(this, forceDuplicate);
+
+ return s;
+ }
+
+ /**
+ * 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.
+ * 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
.
+ *
+ * @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.
+ *
+ * @see Node#cloneTree
+ * @see Node#cloneNode
+ * @see NodeComponent#setDuplicateOnCloneTree
+ */
+ @Override
+ public void duplicateNode(Node originalNode, boolean forceDuplicate) {
+ super.duplicateNode(originalNode, forceDuplicate);
+ }
+
+ /**
+ * Returns the radius of the sphere
+ *
+ * @since Java 3D 1.2.1
+ */
+ public float getRadius() {
+ return radius;
+ }
+
+ /**
+ * Returns the number of divisions
+ *
+ * @since Java 3D 1.2.1
+ */
+ public int getDivisions() {
+ return divisions;
+ }
+
+ void buildQuadrant(GeomBuffer gbuf, double startDelta, double endDelta,
+ int sign, int nstep, int n, boolean upperSphere)
+ {
+
+ double ds, dt, theta, delta;
+ int i, j, index, i2;
+ double h, r, vx, vz;
+ Point3f pt;
+ Vector3f norm;
+ TexCoord2f texCoord;
+ double starth;
+ double t;
+ boolean leftToRight;
+
+
+ if (upperSphere) {
+ dt = Math.PI/(2*nstep);
+ theta = dt;
+ starth = 1;
+ leftToRight = (sign > 0);
+ } else {
+ dt = -Math.PI/(2*nstep);
+ theta = Math.PI + dt;
+ starth = -1;
+ leftToRight = (sign < 0);
+ }
+
+
+ for (i = 1; i <= nstep; i++) {
+ h = Math.cos(theta);
+ r = Math.sin(theta);
+ if (sign > 0) {
+ t = 1 - theta/Math.PI;
+ } else {
+ t = theta/Math.PI;
+ }
+
+ i2 = i << 1;
+ // subdivision decreases towards the pole
+ ds = (endDelta - startDelta) / i;
+
+ gbuf.begin(GeomBuffer.TRIANGLE_STRIP);
+
+ if (leftToRight) {
+ // Build triangle strips from left to right
+ delta = startDelta;
+
+ for (j=0; j < i; j++) {
+ vx = r*Math.cos(delta);
+ vz = r*Math.sin(delta);
+
+ gbuf.normal3d( vx*sign, h*sign, vz*sign );
+ gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t);
+ gbuf.vertex3d( vx*radius, h*radius, vz*radius );
+ if (i > 1) {
+ // get previous vertex from buffer
+ index = gbuf.currVertCnt - i2;
+ pt = gbuf.pts[index];
+ norm = gbuf.normals[index];
+ texCoord = gbuf.tcoords[index];
+ // connect with correspondent vertices from previous row
+ gbuf.normal3d(norm.x, norm.y, norm.z);
+ gbuf.texCoord2d(texCoord.x, texCoord.y);
+ gbuf.vertex3d(pt.x, pt.y, pt.z);
+ } else {
+ gbuf.normal3d(0, sign*starth, 0);
+ if (sign > 0) {
+ gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI),
+ 1.0 - (theta - dt)/Math.PI);
+ } else {
+ gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI),
+ (theta - dt)/Math.PI);
+ }
+ gbuf.vertex3d( 0, starth*radius, 0);
+
+ }
+ delta += ds;
+ }
+
+ // Put the last vertex in that row,
+ // for numerical accuracy we don't use delta
+ // compute from above.
+ delta = endDelta;
+ vx = r*Math.cos(delta);
+ vz = r*Math.sin(delta);
+ gbuf.normal3d( vx*sign, h*sign, vz*sign );
+ gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t);
+ gbuf.vertex3d( vx*radius, h*radius, vz*radius);
+ } else {
+ delta = endDelta;
+ // Build triangle strips from right to left
+ for (j=i; j > 0; j--) {
+ vx = r*Math.cos(delta);
+ vz = r*Math.sin(delta);
+
+ gbuf.normal3d( vx*sign, h*sign, vz*sign );
+ // Convert texture coordinate back to one
+ // set in previous version
+ gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t);
+ gbuf.vertex3d( vx*radius, h*radius, vz*radius );
+ if (i > 1) {
+ // get previous vertex from buffer
+ index = gbuf.currVertCnt - i2;
+ pt = gbuf.pts[index];
+ norm = gbuf.normals[index];
+ texCoord = gbuf.tcoords[index];
+ gbuf.normal3d(norm.x, norm.y, norm.z);
+ gbuf.texCoord2d(texCoord.x, texCoord.y);
+ gbuf.vertex3d(pt.x, pt.y, pt.z);
+ } else {
+ gbuf.normal3d(0, sign*starth, 0);
+ if (sign > 0) {
+ gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI),
+ 1.0 - (theta - dt)/Math.PI);
+ } else {
+ gbuf.texCoord2d(0.75 - (startDelta + endDelta)/(4*Math.PI),
+ (theta - dt)/Math.PI);
+ }
+ gbuf.vertex3d( 0, starth*radius, 0);
+
+ }
+ delta -= ds;
+ }
+
+ // Put the last vertex in that row,
+ // for numerical accuracy we don't use delta
+ // compute from above.
+ delta = startDelta;
+ vx = r*Math.cos(delta);
+ vz = r*Math.sin(delta);
+ gbuf.normal3d( vx*sign, h*sign, vz*sign );
+ gbuf.texCoord2d(0.75 - delta/(2*Math.PI), t);
+ gbuf.vertex3d( vx*radius, h*radius, vz*radius );
+
+ }
+
+ gbuf.end();
+
+ if (i < nstep) {
+ theta += dt;
+ } else { // take care of numerical imprecision
+ theta = Math.PI/2;
+ }
+ }
+
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Stripifier.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Stripifier.java
new file mode 100644
index 0000000..f6353e1
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Stripifier.java
@@ -0,0 +1,2529 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+import java.util.ArrayList;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+/**
+ * The Stripifier utility will change the primitive of the GeometryInfo
+ * object to Triangle Strips. The strips are made by analyzing the
+ * triangles in the original data and connecting them together.
+ * GeometryInfo gi = new GeometryInfo(TRIANGLE_ARRAY);
+ * gi.setCoordinates(coordinateData);
+ *
+ * NormalGenerator ng = new NormalGenerator();
+ * ng.generateNormals(gi);
+ *
+ * Stripifier st = new Stripifier()
+ * st.stripify(gi);
+ *
+ * Shape3D part = new Shape3D();
+ * part.setAppearance(appearance);
+ * part.setGeometry(gi.getGeometryArray());
+ *
+ */
+public class Stripifier {
+
+ final boolean DEBUG = false;
+ final boolean CHECK_ORIENT = false;
+
+ static final int EMPTY = -1;
+
+ boolean hasNormals = false;
+ boolean hasTextures = false;
+ int texSetCount = 0;
+ boolean hasColors = false;
+ boolean colorStrips = false;
+
+ StripifierStats stats;
+
+ int[] numNhbrs;
+
+ /**
+ * Indicates to the stripifier to collect statistics on the data
+ */
+ public static final int COLLECT_STATS = 0x01;
+
+ /**
+ * Creates the Stripifier object.
+ */
+ public Stripifier() {
+ }
+
+ /**
+ * Creates the Stripifier object.
+ * @param flags Flags
+ * @since Java 3D 1.2.1
+ */
+ public Stripifier(int flags) {
+ if ((flags & COLLECT_STATS) != 0) {
+ stats = new StripifierStats();
+ }
+ }
+
+ /**
+ * Converts the geometry contained in the GeometryInfo object into an
+ * array of triangle strips.
+ */
+ public void stripify(GeometryInfo gi) {
+ // System.out.println("stripify");
+ long time = System.currentTimeMillis();
+ // setup
+ gi.convertToIndexedTriangles();
+ gi.forgetOldPrim();
+
+ // write out the gi object
+ // System.out.println("write out the object");
+ // gi.writeObj();
+
+ Face[] faces = createFaceArray(gi);
+ Edge[] edges = createEdgeArray(faces);
+ buildAdjacencies(edges, faces);
+
+ // print out the adjacency information
+ if (DEBUG) {
+ for (int i = 0; i < faces.length; i++) {
+ faces[i].printVertices();
+ }
+ System.out.println("");
+ for (int i = 0; i < faces.length; i++) {
+ faces[i].printAdjacency();
+ }
+ System.out.println("");
+ }
+
+ Node[] faceNodes = new Node[faces.length];
+ // Node[] queue = hybridSearch(faces, faceNodes);
+ Node[] queue = dfSearch(faces, faceNodes);
+
+ // print out the queue
+ if (DEBUG) {
+ for (int i = 0; i < queue.length; i++) {
+ queue[i].print();
+ }
+ System.out.println("");
+ }
+
+ // int "pointers" for the numbers of strips and patches from
+ // hamiliton
+ int[] ns = new int[1];
+ int[] np = new int[1];
+ ArrayList hamiltons = hamilton(queue, ns, np);
+ int numStrips = ns[0];
+ int numPatches = np[0];
+
+ // print out the hamiltonians
+ if (DEBUG) {
+ for (int i = 0; i < hamiltons.size(); i++) {
+ System.out.println("Hamiltonian: " + i);
+ ArrayList list = (ArrayList)hamiltons.get(i);
+ for (int j = 0; j < list.size(); j++) {
+ Face face = (Face)list.get(j);
+ face.printVertices();
+ }
+ System.out.println("");
+ }
+ }
+
+ // now make strips out of the hamiltonians
+ ArrayList strips = stripe(hamiltons);
+
+ // print out the strips
+ if (DEBUG) {
+ for (int i = 0; i < strips.size(); i++) {
+ System.out.println("Strip: " + i);
+ Istream istream = (Istream)strips.get(i);
+ for (int j = 0; j < istream.length; j++) {
+ System.out.println("vertex: " + istream.istream[j].index);
+ }
+ System.out.println("");
+ }
+ }
+
+ // concatenate the strips
+ concatenate(strips, faces);
+
+ // print out the new strips
+ if (DEBUG) {
+ System.out.println("");
+ System.out.println("concatenated strips: (" +
+ (strips.size()) + ")");
+ System.out.println("");
+ for (int i = 0; i < strips.size(); i++) {
+ System.out.println("Strip: " + i);
+ Istream istream = (Istream)strips.get(i);
+ for (int j = 0; j < istream.length; j++) {
+ System.out.println("vertex: " + istream.istream[j].index);
+ }
+ System.out.println("");
+ }
+ }
+
+ // put the stripified data into the GeometryInfo object
+ putBackData(gi, strips);
+
+ // System.out.println("time: " + (System.currentTimeMillis()-time));
+ // System.out.println("");
+
+ // add to stats
+ if (stats != null) {
+ stats.updateInfo(System.currentTimeMillis()-time, strips,
+ faces.length);
+ }
+
+ // Stat.printInfo();
+
+ // print out strip count info
+ // System.out.println("numStrips = " + strips.size());
+ // System.out.println("stripCounts:");
+ // int avg = 0;
+ // for (int i = 0; i < strips.size(); i++) {
+ // System.out.print(((Istream)strips.get(i)).length + " ");
+ // avg += ((Istream)strips.get(i)).length;
+ // }
+ // System.out.println("Avg: " + ((double)avg/(double)strips.size()));
+ }
+
+ /**
+ * Prints out statistical information for the stripifier: the number of
+ * original triangles, the number of original vertices, the number of
+ * strips created, the number of vertices, the total number of triangles,
+ * the minimum strip length (in # of tris) the maximum strip length
+ * (in number of tris), the average strip length (in # of tris), the
+ * average number of vertices per triangle, the total time it took to
+ * stripify, and the strip length (how many strips of a given length.
+ * The data is cumulative over all the times the stripifier is called
+ * until the stats are printed, and then they are reset.
+ */
+ // public static void printStats() {
+ // // stats.toString();
+ // }
+
+ /**
+ * Returns the stripifier stats object.
+ * @exception IllegalStateException if the Stripfier has not
+ * been constructed
+ * with the COLLECT_STATS flag
+ * @since Java 3D 1.2.1
+ */
+ public StripifierStats getStripifierStats() {
+ if (stats == null) {
+ throw new IllegalStateException(J3dUtilsI18N.getString("Stripifier0"));
+ }
+ return stats;
+ }
+
+ /**
+ * Creates an array of faces from the geometry in the GeometryInfo object.
+ */
+ Face[] createFaceArray(GeometryInfo gi) {
+ int[] vertices = gi.getCoordinateIndices();
+ int[] normals = gi.getNormalIndices();
+
+ int[][] textures = null;
+ int[] t1 = null;
+ int[] t2 = null;
+ int[] t3 = null;
+ texSetCount = gi.getTexCoordSetCount();
+ if (texSetCount > 0) {
+ hasTextures = true;
+ textures = new int[texSetCount][];
+ for (int i = 0; i < texSetCount; i++) {
+ textures[i] = gi.getTextureCoordinateIndices(i);
+ }
+ t1 = new int[texSetCount];
+ t2 = new int[texSetCount];
+ t3 = new int[texSetCount];
+ } else hasTextures = false;
+
+ int[] colors = gi.getColorIndices();
+ Face[] faces = new Face[vertices.length/3];
+ int n1, n2, n3, c1, c2, c3;
+ Vertex v1, v2, v3;
+ int count = 0;
+ for (int i = 0; i < vertices.length;) {
+ if (normals != null) {
+ // System.out.println("hasNormals");
+ hasNormals = true;
+ n1 = normals[i];
+ n2 = normals[i+1];
+ n3 = normals[i+2];
+ }
+ else {
+ // System.out.println("doesn't have normals");
+ hasNormals = false;
+ n1 = EMPTY;
+ n2 = EMPTY;
+ n3 = EMPTY;
+ }
+ if (hasTextures) {
+ for (int j = 0; j < texSetCount; j++) {
+ t1[j] = textures[j][i];
+ t2[j] = textures[j][(i+1)];
+ t3[j] = textures[j][(i+2)];
+ }
+ }
+ if (colors != null) {
+ hasColors = true;
+ c1 = colors[i];
+ c2 = colors[i+1];
+ c3 = colors[i+2];
+ }
+ else {
+ hasColors = false;
+ c1 = EMPTY;
+ c2 = EMPTY;
+ c3 = EMPTY;
+ }
+ v1 = new Vertex(vertices[i], n1, texSetCount, t1, c1);
+ v2 = new Vertex(vertices[i+1], n2, texSetCount, t2, c2);
+ v3 = new Vertex(vertices[i+2], n3, texSetCount, t3, c3);
+ if (!v1.equals(v2) && !v2.equals(v3) && !v3.equals(v1)) {
+ faces[count] = new Face(count, v1, v2, v3);
+ count++;
+ }
+ i+=3;
+ }
+
+ if (faces.length > count) {
+ Face[] temp = faces;
+ faces = new Face[count];
+ System.arraycopy(temp, 0, faces, 0, count);
+ }
+ return faces;
+ }
+
+ /**
+ * Creates an array of edges from the Face array.
+ */
+ Edge[] createEdgeArray(Face[] faces) {
+ Edge[] edges = new Edge[faces.length*3];
+ Face face;
+ for (int i = 0; i < faces.length; i++) {
+ face = faces[i];
+ edges[i*3] = new Edge(face.verts[0], face.verts[1], face.key);
+ edges[i*3+1] = new Edge(face.verts[1], face.verts[2], face.key);
+ edges[i*3+2] = new Edge(face.verts[2], face.verts[0], face.key);
+ }
+ return edges;
+ }
+
+ /**
+ * Builds the adjacency graph by finding the neighbors of the edges
+ */
+ void buildAdjacencies(Edge[] edges, Face[] faces) {
+ // sortEdges(edges);
+ quickSortEdges(edges, 0, edges.length-1);
+ // int i = 1;
+
+ // set up the edge list of each face
+ Edge edge;
+ Face face;
+ Vertex[] verts;
+ boolean flag;
+ int k;
+ for (int i = 0; i < edges.length; i++) {
+ // edges are kept in order s.t. the ith edge is the opposite
+ // edge of the ith vertex
+ edge = edges[i];
+ face = faces[edge.face];
+ verts = face.verts;
+
+ flag = true;
+ if ((!verts[0].equals(edge.v1)) && (!verts[0].equals(edge.v2))) {
+ face.edges[0] = edge;
+ face.numNhbrs--;
+ flag = false;
+ }
+ else if ((!verts[1].equals(edge.v1)) &&
+ (!verts[1].equals(edge.v2))) {
+ face.edges[1] = edge;
+ face.numNhbrs--;
+ flag = false;
+ }
+ else if ((!verts[2].equals(edge.v1)) &&
+ (!verts[2].equals(edge.v2))) {
+ face.edges[2] = edge;
+ face.numNhbrs--;
+ flag = false;
+ }
+ else {
+ if (DEBUG) System.out.println("error!!! Stripifier.buildAdj");
+ }
+
+ // handle degenerencies
+ if (flag) {
+ Vertex i1;
+ // triangle degenerated to a point
+ if ((edge.v1).equals(edge.v2)) {
+ face.edges[--face.numNhbrs] = edge;
+ }
+ // triangle degenerated to an edge
+ else {
+ if (verts[0].equals(verts[1])) {
+ i1 = verts[1];
+ }
+ else {
+ i1 = verts[2];
+ }
+ if (verts[0].equals(i1) && face.edges[0] == null) {
+ face.edges[0] = edge;
+ face.numNhbrs--;
+ }
+ else if (verts[1].equals(i1) && face.edges[1] == null) {
+ face.edges[1] = edge;
+ face.numNhbrs--;
+ }
+ else {
+ face.edges[2] = edge;
+ face.numNhbrs--;
+ }
+ }
+ }
+ }
+
+ // build the adjacency information by pairing up every two triangles
+ // that share the same edge
+ int i = 0; int j = 0;
+ int j1, j2;
+ while (i < (edges.length-1)) {
+ j = i+1;
+ if (edges[i].equals(edges[j])) {
+ // determine the orientations of the common edge in the two
+ // adjacent triangles. Only set them to be adjacent if they
+ // are opposite
+ j1 = edges[i].face;
+ j2 = edges[j].face;
+ if (j1 != j2) { // set up the two faces as neighbors
+ edge = edges[i];
+ face = faces[j1];
+ k = face.getEdgeIndex(edge);
+ if ((edge.v1.equals(face.verts[(k+1)%3])) &&
+ (edge.v2.equals(face.verts[(k+2)%3]))) {
+ flag = false;
+ }
+ else flag = true;
+
+ edge = edges[j];
+ face = faces[j2];
+ k = face.getEdgeIndex(edge);
+ if ((edge.v1.equals(face.verts[(k+1)%3])) &&
+ (edge.v2.equals(face.verts[(k+2)%3]))) {
+ flag = flag;
+ }
+ else flag = (!flag);
+
+ if (flag) {
+ edges[i].face = j2;
+ edges[j].face = j1;
+ (faces[j1].numNhbrs)++;
+ (faces[j2].numNhbrs)++;
+ j++;
+ }
+ else edges[i].face = EMPTY;
+ }
+ else edges[i].face = EMPTY;
+ }
+ else edges[i].face = EMPTY;
+ i=j;
+ }
+ if (i <= (edges.length-1)) edges[i].face = EMPTY;
+
+ // check, for each face, if it is duplicated. For a face that
+ // neighbors its duplicate in the adjacency graph, it's possible
+ // that two or more of its neighbors are the same (the duplicate).
+ // This will be corrected to avoid introducing redundant faces
+ // later on
+
+ for (i = 0; i < faces.length; i++) {
+ face = faces[i];
+ if (face.numNhbrs == 3) {
+ if ((j1 = face.edges[1].face) == face.edges[0].face) {
+ face.edges[1].face = EMPTY;
+ face.numNhbrs--;
+ faces[j1].counterEdgeDel(face.edges[1]);
+ }
+ if ((j2 = face.edges[2].face) == face.edges[0].face) {
+ face.edges[2].face = EMPTY;
+ face.numNhbrs--;
+ faces[j2].counterEdgeDel(face.edges[2]);
+ }
+ if ((face.edges[1].face != EMPTY) && (j1 == j2)) {
+ face.edges[2].face = EMPTY;
+ face.numNhbrs--;
+ faces[j1].counterEdgeDel(face.edges[2]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Sorts the edges using BubbleSort
+ */
+ void sortEdges(Edge[] edges) {
+ int i = edges.length;
+ boolean sorted = false;
+ Edge temp = null;
+ while ((i > 1) && !sorted) {
+ sorted = true;
+ for (int j = 1; j < i; j++) {
+ if (edges[j].lessThan(edges[j-1])) {
+ temp = edges[j-1];
+ edges[j-1] = edges[j];
+ edges[j] = temp;
+ sorted = false;
+ }
+ }
+ i--;
+ }
+ }
+
+ /**
+ * uses quicksort to sort the edges
+ */
+ void quickSortEdges(Edge[] edges, int l, int r) {
+ if (edges.length > 0) {
+ int i = l;
+ int j = r;
+ Edge k = edges[(l+r) / 2];
+
+ do {
+ while (edges[i].lessThan(k)) i++;
+ while (k.lessThan(edges[j])) j--;
+ if (i <= j) {
+ Edge tmp = edges[i];
+ edges[i] = edges[j];
+ edges[j] = tmp;
+ i++;
+ j--;
+ }
+ } while (i <= j);
+
+ if (l < j) quickSortEdges(edges, l, j);
+ if (l < r) quickSortEdges(edges, i, r);
+ }
+ }
+
+ /**
+ * Takes a list of faces as input and performs a hybrid search, a
+ * variated depth first search that returns to the highest level node
+ * not yet fully explored. Returns an array of pointers to the faces
+ * found in order from the search. The faceNodes parameter is an
+ * array of the Nodes created for the faces.
+ */
+ Node[] hybridSearch(Face[] faces, Node[] faceNodes) {
+
+ int numFaces = faces.length;
+ int i = 0, j = 0, k = 0, ind = 0;
+
+ // keep # of faces with certain # of neighbors
+ int[] count = {0, 0, 0, 0};
+
+ // faces sorted by number of neighbors
+ int[] index = new int[numFaces];
+ // the index of a certain face in the sorted array
+ int[] rindex = new int[numFaces];
+
+ // Control list pop up operation
+ boolean popFlag = false;
+
+ // queue of pointers to faces found in search
+ Node[] queue = new Node[numFaces];
+ // root of depth first tree
+ Node source;
+ // for the next node
+ Node nnode;
+ // a face
+ Face face;
+ // starting position for insertion into the list
+ int start = 0;
+ // list for search
+ SortedList dlist;
+
+ // count how many faces have a certain # of neighbors and
+ // create a Node for each face
+ for (i = 0; i < numFaces; i++) {
+ j = faces[i].numNhbrs;
+ count[j]++;
+ faceNodes[i] = new Node(faces[i]);
+ }
+
+ // to help with sorting
+ for (i = 1; i < 4; i++) {
+ count[i] += count[i-1];
+ }
+
+ // decreasing i to make sorting stable
+ for (i = numFaces - 1; i >= 0; i--) {
+ j = faces[i].numNhbrs;
+ count[j]--;
+ index[count[j]] = i;
+ rindex[i] = count[j];
+ }
+
+ // start the hybrid search
+ for (i = 0; i < numFaces; i++) {
+ if (index[i] != EMPTY) {
+ dlist = new SortedList();
+ source = faceNodes[index[i]];
+ source.setRoot();
+ queue[ind] = source;
+ ind++;
+ index[i] = EMPTY;
+
+ while (source != null) {
+ nnode = null;
+ // use the first eligible for continuing search
+ face = source.face;
+ for (j = 0; j < 3; j++) {
+ k = face.getNeighbor(j);
+ if ((k != EMPTY) &&
+ (faceNodes[k].notAccessed())) {
+ nnode = faceNodes[k];
+ break;
+ }
+ }
+
+ if (nnode != null) {
+ // insert the new node
+ nnode.insert(source);
+ if (!popFlag) {
+ start = dlist.sortedInsert(source, start);
+ }
+ else popFlag = false;
+ source = nnode;
+ queue[ind] = source;
+ ind++;
+ index[rindex[k]] = EMPTY;
+ }
+ else {
+ source.processed();
+ source = dlist.pop();
+ popFlag = true;
+ start = 0;
+ }
+ } // while -- does popFlag need to be set to false here?
+ }
+ }
+ return queue;
+ }
+
+ Node[] dfSearch(Face[] faces, Node[] faceNodes) {
+ int numFaces = faces.length;
+ int i = 0, j = 0, k = 0, ind = 0;
+
+ // keep certain # of faces with certain # of neighbors
+ int[] count = {0, 0, 0, 0};
+
+ // faces sorted by # of neighbors
+ int[] index = new int[numFaces];
+ // index of a certain face in the sorted array
+ int[] rindex = new int[numFaces];
+
+ // queue of pointers to faces found in the search
+ Node[] queue = new Node[numFaces];
+ // root of the depth first tree
+ Node source;
+ // the current node
+ Node node;
+ // for the next Node
+ Node nnode;
+ // a face
+ Face face;
+
+ // count how many faces have a certain # of neighbors and create
+ // a Node for each face
+ for (i = 0; i < numFaces; i++) {
+ j = faces[i].numNhbrs;
+ count[j]++;
+ faceNodes[i] = new Node(faces[i]);
+ }
+
+ // to help with sorting
+ for (i = 1; i < 4; i++) count[i] += count[i-1];
+
+ // dec i to make sorting stable
+ for (i = numFaces-1; i >= 0; i--) {
+ j = faces[i].numNhbrs;
+ count[j]--;
+ index[count[j]] = i;
+ rindex[i] = count[j];
+ }
+
+ setNumNhbrs(faces);
+ // start the dfs
+ for (i = 0; i < numFaces; i++) {
+ if (index[i] != EMPTY) {
+ source = faceNodes[index[i]];
+ source.setRoot();
+ queue[ind] = source;
+ ind++;
+ index[i] = EMPTY;
+ node = source;
+
+ do {
+ // if source has been done, stop
+ if ((node == source) && (node.right != null)) break;
+
+ nnode = null;
+ face = node.face;
+
+ // for (j = 0; j < 3; j++) {
+ // if (((k = face.getNeighbor(j)) != EMPTY) &&
+ // (faceNodes[k].notAccessed())) {
+ // nnode = faceNodes[k];
+ // break;
+ // }
+ // }
+
+ k = findNext(node, faceNodes, faces);
+ if (k != EMPTY) nnode = faceNodes[k];
+ if (nnode != null) updateNumNhbrs(nnode);
+
+ if (nnode != null) {
+ // insert new node
+ nnode.insert(node);
+ node = nnode;
+ queue[ind] = node;
+ ind++;
+ index[rindex[k]] = EMPTY;
+ }
+ else {
+ node.processed();
+ node = node.parent;
+ }
+ } while (node != source.parent);
+ }
+ }
+ freeNhbrTable();
+ return queue;
+ }
+
+ int findNext(Node node, Node[] faceNodes, Face[] faces) {
+ Face face = node.face;
+ // this face has no neighbors so return
+ if (face.numNhbrs == 0) return EMPTY;
+
+ int i, j, count;
+ int[] n = new int[3]; // num neighbors of neighboring face
+ int[] ind = {-1, -1, -1}; // neighboring faces
+
+ // find the number of neighbors for each neighbor
+ count = 0;
+ for (i = 0; i < 3; i++) {
+ if (((j = face.getNeighbor(i)) != EMPTY) &&
+ (faceNodes[j].notAccessed())) {
+ ind[count] = j;
+ n[count] = numNhbrs[j];
+ count++;
+ }
+ }
+
+ // this face has no not accessed faces
+ if (count == 0) return EMPTY;
+
+ // this face has only one neighbor
+ if (count == 1) return ind[0];
+
+ if (count == 2) {
+ // if the number of neighbors are the same, try reseting
+ if ((n[0] == n[1]) && (n[0] != 0)) {
+ n[0] = resetNhbr(ind[0], faces, faceNodes);
+ n[1] = resetNhbr(ind[1], faces, faceNodes);
+ }
+ // if one neighbor has fewer neighbors, return that neighbor
+ if (n[0] < n[1]) return ind[0];
+ if (n[1] < n[0]) return ind[1];
+ // neighbors tie. pick the sequential one
+ Node pnode, ppnode;
+ Face pface, ppface;
+ if ((pnode = node.parent) != null) {
+ pface = pnode.face;
+ i = pface.findSharedEdge(face.key);
+ if ((ppnode = pnode.parent) != null) {
+ ppface = ppnode.face;
+ if (pface.getNeighbor((i+1)%3) == ppface.key) {
+ j = pface.verts[(i+2)%3].index;
+ }
+ else {
+ j = pface.verts[(i+1)%3].index;
+ }
+ }
+ else {
+ j = pface.verts[(i+1)%3].index;
+ }
+ i = face.findSharedEdge(ind[0]);
+ if (face.verts[i].index == j) return ind[0];
+ else return ind[1];
+ }
+ else return ind[0];
+ }
+ // three neighbors
+ else {
+ if ((n[0] < n[1]) && (n[0] < n[2])) return ind[0];
+ else if ((n[1] < n[0]) && (n[1] < n[2])) return ind[1];
+ else if ((n[2] < n[0]) && (n[2] < n[1])) return ind[2];
+ else if ((n[0] == n[1]) && (n[0] < n[2])) {
+ if (n[0] != 0) {
+ n[0] = resetNhbr(ind[0], faces, faceNodes);
+ n[1] = resetNhbr(ind[1], faces, faceNodes);
+ }
+ if (n[0] <= n[1]) return ind[0];
+ else return ind[1];
+ }
+ else if ((n[1] == n[2]) && n[1] < n[0]) {
+ if (n[1] != 0) {
+ n[1] = resetNhbr(ind[1], faces, faceNodes);
+ n[2] = resetNhbr(ind[2], faces, faceNodes);
+ }
+ if (n[1] <= n[2]) return ind[1];
+ else return ind[2];
+ }
+ else if ((n[2] == n[0]) && (n[2] < n[1])) {
+ if (n[0] != 0) {
+ n[0] = resetNhbr(ind[0], faces, faceNodes);
+ n[2] = resetNhbr(ind[2], faces, faceNodes);
+ }
+ if (n[0] <= n[2]) return ind[0];
+ else return ind[2];
+ }
+ else {
+ if (n[0] != 0) {
+ n[0] = resetNhbr(ind[0], faces, faceNodes);
+ n[1] = resetNhbr(ind[1], faces, faceNodes);
+ n[2] = resetNhbr(ind[2], faces, faceNodes);
+ }
+ if ((n[0] <= n[1]) && (n[0] <= n[2])) return ind[0];
+ else if (n[1] <= n[2]) return ind[1];
+ else return ind[2];
+ }
+ }
+ }
+
+ void setNumNhbrs(Face[] faces) {
+ int numFaces = faces.length;
+ numNhbrs = new int[numFaces];
+ for (int i = 0; i < numFaces; i++) {
+ numNhbrs[i] = faces[i].numNhbrs;
+ }
+ }
+
+ void freeNhbrTable() {
+ numNhbrs = null;
+ }
+
+ void updateNumNhbrs(Node node) {
+ Face face = node.face;
+ int i;
+ if ((i = face.getNeighbor(0)) != EMPTY) numNhbrs[i]--;
+ if ((i = face.getNeighbor(1)) != EMPTY) numNhbrs[i]--;
+ if ((i = face.getNeighbor(2)) != EMPTY) numNhbrs[i]--;
+ }
+
+ int resetNhbr(int y, Face[] faces, Node[] faceNodes) {
+ int x = EMPTY;
+ Face nface = faces[y];
+ int i;
+ for (int j = 0; j < 3; j++) {
+ if (((i = nface.getNeighbor(j)) != EMPTY) &&
+ (faceNodes[i].notAccessed())) {
+ if ((x == EMPTY) || (x > numNhbrs[i])) x = numNhbrs[i];
+ }
+ }
+ return x;
+ }
+
+ /**
+ * generates hamiltonian strips from the derived binary spanning tree
+ * using the path peeling algorithm to peel off any node wiht double
+ * children in a bottom up fashion. Returns a Vector of strips. Also
+ * return the number of strips and patches in the numStrips and
+ * numPatches "pointers"
+ */
+ ArrayList hamilton(Node[] sTree, int[] numStrips, int[] numPatches) {
+ // the number of nodes in the tree
+ int numNodes = sTree.length;
+ // number of strips
+ int ns = 0;
+ // number of patches
+ int np = 0;
+ // some tree node variables
+ Node node, pnode, cnode;
+ // the Vector of strips
+ ArrayList strips = new ArrayList();
+ // the current strip
+ ArrayList currStrip;
+
+ // the tree nodes are visited in such a bottom-up fashion that
+ // any node is visited prior to its parent
+ for (int i = numNodes - 1; i >= 0; i--) {
+ cnode = sTree[i];
+
+ // if cnode is the root of a tree create a strip
+ if (cnode.isRoot()) {
+ // each patch is a single tree
+ np++;
+ // create a new strip
+ currStrip = new ArrayList();
+ // insert the current node into the list
+ currStrip.add(0, cnode.face);
+
+ // add the left "wing" of the parent node to the strip
+ node = cnode.left;
+ while (node != null) {
+ currStrip.add(0, node.face);
+ node = node.left;
+ }
+
+ // add the right "wing" of the parent node to the strip
+ node = cnode.right;
+ while (node != null) {
+ currStrip.add(currStrip.size(), node.face);
+ node = node.left;
+ }
+
+ // increase the number of strips
+ ns++;
+ // add the strip to the Vector
+ strips.add(currStrip);
+ }
+
+ // if the number of children of this node is 2, create a strip
+ else if (cnode.numChildren == 2) {
+ // if the root has a single child with double children, it
+ // could be left over as a singleton. However, the following
+ // rearrangement reduces the chances
+ pnode = cnode.parent;
+ if (pnode.isRoot() && (pnode.numChildren == 1)) {
+ pnode = cnode.right;
+ if (pnode.left != null) cnode = pnode;
+ else cnode = cnode.left;
+ }
+
+ // handle non-root case
+
+ // remove the node
+ cnode.remove();
+
+ // create a new strip
+ currStrip = new ArrayList();
+ // insert the current node into the list
+ currStrip.add(0, cnode.face);
+
+ // add the left "wing" of cnode to the list
+ node = cnode.left;
+ while (node != null) {
+ currStrip.add(0, node.face);
+ node = node.left;
+ }
+
+ // add the right "wing" of cnode to the list
+ node = cnode.right;
+ while (node != null) {
+ currStrip.add(currStrip.size(), node.face);
+ node = node.left;
+ }
+
+ // increase the number of strips
+ ns++;
+ // add the strip to the Vector
+ strips.add(currStrip);
+ }
+ }
+
+ // put the ns and np in the "pointers to return
+ numStrips[0] = ns;
+ numPatches[0] = np;
+
+ // return the strips
+ return strips;
+ }
+
+ /**
+ * creates the triangle strips
+ */
+ ArrayList stripe(ArrayList strips) {
+ int numStrips = strips.size(); // the number of strips
+ int count; // where we are in the hamiltonian
+ Face face; // the face we are adding to the stream
+ Face prev; // the previous face added to the stream
+ boolean done; // whether we are done with the current strip
+ boolean cont; // whether we should continue the current stream
+ ArrayList currStrip; // the current hamiltonian
+ Istream currStream; // the stream we are building
+ ArrayList istreams = new ArrayList(); // the istreams to return
+ boolean ccw = true;; // counter-clockwise
+ int share; // the shared edge
+ Vertex[] buf = new Vertex[4]; // a vertex array to start the stream
+
+ // create streams for each hamiltonian
+ for (int i = 0; i < numStrips; i++) {
+ currStrip = (ArrayList)strips.get(i);
+ count = 0;
+ done = false;
+ face = getNextFace(currStrip, count++);
+
+ // while we are not done with the current hamiltonian
+ while (!done) {
+ cont = true;
+
+ // if the current face is the only one left in the current
+ // hamiltonian
+ if (stripDone(currStrip, count)) {
+ // create a new istream with the current face
+ currStream = new Istream(face.verts, 3, false);
+ // set the head of the strip to this face
+ currStream.head = face.key;
+ done = true;
+ // since we are done with the strip, set the tail to this
+ // face
+ currStream.tail = face.key;
+ }
+
+ else {
+ prev = face;
+ face = getNextFace(currStrip, count++);
+
+ // put the prev vertices in the correct order
+ // to add the next tri on
+ share = prev.findSharedEdge(face.key);
+ buf[0] = prev.verts[share];
+ buf[1] = prev.verts[(share+1)%3];
+ buf[2] = prev.verts[(share+2)%3];
+
+ // find the fourth vertex
+ if (CHECK_ORIENT) {
+ // check for clockwise orientation
+ if (checkOrientCWSeq(buf[2], buf[1], face)) {
+ share = face.findSharedEdge(prev.key);
+ buf[3] = face.verts[share];
+ currStream = new Istream(buf, 4, false);
+ // set the head of this strip to the prev face
+ currStream.head = prev.key;
+ // if this was the last tri in the strip, then
+ // we are done
+ if (stripDone(currStrip, count)) {
+ done = true;
+ // set the tail for the strip to current face
+ currStream.tail = face.key;
+ }
+ }
+ else {
+ cont = false;
+ currStream = new Istream(buf, 3, false);
+ // set the head to the prev face
+ currStream.head = prev.key;
+ // since we are not continuing, set
+ // the tail to prev also
+ currStream.tail = prev.key;
+ }
+
+ // orientation starts counter-clockwise for 3rd face
+ ccw = true;
+ }
+ else {
+ share = face.findSharedEdge(prev.key);
+ buf[3] = face.verts[share];
+ currStream = new Istream(buf, 4, false);
+ // set the head of this strip to the prev face
+ currStream.head = prev.key;
+ // if this was the last tri in the strip, then
+ // we are done
+ if (stripDone(currStrip, count)) {
+ done = true;
+ // set the tail for the strip to current face
+ currStream.tail = face.key;
+ }
+ }
+
+ // while continue and the strip isn't finished
+ // add more faces to the stream
+ while (cont && !stripDone(currStrip, count)) {
+ prev = face;
+ face = getNextFace(currStrip, count++);
+ share = face.findSharedEdge(prev.key);
+
+ // if we can add the face without adding any
+ // zero area triangles
+ if (seq(currStream, face, share)) {
+ if (CHECK_ORIENT) {
+ // if we can add the next face with the correct
+ // orientation
+ if (orientSeq(ccw, currStream, face)) {
+ // append the vertex opposite the
+ //shared edge
+ currStream.append(face.verts[share]);
+ // next face must have opposite orientation
+ ccw = (!ccw);
+ // if this was the last tri in the
+ //strip, then we are done
+ if (stripDone(currStrip, count)) {
+ done = true;
+ // since we are done with this strip,
+ // set the tail to the current face
+ currStream.tail = face.key;
+ }
+ }
+ // if we cannot add the face with the correct
+ // orientation, do not continue with this
+ // stream
+ else {
+ cont = false;
+ // since we cannot continue with this strip
+ // set the tail to prev
+ currStream.tail = prev.key;
+ }
+ }
+ else {
+ // append the vertex opposite the
+ //shared edge
+ currStream.append(face.verts[share]);
+ // if this was the last tri in the
+ //strip, then we are done
+ if (stripDone(currStrip, count)) {
+ done = true;
+ // since we are done with this strip,
+ // set the tail to the current face
+ currStream.tail = face.key;
+ }
+ }
+ }
+
+ // need zero area tris to add continue the strip
+ else {
+ if (CHECK_ORIENT) {
+ // check the orientation for adding a zero
+ // area tri and this face
+ if (orientZAT(ccw, currStream, face)) {
+ // swap the end of the current stream to
+ // add a zero area triangle
+ currStream.swapEnd();
+ // append the vertex opposite the
+ // shared edge
+ currStream.append(face.verts[share]);
+ // if this was the last tri in the
+ // strip then we are done
+ if (stripDone(currStrip, count)) {
+ done = true;
+ // set the tail because we are done
+ currStream.tail = face.key;
+ }
+ }
+ // if we cannot add the face with the correct
+ // orientation, do not continue with this
+ // stream
+ else {
+ cont = false;
+ // since we cannot continue with this face,
+ // set the tail to the prev face
+ currStream.tail = prev.key;
+ }
+ }
+ else {
+ // swap the end of the current stream to
+ // add a zero area triangle
+ currStream.swapEnd();
+ // append the vertex opposite the
+ // shared edge
+ currStream.append(face.verts[share]);
+ // if this was the last tri in the
+ // strip then we are done
+ if (stripDone(currStrip, count)) {
+ done = true;
+ // set the tail because we are done
+ currStream.tail = face.key;
+ }
+ }
+ }
+ } // while (cont && !stripDone)
+ } // else
+
+ // add the current strip to the strips to be returned
+ istreams.add(currStream);
+ } // while !done
+ } // for each hamiltonian
+ return istreams;
+ } // stripe
+
+ boolean stripDone(ArrayList strip, int count) {
+ if (count < strip.size()) {
+ return false;
+ }
+ else return true;
+ }
+
+ boolean seq(Istream stream, Face face, int share) {
+ int length = stream.length;
+ Vertex v1 = face.edges[share].v1;
+ Vertex v2 = face.edges[share].v2;
+ Vertex last = stream.istream[length-1];
+ Vertex prev = stream.istream[length-2];
+ if (((v1.equals(prev)) && (v2.equals(last))) ||
+ ((v1.equals(last)) && (v2.equals(prev)))) {
+ return true;
+ }
+ else return false;
+ }
+
+ boolean orientSeq(boolean ccw, Istream stream, Face face) {
+ int length = stream.length;
+ Vertex last = stream.istream[length-1];
+ Vertex prev = stream.istream[length-2];
+ if ((ccw && checkOrientCCWSeq(last, prev, face)) ||
+ ((!ccw) && checkOrientCWSeq(last, prev, face))) {
+ return true;
+ }
+ else return false;
+ }
+
+ boolean orientZAT(boolean ccw, Istream stream, Face face) {
+ int length = stream.length;
+ Vertex last = stream.istream[length-1];
+ Vertex swap = stream.istream[length-3];
+ if ((ccw && checkOrientCWSeq(last, swap, face)) ||
+ ((!ccw) && checkOrientCCWSeq(last, swap, face))) {
+ return true;
+ }
+ else return false;
+ }
+
+ boolean checkOrientCWSeq(Vertex last, Vertex prev, Face face) {
+ System.out.println("checkOrientCWSeq");
+ System.out.println("last = " + last.index);
+ System.out.println("prev = " + prev.index);
+ System.out.print("face = ");
+ face.printVertices();
+ if (last.equals(face.verts[0])) {
+ if (!prev.equals(face.verts[1])) {
+ if (DEBUG) System.out.println("ORIENTATION PROBLEM!");
+ return false;
+ }
+ }
+ else if (last.equals(face.verts[1])) {
+ if (!prev.equals(face.verts[2])) {
+ if (DEBUG) System.out.println("ORIENTATION PROBLEM!");
+ return false;
+ }
+ }
+ else if (last.equals(face.verts[2])) {
+ if (!prev.equals(face.verts[0])) {
+ if (DEBUG) System.out.println("ORIENTATION PROBLEM!");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ boolean checkOrientCCWSeq(Vertex last, Vertex prev, Face face) {
+ System.out.println("checkOrientCCWSeq");
+ System.out.println("last = " + last.index);
+ System.out.println("prev = " + prev.index);
+ System.out.print("face = ");
+ face.printVertices();
+ if (prev.equals(face.verts[0])) {
+ if (!last.equals(face.verts[1])) {
+ System.out.println("ORIENTATION PROBLEM!");
+ return false;
+ }
+ }
+ else if (prev.equals(face.verts[1])) {
+ if (!last.equals(face.verts[2])) {
+ System.out.println("ORIENTATION PROBLEM!");
+ return false;
+ }
+ }
+ else if (prev.equals(face.verts[2])) {
+ if (!last.equals(face.verts[0])) {
+ System.out.println("ORIENTATION PROBLEM!");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ Face getNextFace(ArrayList currStrip, int index) {
+ if (currStrip.size() > index) return (Face)currStrip.get(index);
+ else return null;
+ }
+
+ /**
+ * joins tristrips if their end triangles neighbor each other. The
+ * priority is performed in three stages: strips are concatenated to
+ * save 2, 1, or no vertices
+ */
+ void concatenate(ArrayList strips, Face[] faces) {
+ int numFaces = faces.length;
+ int[] faceTable = new int[numFaces];
+ Istream strm;
+
+ // initialize the face table to empty
+ for (int i = 0; i < numFaces; i++) {
+ faceTable[i] = EMPTY;
+ }
+
+ // set up the faceTable so that a face index relates to a strip
+ // that owns the face as one of its end faces
+ for (int i = 0; i < strips.size(); i++) {
+ strm = (Istream)strips.get(i);
+ faceTable[strm.head] = i;
+ faceTable[strm.tail] = i;
+ }
+
+ if (DEBUG) {
+ System.out.println("");
+ System.out.println("faceTable:");
+ for (int i = 0; i < faceTable.length; i++) {
+ System.out.println(faceTable[i]);
+ }
+ System.out.println("");
+ }
+
+ reduceCostByTwo(strips, faces, faceTable);
+ reduceCostByOne(strips, faces, faceTable);
+ reduceCostByZero(strips, faces, faceTable);
+ }
+
+ /**
+ * find all the links that reduce the cost by 2
+ */
+ void reduceCostByTwo(ArrayList strips, Face[] faces, int[] faceTable) {
+ // System.out.println("reduceCostByTwo");
+ // number of faces in the face array
+ int numFaces = faces.length;
+ // possible adjacent strips
+ int id, id1, id2;
+ // Istreams
+ Istream strm, strm1;
+ // the length of the Istrem
+ int len, len1;
+ // vertex sequences for tristrips
+ Vertex[] seq, seq1;
+ // a face
+ Face face;
+ // the list of vertices for the face
+ Vertex[] verts;
+ // used to syncronize the orientation
+ boolean sync, sync1;
+ // a swap variable
+ Vertex swap;
+
+ for (int i = 0; i < numFaces; i++) {
+ id = faceTable[i];
+ if (id != EMPTY) {
+ sync = false; sync1 = false;
+ strm = (Istream)strips.get(id);
+ len = strm.length;
+ seq = strm.istream;
+ face = faces[i];
+ verts = face.verts;
+
+ // sequential strips
+ if (!strm.fan) {
+
+ // a singleton strip
+ if (len == 3) {
+
+ // check all three neighbors
+ for (int j = 0; j < 3; j++) {
+ int k = face.getNeighbor(j);
+ if ((k != EMPTY) &&
+ ((id1 = faceTable[k]) != EMPTY) &&
+ (id1 != id)) {
+ // reassign the sequence
+ seq[0] = verts[j];
+ seq[1] = verts[(j+1)%3];
+ seq[2] = verts[(j+2)%3];
+
+ // the neighboring stream
+ strm1 = (Istream)strips.get(id1);
+ len1 = strm1.length;
+ if (k != strm1.head) {
+ strm1.invert();
+ // if the length is odd set sync1 to true
+ if ((len1 % 2) != 0) sync1 = true;
+ }
+ seq1 = strm1.istream;
+
+ // append a singleton strip
+ if (len1 == 3) {
+ // System.out.println("reduce2");
+ int m = faces[k].findSharedEdge(i);
+ strm.append(faces[k].verts[m]);
+ strm1.length = 0;
+ strm1.istream = null;
+ strm.tail = k;
+ faceTable[k] = id;
+ i--;
+ break;
+ }
+
+ // append a strip of length over 2
+ else {
+ if ((len1 == 4) &&
+ (seq[1].index == seq1[0].index) &&
+ (seq[2].index == seq1[2].index)) {
+
+ // swap seq1[1] and seq1[2] so that
+ // seq[1] == seq1[0] and
+ // seq[1] == seq1[1]
+ swap = seq1[1];
+ seq1[1] = seq1[2];
+ seq1[2] = swap;
+ }
+
+ // see if we can join the strips
+ if ((seq[1].index == seq1[0].index) &&
+ (seq[2].index == seq1[1].index)) {
+ // System.out.println("reduce2");
+ // add the stream in
+ strm.addStream(strm1);
+ faceTable[k] = EMPTY;
+ faceTable[strm.tail] = id;
+
+ i--;
+ break;
+ }
+ else if (sync1) {
+ strm1.invert();
+ sync1 = false;
+ }
+ }
+ }
+ }
+ }
+
+ // not a singleton strip
+
+ // can append a stream where the current face is the tail
+ // or is an even length so we can invert it
+ else if ((i == strm.tail) || ((len % 2) == 0)) {
+ // if the current face isn't the tail, then
+ // have to invert the strip
+ if (i != strm.tail) {
+ strm.invert();
+ seq = strm.istream;
+ }
+
+ // System.out.println("seq.length = " + seq.length);
+ // System.out.println("len = " + len);
+ // System.out.print("seq = ");
+ // for (int l = 0; l < seq.length; l++) {
+ // if (seq[l] == null) System.out.print(" null");
+ // else System.out.print(" " + seq[l].index);
+ // }
+ // System.out.println("");
+
+ swap = seq[len - 3];
+
+ // find the neighboring strip
+ int m = EMPTY;
+ if (verts[0].index == swap.index) m = 0;
+ else if (verts[1].index == swap.index) m = 1;
+ else if (verts[2].index == swap.index) m = 2;
+ if (m == EMPTY) {
+ if (DEBUG) System.out.println("problem finding neighbor strip");
+ }
+ int j = face.getNeighbor(m);
+ if (j == EMPTY) id1 = j;
+ else id1 = faceTable[j];
+ if ((id1 != EMPTY) &&
+ (((Istream)strips.get(id1)).fan !=
+ strm.fan)) {
+ id1 = EMPTY;
+ }
+
+ if ((id1 != EMPTY) && (id1 != id)) {
+ strm1 = (Istream)strips.get(id1);
+ len1 = strm1.length;
+
+ // if the shared face isn't the head, invert
+ // the stream
+ if (j != strm1.head) {
+ strm1.invert();
+ // set the sync var if the length is odd
+ if ((len1 % 2) != 0) sync1 = true;
+ }
+ seq1 = strm1.istream;
+
+ // append a singleton strip
+ if (len1 == 3) {
+ // System.out.println("reduce2");
+ m = faces[j].findSharedEdge(i);
+ strm.append(faces[j].verts[m]);
+ strm1.length = 0;
+ strm1.istream = null;
+ strm.tail = j;
+ faceTable[i] = EMPTY;
+ faceTable[j] = id;
+ }
+
+ // append a non-singleton strip
+ else {
+ if ((len1 == 4) &&
+ (seq[len-2].index == seq1[0].index) &&
+ (seq[len-1].index == seq1[2].index)) {
+
+ // swap seq1[1] and seq1[2] so that
+ // seq[len-2] == seq1[0] and
+ // seq[len-1] == seq1[1]
+ swap = seq1[1];
+ seq1[1] = seq1[2];
+ seq1[2] = swap;
+ }
+
+ // see if we can append the strip
+ if ((seq[len-2].index == seq1[0].index) &&
+ (seq[len-1].index == seq1[1].index)) {
+ // System.out.println("reduce2");
+ strm.addStream(strm1);
+ faceTable[i] = EMPTY;
+ faceTable[strm.tail] = id;
+ faceTable[j] = EMPTY;
+ }
+ else if (sync1) strm1.invert();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * find all links that reduce cost by 1
+ */
+ void reduceCostByOne(ArrayList strips, Face[] faces, int[] faceTable) {
+ // System.out.println("reduceCostByOne");
+ // number of faces in the face array
+ int numFaces = faces.length;
+ // possible adjacent strips
+ int id, id1, id2;
+ // Istreams
+ Istream strm, strm1;
+ // the length of the Istream
+ int len, len1;
+ // vertex sequences for tristrips
+ Vertex[] seq, seq1;
+ // a face
+ Face face;
+ // the list of vertices for the face
+ Vertex[] verts;
+ // used to synchronize the orientation
+ boolean sync, sync1;
+ // a swap variable
+ Vertex swap;
+
+ for (int i = 0; i < numFaces; i++) {
+ id = faceTable[i];
+ if ((id != EMPTY) && !((Istream)strips.get(id)).fan) {
+ sync = false;
+ strm = (Istream)strips.get(id);
+ seq = strm.istream;
+ face = faces[i];
+ verts = face.verts;
+ len = strm.length;
+
+ // a singleton strip
+ if (len == 3) {
+
+ // consider the three neighboring triangles
+ for (int j = 0; j < 3; j++) {
+ int k = face.getNeighbor(j);
+ if ((k != EMPTY) &&
+ ((id1 = faceTable[k]) != EMPTY) &&
+ (id1 != id) &&
+ (!((Istream)strips.get(id1)).fan)) {
+
+ // reassign the sequence
+ seq[0] = verts[j];
+ seq[1] = verts[(j+1)%3];
+ seq[2] = verts[(j+2)%3];
+
+ // the neighboring stream
+ strm1 = (Istream)strips.get(id1);
+ len1 = strm1.length;
+ if (k != strm1.head) {
+ strm1.invert();
+ if ((len1 % 2) != 0) sync = true;
+ }
+ seq1 = strm1.istream;
+
+ // see if we can join the strips
+
+ if ((len1 == 4) &&
+ (((seq[1].index == seq1[2].index) &&
+ (seq[2].index == seq1[0].index)) ||
+ ((seq[1].index == seq1[0].index) &&
+ (seq[2].index == seq1[2].index)))) {
+ swap = seq1[1];
+ seq1[1] = seq1[2];
+ seq1[2] = swap;
+ }
+
+ if ((seq[1].index == seq1[0].index) &&
+ (seq[2].index == seq1[1].index)) {
+ // System.out.println("reduce1");
+ strm.addStream(strm1);
+ faceTable[k] = EMPTY;
+ faceTable[strm.tail] = id;
+ i--;
+ break;
+ }
+
+ if ((seq[1].index == seq1[1].index) &&
+ (seq[2].index == seq1[0].index)) {
+ // System.out.println("reduce1");
+ strm.append(seq1[1]);
+ strm.addStream(strm1);
+ faceTable[k] = EMPTY;
+ faceTable[strm.tail] = id;
+ i--;
+ break;
+ }
+
+ if ((seq[1].index == seq1[0].index) &&
+ (seq[2].index == seq1[2].index)) {
+ // System.out.println("reduce1");
+ seq1[0] = seq1[2];
+ strm.append(seq1[1]);
+ strm.addStream(strm1);
+ faceTable[k] = EMPTY;
+ faceTable[strm.tail] = id;
+ i--;
+ break;
+ }
+
+ if (sync) {
+ strm1.invert();
+ sync = false;
+ }
+ }
+ }
+ }
+
+ // non-singleton strip
+ else if ((i == strm.tail) || ((len % 2) == 0)) {
+
+ // make sure the face i ends the id-th strip
+ if (i != strm.tail) {
+ strm.invert();
+ seq = strm.istream;
+ }
+
+ swap = seq[len-3];
+
+ // find the neighboring strip
+ int m = EMPTY;
+ if (verts[0].index == swap.index) m = 0;
+ else if (verts[1].index == swap.index) m = 1;
+ else if (verts[2].index == swap.index) m = 2;
+ if (m == EMPTY) {
+ if (DEBUG) System.out.println("problem finding neighbor strip");
+ }
+ int j = face.getNeighbor(m);
+ if (j == EMPTY) id1 = j;
+ else id1 = faceTable[j];
+ if ((id1 != EMPTY) &&
+ (((Istream)strips.get(id1)).fan != strm.fan)) {
+ id1 = EMPTY;
+ }
+
+ // find another neighboring strip
+ swap = seq[len-2];
+ m = EMPTY;
+ if (verts[0].index == swap.index) m = 0;
+ else if (verts[1].index == swap.index) m = 1;
+ else if (verts[2].index == swap.index) m = 2;
+ if (m == EMPTY) {
+ if (DEBUG) System.out.println("problem finding neighbor strip.");
+ }
+ int k = face.getNeighbor(m);
+ if (k == EMPTY) id2 = k;
+ else id2 = faceTable[k];
+ if ((id2 != EMPTY) &&
+ (((Istream)strips.get(id2)).fan != strm.fan)) {
+ id2 = EMPTY;
+ }
+
+ // consider strip id1
+ boolean success = false;
+ if ((id1 != EMPTY) && (id1 != id)) {
+ strm1 = (Istream)strips.get(id1);
+ len1 = strm1.length;
+ if (j != strm1.head) {
+ strm1.invert();
+ if ((len1 % 2) != 0) sync = true;
+ }
+ seq1 = strm1.istream;
+
+ if ((len1 == 4) &&
+ (((seq[len-2].index == seq1[2].index) &&
+ (seq[len-1].index == seq1[0].index)) ||
+ (seq[len-2].index == seq1[0].index) &&
+ (seq[len-1].index == seq1[2].index))) {
+ swap = seq1[1];
+ seq1[1] = seq1[2];
+ seq1[2] = swap;
+ }
+
+ // find matches
+ if ((seq[len-2].index == seq1[0].index) &&
+ (seq[len-1].index == seq1[1].index)) {
+ // System.out.println("reduce1");
+ strm.addStream(strm1);
+ faceTable[i] = EMPTY;
+ faceTable[strm.tail] = id;
+ faceTable[j] = EMPTY;
+ success = true;
+ }
+
+ else if ((seq[len-2].index == seq1[1].index) &&
+ (seq[len-1].index == seq1[0].index)) {
+ // System.out.println("reduce1");
+ strm.append(seq1[1]);
+ strm.addStream(strm1);
+ faceTable[i] = EMPTY;
+ faceTable[strm.tail] = id;
+ faceTable[j] = EMPTY;
+ success = true;
+ }
+
+ else if ((seq[len-2].index == seq1[0].index) &&
+ (seq[len-1].index == seq1[2].index)) {
+ // System.out.println("reduce1");
+ seq1[0] = seq1[2];
+ strm.append(seq1[1]);
+ strm.addStream(strm1);
+ faceTable[i] = EMPTY;
+ faceTable[strm.tail] = id;
+ faceTable[j] = EMPTY;
+ success = true;
+ }
+ else if (sync) {
+ strm1.invert();
+ sync = false;
+ }
+ }
+
+ // now consider strip id2
+ if (!success &&
+ (id2 != EMPTY) && (id2 != id)) {
+ strm1 = (Istream)strips.get(id2);
+ len1 = strm1.length;
+ if (k != strm1.head) {
+ strm1.invert();
+ if ((len1 % 2) != 0) sync = true;
+ }
+ seq1 = strm1.istream;
+
+ if ((len1 == 4) &&
+ (seq[len-3].index == seq1[0].index) &&
+ (seq[len-1].index == seq1[2].index)) {
+ swap = seq1[1];
+ seq1[1] = seq1[2];
+ seq1[2] = swap;
+ }
+
+ // find matches
+
+ if ((seq[len-3].index == seq1[0].index) &&
+ (seq[len-1].index == seq1[1].index)) {
+ // System.out.println("reduce1");
+ strm.swapEnd();
+ strm.addStream(strm1);
+ faceTable[i] = EMPTY;
+ faceTable[strm.tail] = id;
+ faceTable[k] = EMPTY;
+ success = true;
+ }
+ if (!success && sync) strm1.invert();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * find all the links that reduce the cost by 0
+ */
+ void reduceCostByZero(ArrayList strips, Face[] faces, int[] faceTable) {
+ // System.out.println("reduceCostByZero");
+ // number of faces in the face array
+ int numFaces = faces.length;
+ // possible adjacent strips
+ int id, id1, id2;
+ // Istreams
+ Istream strm, strm1;
+ // the length of the Istream
+ int len, len1;
+ // vertex sequences for tristrips
+ Vertex[] seq, seq1;
+ // a face
+ Face face;
+ // the list of vertices for the face
+ Vertex[] verts;
+ // used to synchronize the orientation
+ boolean sync, sync1;
+ // a swap variable
+ Vertex swap;
+
+ for (int i = 0; i < numFaces; i++) {
+ id = faceTable[i];
+ if ((id != EMPTY) && !((Istream)strips.get(id)).fan) {
+ sync = false;
+ strm = (Istream)strips.get(id);
+ seq = strm.istream;
+ len = strm.length;
+ face = faces[i];
+ verts = face.verts;
+
+ if (len == 3) {
+ for (int j = 0; j < 3; j++) {
+ int k = face.getNeighbor(j);
+ if ((k != EMPTY) && ((id1 = faceTable[k]) != EMPTY) &&
+ (id1 != id) &&
+ !((Istream)strips.get(id1)).fan) {
+ // reassign the sequence
+ seq[0] = verts[j];
+ seq[1] = verts[(j+1)%3];
+ seq[2] = verts[(j+2)%3];
+
+ // the neighboring stream
+ strm1 = (Istream)strips.get(id1);
+ len1 = strm1.length;
+ if (k != strm1.head) {
+ strm1.invert();
+ if ((len1 % 2) != 0) sync = true;
+ }
+ seq1 = strm1.istream;
+
+ // see if we can join the strips
+ if ((seq[1].index == seq1[2].index) &&
+ (seq[2].index == seq1[0].index)) {
+ // System.out.println("reduce0");
+ seq1[0] = seq1[2];
+ strm.append(seq1[0]);
+ strm.append(seq1[1]);
+ strm.addStream(strm1);
+ faceTable[k] = EMPTY;
+ faceTable[strm.tail] = id;
+ i--;
+ break;
+ }
+ else if (sync) {
+ strm1.invert();
+ sync = false;
+ }
+ }
+ }
+ }
+ else if ((i == strm.tail) || ((len % 2) == 0)) {
+ if (i != strm.tail) {
+ strm.invert();
+ seq = strm.istream;
+ }
+
+ swap = seq[len-3];
+
+ // find neighboring strip
+ int m = EMPTY;
+ if (verts[0].index == swap.index) m = 0;
+ else if (verts[1].index == swap.index) m = 1;
+ else if (verts[2].index == swap.index) m = 2;
+ if (m == EMPTY) {
+ if (DEBUG) System.out.println("problem finding neighbor strip");
+ }
+ int j = face.getNeighbor(m);
+ if (j == EMPTY) id1 = j;
+ else id1 = faceTable[j];
+ if ((id1 != EMPTY) &&
+ (((Istream)strips.get(id1)).fan != strm.fan)) {
+ id1 = EMPTY;
+ }
+
+ // find another neighboring strip
+ swap = seq[len-2];
+ m = EMPTY;
+ if (verts[0].index == swap.index) m = 0;
+ else if (verts[1].index == swap.index) m = 1;
+ else if (verts[2].index == swap.index) m = 2;
+ if (m == EMPTY) {
+ if (DEBUG) System.out.println("problem finding neighbor strip.");
+ }
+ int k = face.getNeighbor(m);
+ if (k == EMPTY) id2 = k;
+ else id2 = faceTable[k];
+ if ((id2 != EMPTY) &&
+ (((Istream)strips.get(id2)).fan != strm.fan)) {
+ id2 = EMPTY;
+ }
+
+ // consider strip id1
+ boolean success = false;
+ if ((id1 != EMPTY) && (id1 != id)) {
+ strm1 = (Istream)strips.get(id1);
+ len1 = strm1.length;
+ if (j != strm1.head) {
+ strm1.invert();
+ if ((len1 % 2) != 0) sync = true;
+ }
+ seq1 = strm1.istream;
+
+ // find matches
+ if ((seq[len-2].index == seq1[2].index) &&
+ (seq[len-1].index == seq1[0].index)) {
+ // System.out.println("reduce0");
+ seq1[0] = seq1[2];
+ strm.append(seq1[0]);
+ strm.append(seq1[1]);
+ strm.addStream(strm1);
+ faceTable[i] = EMPTY;
+ faceTable[strm.tail] = id;
+ faceTable[j] = EMPTY;
+ success = true;
+ }
+ else if (sync) {
+ strm1.invert();
+ sync = false;
+ }
+ }
+
+ // consider strip id2
+ if (!success && (id2 != EMPTY) && (id2 != id)) {
+ strm1 = (Istream)strips.get(id2);
+ len1 = strm1.length;
+ if (k != strm1.head) {
+ strm1.invert();
+ if ((len1 % 2) != 0) sync = true;
+ }
+ seq1 = strm1.istream;
+
+ if ((len1 == 4) &&
+ (((seq[len-3].index == seq1[2].index) &&
+ (seq[len-1].index == seq1[0].index)) ||
+ ((seq[len-3].index == seq1[0].index) &&
+ (seq[len-1].index == seq1[2].index)))) {
+
+ swap = seq1[1];
+ seq1[1] = seq1[2];
+ seq1[2] = swap;
+ }
+
+ // find matches
+ if ((seq[len-3].index == seq1[1].index) &&
+ (seq[len-1].index == seq1[0].index)) {
+ // System.out.println("reduce0");
+ strm.swapEnd();
+ strm.append(seq1[1]);
+ strm.addStream(strm1);
+ faceTable[i] = EMPTY;
+ faceTable[strm.tail] = id;
+ faceTable[k] = EMPTY;
+ }
+ else if ((seq[len-3].index == seq1[0].index) &&
+ (seq[len-1].index == seq1[2].index)) {
+ // System.out.println("reduce0");
+ seq1[0] = seq1[2];
+ strm.swapEnd();
+ strm.append(seq1[1]);
+ strm.addStream(strm1);
+ faceTable[i] = EMPTY;
+ faceTable[strm.tail] = id;
+ faceTable[k] = EMPTY;
+ }
+ else if ((seq[len-3].index == seq1[0].index) &&
+ (seq[len-1].index == seq1[1].index)) {
+ // System.out.println("reduce0");
+ strm.swapEnd();
+ strm.addStream(strm1);
+ faceTable[i] = EMPTY;
+ faceTable[strm.tail] = id;
+ faceTable[k] = EMPTY;
+ }
+ else if (sync) strm1.invert();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * puts the stripified data back into the GeometryInfo object
+ */
+ void putBackData(GeometryInfo gi, ArrayList strips) {
+ int[] tempStripCounts = new int[strips.size()];
+ int ciSize = 0;
+ int stripLength;
+ for (int i = 0; i < strips.size();) {
+ stripLength = ((Istream)strips.get(i)).length;
+ if (stripLength != 0) {
+ tempStripCounts[i] = stripLength;
+ ciSize += stripLength;
+ i++;
+ }
+ else {
+ strips.remove(i);
+ }
+ }
+ if (ciSize > 3) {
+ gi.setPrimitive(gi.TRIANGLE_STRIP_ARRAY);
+ int[] stripCounts = new int[strips.size()];
+ System.arraycopy(tempStripCounts, 0, stripCounts, 0, strips.size());
+ gi.setStripCounts(stripCounts);
+
+ // create one array with all the strips
+ int[] coords = new int[ciSize];
+
+ // create arrays for normals, textures and colors if necessary
+ int[] normals = null;
+ int[][] textures = null;
+ int[] colors = null;
+ org.jogamp.vecmath.Color3b[] stripColors = null;
+ if (hasNormals) normals = new int[ciSize];
+ if (hasTextures) {
+ textures = new int[texSetCount][ciSize];
+ }
+ if (hasColors) colors = new int[ciSize];
+ if (colorStrips) {
+ stripColors = new org.jogamp.vecmath.Color3b[ciSize];
+ colors = new int[ciSize];
+ }
+ int count = 0;
+ Istream currStrip;
+ for (int i = 0; i < strips.size(); i++) {
+ currStrip = (Istream)strips.get(i);
+
+ if (currStrip.length < 3) {
+ throw new RuntimeException("currStrip.length = " +
+ currStrip.length);
+ }
+
+ java.awt.Color stripColor = null;
+ if (colorStrips) {
+ int r = ((int)(Math.random()*1000))%255;
+ int g = ((int)(Math.random()*1000))%255;
+ int b = ((int)(Math.random()*1000))%255;
+ stripColor = new java.awt.Color(r, g, b);
+ }
+
+ for (int j = 0; j < currStrip.length; j++) {
+ coords[count] = currStrip.istream[j].index;
+ if (hasNormals) normals[count] = currStrip.istream[j].normal;
+ if (hasTextures) {
+ for (int k = 0; k < texSetCount; k++) {
+ textures[k][count] =
+ currStrip.istream[j].texture[k];
+ }
+ }
+ if (hasColors) colors[count] = currStrip.istream[j].color;
+ if (colorStrips) stripColors[count] =
+ new org.jogamp.vecmath.Color3b(stripColor);
+ count++;
+ }
+ }
+ gi.setCoordinateIndices(coords);
+ if (hasNormals) gi.setNormalIndices(normals);
+ if (hasTextures) {
+ for (int i = 0; i < texSetCount; i++) {
+ gi.setTextureCoordinateIndices(i, textures[i]);
+ }
+ }
+ if (hasColors) gi.setColorIndices(colors);
+ if (colorStrips) {
+ gi.setColors(stripColors);
+ colors = gi.getListIndices(stripColors);
+ gi.setColorIndices(colors);
+ }
+ }
+ }
+
+ /**
+ * Stores the infomration about a vertex
+ */
+ class Vertex {
+
+ int index;
+ int normal = EMPTY;
+ int numTexSets = 0;
+ int[] texture = null;
+ int color = EMPTY;
+
+ Vertex(int vertIndex) {
+ this(vertIndex, EMPTY, 0, null, EMPTY);
+ }
+
+ Vertex(int vertIndex, int vertNormal,
+ int vertNumTexSets, int[] vertTexture, int vertColor) {
+ index = vertIndex;
+ normal = vertNormal;
+ numTexSets = vertNumTexSets;
+ if (numTexSets > 0) {
+ texture = new int[numTexSets];
+ System.arraycopy(vertTexture, 0, texture, 0, numTexSets);
+ }
+ color = vertColor;
+ }
+
+ boolean equals(Vertex v) {
+ for (int i = 0; i < numTexSets; i++) {
+ if (texture[i] != v.texture[i]) {
+ return false;
+ }
+ }
+ return ((v.index == index) &&
+ (v.normal == normal) &&
+ (v.color == color));
+ }
+
+ // will this yield same results as c code ???
+ boolean lessThan(Vertex v) {
+ if (index < v.index) return true;
+ if (index > v.index) return false;
+ if (normal < v.normal) return true;
+ if (normal > v.normal) return false;
+ for (int i = 0; i < numTexSets; i++) {
+ if (texture[i] < v.texture[i]) return true;
+ if (texture[i] > v.texture[i]) return false;
+ }
+ if (color < v.color) return true;
+ if (color > v.color) return false;
+ return false;
+ }
+ }
+
+ /**
+ * Stores the information about an edge of a triangle
+ */
+ class Edge {
+
+ Vertex v1, v2;
+ int face;
+
+ Edge(Vertex vertex1, Vertex vertex2, int faceIndex) {
+ face = faceIndex;
+
+ // this could be causing wrapping problem
+ if (vertex1.lessThan(vertex2)) {
+ v1 = vertex1;
+ v2 = vertex2;
+ } else {
+ v1 = vertex2;
+ v2 = vertex1;
+ }
+ }
+
+ /**
+ * Determine whether the edges have the same vertices
+ */
+ boolean equals(Edge edge) {
+ return ((v1.equals(edge.v1)) && (v2.equals(edge.v2)));
+
+ }
+
+ /**
+ * Used to sort the edges. If this is less than the edge parameter,
+ * return true. First check if vertex1 is less than vertex1 of the
+ * edge provided. If so, return true. If the first vertices are equal
+ * then check vertex2.
+ */
+ boolean lessThan(Edge edge) {
+ if (v1.lessThan(edge.v1)) return true;
+ else if (v1.equals(edge.v1)) return (v2.lessThan(edge.v2));
+ else return false;
+ }
+ }
+
+ /**
+ * Stores the information about the face of a triangle
+ */
+ class Face {
+ int key;
+ int numNhbrs = 0;
+ Vertex[] verts = null;
+ // edges are kept in order s.t. the ith edge is the opposite
+ // edge of the ith vertex
+ Edge[] edges = null;
+
+ /**
+ * Creates a new Face with the three given vertices
+ */
+ Face(int index, Vertex v1, Vertex v2, Vertex v3) {
+ key = index;
+
+ verts = new Vertex[3];
+ verts[0] = v1;
+ verts[1] = v2;
+ verts[2] = v3;
+
+ edges = new Edge[3];
+ edges[0] = null;
+ edges[1] = null;
+ edges[2] = null;
+ numNhbrs = 3;
+ }
+
+ /**
+ * returns the index of the face that neighbors the edge supplied
+ * by the parameter
+ */
+ int getNeighbor(int edge) {
+ return edges[edge].face;
+ }
+
+ /**
+ * returns the index of the edge that is shared by the triangle
+ * specified by the key parameter
+ */
+ int findSharedEdge(int key) {
+ if (edges[0].face == key) return 0;
+ else if (edges[1].face == key) return 1;
+ else if (edges[2].face == key) return 2;
+ else return -1; /* error */
+ }
+
+ int getEdgeIndex(Edge edge) {
+ if (edges[0].equals(edge)) return 0;
+ else if (edges[1].equals(edge)) return 1;
+ else return 2;
+ }
+
+ void counterEdgeDel(Edge edge) {
+ if (DEBUG) {
+ System.out.println("counterEdgeDel");
+ }
+ if ((edges[0]).equals(edge)) {
+ edges[0].face = EMPTY;
+ numNhbrs--;
+ }
+ else if ((edges[1]).equals(edge)) {
+ edges[1].face = EMPTY;
+ numNhbrs--;
+ }
+ else if ((edges[2]).equals(edge)) {
+ edges[2].face = EMPTY;
+ numNhbrs--;
+ }
+ else {
+ if (DEBUG) {
+ System.out.println("error in counterEdgeDel");
+ }
+ }
+ }
+
+ void printAdjacency() {
+ System.out.println("Face " + key + ": ");
+ System.out.println("\t numNhbrs = " + numNhbrs);
+ System.out.println("\t edge 0: Face " + edges[0].face);
+ System.out.println("\t edge 1: Face " + edges[1].face);
+ System.out.println("\t edge 2: Face " + edges[2].face);
+ }
+
+ void printVertices() {
+ System.out.println("Face " + key + ": (" + verts[0].index + ", " +
+ verts[1].index + ", " + verts[2].index + ")");
+ }
+ }
+
+ /**
+ * stores the information for a face node
+ */
+ class Node {
+ Face face; // the data: the face
+ Node parent; // the parent node
+ Node left; // the left child
+ Node right; // the right child
+ int depth; // the topological distance of the node from the root
+ int numChildren; // the number of children
+ int attrib; // characteristic of the node eg. color
+
+ // the attributes - 3 states for the Node
+ static final int WHITE = 0; // not being accessed yet
+ static final int GREY = 1; // being accessed but not done yet
+ static final int BLACK = 2; // done
+
+ Node(Face f) {
+ face = f;
+ }
+
+ /**
+ * inserts this node below the parent supplied.
+ */
+ void insert(Node p) {
+ parent = p;
+ depth = p.depth + 1;
+ attrib = GREY;
+
+ if (parent.left == null) parent.left = this;
+ else parent.right = this;
+ (parent.numChildren)++;
+ }
+
+ /**
+ * remove this node from its parent
+ */
+ void remove() {
+ if (parent != null) {
+ if (parent.left == this) {
+ parent.left = parent.right;
+ parent.right = null;
+ }
+ else {
+ parent.right = null;
+ }
+ (parent.numChildren)--;
+ }
+ }
+
+
+ /**
+ * sets the depth to 0 and the attrib to GREY
+ */
+ void setRoot() {
+ depth = 0;
+ attrib = GREY;
+ }
+
+ /**
+ * returns true if the attrib is WHITE
+ */
+ boolean notAccessed() {
+ return (attrib == WHITE);
+ }
+
+ /**
+ * sets the color to BLACK
+ */
+ void processed() {
+ attrib = BLACK;
+ }
+
+ /**
+ * a node is the root if it doesn't have a parent
+ */
+ boolean isRoot() {
+ return (parent == null);
+ }
+
+ /**
+ * prints the information in this Node
+ */
+ void print() {
+ System.out.println(this);
+ System.out.println("Node depth: " + depth);
+ face.printVertices();
+ System.out.print("parent: ");
+ if (parent != null) parent.face.printVertices();
+ else System.out.println("null");
+ System.out.print("left: ");
+ if (left != null) left.face.printVertices();
+ else System.out.println("null");
+ System.out.print("right: ");
+ if (right != null) right.face.printVertices();
+ else System.out.println("null");
+ System.out.println("attrib: " + attrib);
+ System.out.println("");
+ }
+ }
+
+ /**
+ * sorts the Nodes by depth
+ */
+ class SortedList {
+
+ ArrayList list;
+
+ /**
+ * create a new SortedList
+ */
+ SortedList() {
+ list = new ArrayList();
+ }
+
+ /**
+ * insert into the list sorted by depth. start looking at start
+ * to save some time. Returns the index of the next item of the
+ * inserted element
+ */
+ int sortedInsert(Node data, int start) {
+ // adjust start to where insert sorted
+ while ((start < list.size()) &&
+ (((Node)list.get(start)).depth <= data.depth)) {
+ start++;
+ }
+
+ // insert at start index
+ list.add(start, data);
+
+ // return start+1 -- the index of the next element
+ return (start+1);
+ }
+
+ /**
+ * remove and return 1st element
+ */
+ Node pop() {
+ if (!list.isEmpty()) return (Node)list.remove(0);
+ else return null;
+ }
+ }
+
+ class Istream {
+
+ // fan encoding
+ boolean fan = false;
+ // length of the strip
+ int length = 0;
+ // array that specifies triangle strip
+ Vertex[] istream;
+ // indices of the head and tail vertices
+ int head, tail;
+
+ /**
+ * creates a new Istream to store the triangle strip
+ */
+ Istream(Vertex[] list, int size, boolean isFan) {
+ if (size == 0) throw new RuntimeException("size is 0");
+ fan = isFan;
+ length = size;
+ istream = new Vertex[length];
+ int i;
+ System.arraycopy(list, 0, istream, 0, length);
+ }
+
+ /**
+ * adds a new vertex to the end of the stream
+ * makes the int array bigger, if necessary
+ */
+ void append(Vertex vertex) {
+ growArray();
+ // add in new vertex
+ istream[length] = vertex;
+ length++;
+ }
+
+ /**
+ * turns the encoding (..., -3, -2, -1) into (.... -3, -2, -3, -1)
+ * so that zero-area triangle (-3, -2. -3) is added
+ */
+ void swapEnd() {
+ growArray();
+ istream[length] = istream[length-1];
+ istream[length-1] = istream[length-3];
+ length++;
+ }
+
+ /**
+ * makes the array bigger, if necessary
+ */
+ void growArray() {
+ if (length >= istream.length) {
+ Vertex[] old = istream;
+ // for now add enough space to add three more vertices
+ // may change this later
+ istream = new Vertex[length + 3];
+ System.arraycopy(old, 0, istream, 0, length);
+ }
+ }
+
+ /**
+ * inverts the istream
+ */
+ void invert() {
+ Vertex[] tmp = new Vertex[istream.length];
+ // reverse the stream
+ for (int i = 0; i < length; i++) {
+ tmp[i] = istream[length - i - 1];
+ }
+ // copy it back
+ System.arraycopy(tmp, 0, istream, 0, istream.length);
+ tmp = null;
+ // swap the head and the tail
+ int swap = head;
+ head = tail;
+ tail = swap;
+ }
+
+ /**
+ * concats two streams into one big stream
+ */
+ void addStream(Istream strm) {
+ // System.out.println("addStream");
+ int strmLen = strm.length;
+ int size = strmLen + length - 2;
+
+ // make the istream bigger
+ if (size >= istream.length) {
+ Vertex[] old = istream;
+ istream = new Vertex[size];
+ System.arraycopy(old, 0, istream, 0, length);
+ }
+
+ // add the strm to istream
+ System.arraycopy(strm.istream, 2, istream, length, strmLen-2);
+
+ tail = strm.tail;
+ length = size;
+ strm.length = 0;
+ strm.istream = null;
+ }
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/StripifierStats.java b/src/classes/share/org/jogamp/java3d/utils/geometry/StripifierStats.java
new file mode 100644
index 0000000..f5d1e68
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/StripifierStats.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+import java.util.ArrayList;
+
+/**
+ * This class collects statistics on the Stripifier. The statistics
+ * are cumulative over all calls to stripify() until clearData() is called.
+ *
+ * @since Java 3D 1.2.1
+ */
+
+public class StripifierStats {
+
+ int numStrips = 0;
+ int numVerts = 0;
+ int minStripLen = 10000;
+ int maxStripLen = 0;
+ int totalTris = 0;
+ int numFaces = 0;
+ long time = 0;
+ int[] counts = new int[14];
+
+ boolean noData = true;
+
+ /**
+ * Returns the number of triangles in the original, un-stripified data.
+ * @since Java 3D 1.2.1
+ */
+ public int getNumOrigTris() {
+ return numFaces;
+ }
+
+ /**
+ * Returns the number of vertices in the original, un-stripified data
+ * @since Java 3D 1.2.1
+ */
+ public int getNumOrigVerts() {
+ return (numFaces * 3);
+ }
+
+ /**
+ * Returns the number of strips created by the stripifier.
+ * @since Java 3D 1.2.1
+ */
+ public int getNumStrips() {
+ return numStrips;
+ }
+
+ /**
+ * Returns the number of vertices in the stripified data.
+ * @since Java 3D 1.2.1
+ */
+ public int getNumVerts() {
+ return numVerts;
+ }
+
+ /**
+ * Returns the number of triangles in the stripified data.
+ * @since Java 3D 1.2.1
+ */
+ public int getTotalTris() {
+ return totalTris;
+ }
+
+ /**
+ * Returns the length in triangles of the shortest strip
+ * created by the stripifier.
+ * @since Java 3D 1.2.1
+ */
+ public int getMinStripLength() {
+ return minStripLen;
+ }
+
+ /**
+ * Returns the length in triangles of the longest strip
+ * created by the stripifier.
+ * @since Java 3D 1.2.1
+ */
+ public int getMaxStripLength() {
+ return maxStripLen;
+ }
+
+ /**
+ * Return the average length of the strips created by the stripifier
+ * @since Java 3D 1.2.1
+ */
+ public double getAvgStripLength() {
+ return ((double)totalTris/(double)numStrips);
+ }
+
+ /**
+ * Returns the average number of vertices per triangle in the stripified
+ * data
+ * @since Java 3D 1.2.1
+ */
+ public double getAvgNumVertsPerTri() {
+ return ((double)numVerts/(double)totalTris);
+ }
+
+ /**
+ * Returns the total time spent in the stripify() method
+ * @since Java 3D 1.2.1
+ */
+ public long getTotalTime() {
+ return time;
+ }
+
+ /**
+ * Returns an array of length 14 that contains the number of strips of
+ * a given length created by the stripifier. Spots 0-8 of the array
+ * represent lengths 1-9, 9 is lengths 10-19, 10 is lengths 20-49,
+ * 11 is lengths 50-99, 12 is lengths 100-999 and 13 is lengths 1000
+ * or more.
+ * @since Java 3D 1.2.1
+ */
+ public int[] getStripLengthCounts() {
+ return counts;
+ }
+
+ /**
+ * Returns a formated String that can be used to print out
+ * the Stripifier stats.
+ * @since Java 3D 1.2.1
+ */
+
+ @Override
+ public String toString() {
+ StringBuffer str = new StringBuffer(
+ "num orig tris: " + numFaces + "\n" +
+ "num orig vertices: " + (numFaces*3) + "\n" +
+ "number of strips: " + numStrips + "\n" +
+ "number of vertices: " + numVerts + "\n" +
+ "total tris: " + totalTris + "\n" +
+ "min strip length: " + minStripLen + "\n" +
+ "max strip length: " + maxStripLen + "\n" +
+ "avg strip length: " + ((double)totalTris/
+ (double)numStrips) + "\n" +
+ "avg num verts/tri: " + ((double)numVerts/
+ (double)totalTris) + "\n" +
+ "total time: " + time + "\n" +
+ "strip length distribution:\n");
+ for (int i = 0; i < 9; i++){
+ str.append(" " + (i+1) + "=" + counts[i]);
+ }
+ str.append(" 10-19=" + counts[9]);
+ str.append(" 20-49=" + counts[10]);
+ str.append(" 50-99=" + counts[11]);
+ str.append(" 100-999=" + counts[12]);
+ str.append(" 1000 or more=" + counts[13] + "\n");
+
+ return str.toString();
+ }
+
+ /**
+ * Clears the statistical data
+ */
+ public void clearData() {
+ noData = true;
+
+ numStrips = 0;
+ numVerts = 0;
+ minStripLen = 10000;
+ maxStripLen = 0;
+ totalTris = 0;
+ numFaces = 0;
+ time = 0;
+ counts = new int[14];
+ }
+
+ void updateInfo(long ntime, ArrayList strips,
+ int nNumFaces) {
+ noData = false;
+
+ time += ntime;
+ numStrips += strips.size();
+ int nv = 0;
+ int mnsl = 10000;
+ int mxsl = 0;
+ int tt = 0;
+ for (int i = 0; i < strips.size(); i++) {
+ Stripifier.Istream strm = (Stripifier.Istream)strips.get(i);
+ int len = strm.length;
+ int trilen = (len-2);
+ nv += len;
+ if (trilen < mnsl) mnsl = trilen;
+ if (trilen > mxsl) mxsl = trilen;
+ tt += trilen;
+
+ // add to counts
+ // how many strips are length 1-9
+ if (trilen <= 9) counts[trilen-1] += 1;
+ // how many strips are length 10-19
+ else if (trilen < 20) counts[9] += 1;
+ // how many strips are length 20-49
+ else if (trilen < 50) counts[10] += 1;
+ // how many strips are length 50-99
+ else if (trilen < 100) counts[11] += 1;
+ // how many strips are length 100-1000
+ else if (trilen < 1000) counts[12] += 1;
+ // how many strips are length > 1000
+ else counts[13] += 1;
+ }
+ numVerts += nv;
+ if (mnsl < minStripLen) minStripLen = mnsl;
+ if (mxsl > maxStripLen) maxStripLen = mxsl;
+ totalTris += tt;
+ numFaces += nNumFaces;
+ }
+
+ void updateInfo(long ntime, int scLen, int sc[],
+ int nNumFaces) {
+
+ noData = false;
+
+ time += ntime;
+ numStrips += scLen;
+ int nv = 0;
+ int mnsl = 10000;
+ int mxsl = 0;
+ int tt = 0;
+ for (int i = 0; i < scLen; i++) {
+ int len = sc[i];
+ int trilen = (len-2);
+ numVerts += len;
+ if (trilen < mnsl) mnsl = trilen;
+ if (trilen > mxsl) mxsl = trilen;
+ totalTris += trilen;
+
+ // add to counts
+ // how many strips are length 1-9
+ if (trilen <= 9) counts[trilen-1] += 1;
+ // how many strips are length 10-19
+ else if (trilen < 20) counts[9] += 1;
+ // how many strips are length 20-49
+ else if (trilen < 50) counts[10] += 1;
+ // how many strips are length 50-99
+ else if (trilen < 100) counts[11] += 1;
+ // how many strips are length 100-1000
+ else if (trilen < 1000) counts[12] += 1;
+ // how many strips are length > 1000
+ else counts[13] += 1;
+ }
+ numVerts += nv;
+ if (mnsl < minStripLen) minStripLen = mnsl;
+ if (mxsl > maxStripLen) maxStripLen = mxsl;
+ totalTris += tt;
+ numFaces += nNumFaces;
+ }
+
+ // void printInfo() {
+ // System.out.println("num orig tris: " + numFaces);
+ // System.out.println("num orig vertices: " + (numFaces*3));
+ // System.out.println("number of strips: " + numStrips);
+ // System.out.println("number of vertices: " + numVerts);
+ // System.out.println("total tris: " + totalTris);
+ // System.out.println("min strip length: " + minStripLen);
+ // System.out.println("max strip length: " + maxStripLen);
+ // System.out.println("avg strip length: " + ((double)totalTris/
+ // (double)numStrips));
+ // System.out.println("avg num verts/tri: " + ((double)numVerts/
+ // (double)totalTris));
+ // System.out.println("total time: " + time);
+ // System.out.println("strip length distribution:");
+ // for (int i = 0; i < 9; i++){
+ // System.out.print(" " + (i+1) + "=" + counts[i]);
+ // }
+ // System.out.print(" 10-19=" + counts[9]);
+ // System.out.print(" 20-49=" + counts[10]);
+ // System.out.print(" 50-99=" + counts[11]);
+ // System.out.print(" 100-999=" + counts[12]);
+ // System.out.println(" 1000 or more=" + counts[13]);
+
+ // // reset info after printing data
+ // numStrips = 0;
+ // numVerts = 0;
+ // minStripLen = 10000;
+ // maxStripLen = 0;
+ // totalTris = 0;
+ // numFaces = 0;
+ // time = 0;
+ // counts = new int[14];
+ // }
+
+ StripifierStats() {
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Text2D.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Text2D.java
new file mode 100644
index 0000000..e9c8e59
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Text2D.java
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.image.BufferedImage;
+import java.util.Hashtable;
+
+import org.jogamp.java3d.Appearance;
+import org.jogamp.java3d.ImageComponent;
+import org.jogamp.java3d.ImageComponent2D;
+import org.jogamp.java3d.Material;
+import org.jogamp.java3d.Node;
+import org.jogamp.java3d.QuadArray;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.java3d.Texture;
+import org.jogamp.java3d.Texture2D;
+import org.jogamp.java3d.TransparencyAttributes;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4f;
+
+/**
+ * A Text2D object is a representation of a string as a texture mapped
+ * rectangle. The texture for the rectangle shows the string as rendered in
+ * the specified color with a transparent background. The appearance of the
+ * characters is specified using the font indicated by the font name, size
+ * and style (see java.awt.Font). The approximate height of the rendered
+ * string will be the font size times the rectangle scale factor, which has a
+ * default value of 1/256. For example, a 12 point font will produce
+ * characters that are about 12/256 = 0.047 meters tall. The lower left
+ * corner of the rectangle is located at (0,0,0) with the height
+ * extending along the positive y-axis and the width extending along the
+ * positive x-axis.
+ */
+public class Text2D extends Shape3D {
+
+ // This table caches FontMetrics objects to avoid the huge cost
+ // of re-retrieving metrics for a font we've already seen.
+ private static Hashtable metricsTable = new Hashtable();
+ private float rectangleScaleFactor = 1f/256f;
+
+ private boolean enableTextureWrite = false;
+
+ private Color3f color = new Color3f();
+ private String fontName;
+ private int fontSize, fontStyle;
+ private String text;
+
+ // max texture dimension, as some font size can be greater than
+ // video card max texture size. 2048 is a conservative value.
+ private int MAX_TEXTURE_DIM = 2048;
+
+ // vWidth is the virtual width texture. Value set by setupImage()
+ private int vWidth;
+ // vHeight is the virtual height texture. Value set by setupImage()
+ private int vHeight;
+
+
+ /**
+ * Creates a Shape3D object which holds a
+ * rectangle that is texture-mapped with an image that has
+ * the specified text written with the specified font
+ * parameters.
+ *
+ * @param text The string to be written into the texture map.
+ * @param color The color of the text string.
+ * @param fontName The name of the Java font to be used for
+ * the text string.
+ * @param fontSize The size of the Java font to be used.
+ * @param fontStyle The style of the Java font to be used.
+ */
+ public Text2D(String text, Color3f color, String fontName,
+ int fontSize, int fontStyle) {
+
+ this.color.set(color);
+ this.fontName = fontName;
+ this.fontSize = fontSize;
+ this.fontStyle = fontStyle;
+ this.text = text;
+ setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
+ setCapability(Shape3D.ALLOW_APPEARANCE_READ);
+ setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
+
+ updateText2D(text, color, fontName, fontSize, fontStyle);
+ }
+
+ // issue 655
+ private Text2D() {
+
+ setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
+ setCapability(Shape3D.ALLOW_APPEARANCE_READ);
+ setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
+ }
+
+ // issue 655
+ @Override
+ public Node cloneNode(boolean forceDuplicate) {
+ Text2D t2d = new Text2D();
+
+ t2d.color.set(color);
+ t2d.fontName = fontName;
+ t2d.fontSize = fontSize;
+ t2d.fontStyle = fontStyle;
+ t2d.text = text;
+
+ t2d.duplicateNode(this, forceDuplicate);
+ return t2d;
+ }
+
+ /*
+ * Changes text of this Text2D to 'text'. All other
+ * parameters (color, fontName, fontSize, fontStyle
+ * remain the same.
+ * @param text The string to be set.
+ */
+ public void setString(String text){
+ this.text = text;
+
+ Texture tex = getAppearance().getTexture();
+
+ // mcneillk: JAVA3D-657
+ if (tex == null) {
+ tex = getAppearance().getTextureUnitState(0).getTexture();
+ }
+
+ int width = tex.getWidth();
+ int height = tex.getHeight();
+ int oldVW = vWidth;
+ int oldVH = vHeight;
+
+ ImageComponent imageComponent = setupImage(text, color, fontName,
+ fontSize, fontStyle);
+ if ((imageComponent.getWidth() == width) &&
+ (imageComponent.getHeight() == height)) {
+ tex.setImage(0, imageComponent);
+ } else {
+ Texture2D newTex = setupTexture(imageComponent);
+ // Copy texture attributes except those related to
+ // mipmap since Texture only set base imageComponent.
+
+ newTex.setBoundaryModeS(tex.getBoundaryModeS());
+ newTex.setBoundaryModeT(tex.getBoundaryModeT());
+ newTex.setMinFilter(tex.getMinFilter());
+ newTex.setMagFilter(tex.getMagFilter());
+ newTex.setEnable(tex.getEnable());
+ newTex.setAnisotropicFilterMode(tex.getAnisotropicFilterMode());
+ newTex.setAnisotropicFilterDegree(tex.getAnisotropicFilterDegree());
+ int pcount = tex.getFilter4FuncPointsCount();
+ if (pcount > 0) {
+ float weights[] = new float[pcount];
+ tex.getFilter4Func(weights);
+ newTex.setFilter4Func(weights);
+ }
+ Color4f c = new Color4f();
+ tex.getBoundaryColor(c);
+ newTex.setBoundaryColor(c);
+ newTex.setUserData(tex.getUserData());
+
+ // mcneillk: JAVA3D-657
+ if (getAppearance().getTexture() != null) {
+ getAppearance().setTexture(newTex);
+ } else {
+ getAppearance().getTextureUnitState(0).setTexture(newTex);
+ }
+ }
+ // Does the new text requires a new geometry ?
+ if ( oldVH != vHeight || oldVW != vWidth){
+ QuadArray rect = setupGeometry(vWidth, vHeight);
+ setGeometry(rect);
+ }
+ }
+
+ private void updateText2D(String text, Color3f color, String fontName,
+ int fontSize, int fontStyle) {
+ ImageComponent imageComponent = setupImage(text, color, fontName,
+ fontSize, fontStyle);
+
+ Texture2D t2d = setupTexture(imageComponent);
+
+ QuadArray rect = setupGeometry(vWidth, vHeight);
+ setGeometry(rect);
+
+ Appearance appearance = setupAppearance(t2d);
+ setAppearance(appearance);
+ }
+
+
+ /**
+ * Sets the scale factor used in converting the image width/height
+ * to width/height values in 3D.
+ *
+ * @param newScaleFactor The new scale factor.
+ */
+ public void setRectangleScaleFactor(float newScaleFactor) {
+ rectangleScaleFactor = newScaleFactor;
+ updateText2D(text, color, fontName, fontSize, fontStyle);
+ }
+
+ /**
+ * Gets the current scale factor being used in converting the image
+ * width/height to width/height values in 3D.
+ *
+ * @return The current scale factor.
+ */
+ public float getRectangleScaleFactor() {
+ return rectangleScaleFactor;
+ }
+
+ /**
+ * Create the ImageComponent and Texture object.
+ */
+ private Texture2D setupTexture(ImageComponent imageComponent) {
+ Texture2D t2d = new Texture2D(Texture2D.BASE_LEVEL,
+ Texture.RGBA,
+ imageComponent.getWidth(),
+ imageComponent.getHeight());
+ t2d.setMinFilter(Texture2D.BASE_LEVEL_LINEAR);
+ t2d.setMagFilter(Texture2D.BASE_LEVEL_LINEAR);
+ t2d.setImage(0, imageComponent);
+ t2d.setEnable(true);
+ t2d.setCapability(Texture.ALLOW_IMAGE_WRITE);
+ t2d.setCapability(Texture.ALLOW_SIZE_READ);
+ t2d.setCapability(Texture.ALLOW_ENABLE_READ);
+ t2d.setCapability(Texture.ALLOW_BOUNDARY_MODE_READ);
+ t2d.setCapability(Texture.ALLOW_FILTER_READ);
+ t2d.setCapability(Texture.ALLOW_BOUNDARY_COLOR_READ);
+ t2d.setCapability(Texture.ALLOW_ANISOTROPIC_FILTER_READ);
+ t2d.setCapability(Texture.ALLOW_FILTER4_READ);
+ return t2d;
+ }
+
+ /**
+ * Creates a ImageComponent2D of the correct dimensions for the
+ * given font attributes. Draw the given text into the image in
+ * the given color. The background of the image is transparent
+ * (alpha = 0).
+ */
+ private ImageComponent setupImage(String text, Color3f color,
+ String fontName,
+ int fontSize, int fontStyle) {
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ Font font = new java.awt.Font(fontName, fontStyle, fontSize);
+
+ FontMetrics metrics;
+ if ((metrics = (FontMetrics)metricsTable.get(font)) == null) {
+ metrics = toolkit.getFontMetrics(font);
+ metricsTable.put(font, metrics);
+ }
+ int width = metrics.stringWidth(text);
+ int descent = metrics.getMaxDescent();
+ int ascent = metrics.getMaxAscent();
+ int leading = metrics.getLeading();
+ int height = descent + ascent;
+
+ // Need to make width/height powers of 2 because of Java3d texture
+ // size restrictions
+ int pow = 1;
+ for (int i = 1; i < 32; ++i) {
+ pow *= 2;
+ if (width <= pow)
+ break;
+ }
+ width = Math.max (width, pow);
+ pow = 1;
+ for (int i = 1; i < 32; ++i) {
+ pow *= 2;
+ if (height <= pow)
+ break;
+ }
+ height = Math.max (height, pow);
+
+ // For now, jdk 1.2 only handles ARGB format, not the RGBA we want
+ BufferedImage bImage = new BufferedImage(width, height,
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics2D offscreenGraphics = bImage.createGraphics();
+
+ // First, erase the background to the text panel - set alpha to 0
+ Color myFill = new Color(0f, 0f, 0f, 0f);
+ offscreenGraphics.setColor(myFill);
+ offscreenGraphics.fillRect(0, 0, width, height);
+
+ // Next, set desired text properties (font, color) and draw String
+ offscreenGraphics.setFont(font);
+ Color myTextColor = new Color(color.x, color.y, color.z, 1f);
+ offscreenGraphics.setColor(myTextColor);
+ offscreenGraphics.drawString(text, 0, height - descent);
+ offscreenGraphics.dispose();
+ //store virtual size
+ vWidth = width;
+ vHeight = height;
+ // rescale down big images
+ if(width > MAX_TEXTURE_DIM || height > MAX_TEXTURE_DIM){
+ bImage = rescaleImage(bImage);
+ }
+
+ ImageComponent imageComponent =
+ new ImageComponent2D(ImageComponent.FORMAT_RGBA,
+ bImage);
+
+ imageComponent.setCapability(ImageComponent.ALLOW_SIZE_READ);
+
+ return imageComponent;
+ }
+ // rescale image
+ private BufferedImage rescaleImage(BufferedImage bImage){
+ int width = bImage.getWidth();
+ int height = bImage.getHeight();
+
+ float sx = (width > MAX_TEXTURE_DIM) ? (float) MAX_TEXTURE_DIM / (float)width : 1.0f;
+ float sy = (height > MAX_TEXTURE_DIM)? (float) MAX_TEXTURE_DIM / (float)height : 1.0f;
+
+ width = Math.round((float) width * sx);
+ height = Math.round((float)height * sy);
+
+ Image scaledImage = bImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
+ bImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = bImage.createGraphics();
+ g.drawImage(scaledImage, 0,0, null);
+ g.dispose();
+
+ return bImage;
+ }
+
+ /**
+ * Creates a rectangle of the given width and height and sets up
+ * texture coordinates to map the text image onto the whole surface
+ * of the rectangle (the rectangle is the same size as the text image)
+ */
+ private QuadArray setupGeometry(int width, int height) {
+ float zPosition = 0f;
+ float rectWidth = (float)width * rectangleScaleFactor;
+ float rectHeight = (float)height * rectangleScaleFactor;
+ float[] verts1 = {
+ rectWidth, 0f, zPosition,
+ rectWidth, rectHeight, zPosition,
+ 0f, rectHeight, zPosition,
+ 0f, 0f, zPosition
+ };
+ float[] texCoords = {
+ 0f, -1f,
+ 0f, 0f,
+ (-1f), 0f,
+ (-1f), -1f
+ };
+
+ QuadArray rect = new QuadArray(4, QuadArray.COORDINATES |
+ QuadArray.TEXTURE_COORDINATE_2);
+ rect.setCoordinates(0, verts1);
+ rect.setTextureCoordinates(0, 0, texCoords);
+
+ return rect;
+ }
+
+ /**
+ * Creates Appearance for this Shape3D. This sets transparency
+ * for the object (we want the text to be "floating" in space,
+ * so only the text itself should be non-transparent. Also, the
+ * appearance disables lighting for the object; the text will
+ * simply be colored, not lit.
+ */
+ private Appearance setupAppearance(Texture2D t2d) {
+ Appearance appearance = getAppearance();
+
+ if (appearance == null) {
+ TransparencyAttributes transp = new TransparencyAttributes();
+ transp.setTransparencyMode(TransparencyAttributes.BLENDED);
+ transp.setTransparency(0f);
+ appearance = new Appearance();
+ appearance.setTransparencyAttributes(transp);
+ appearance.setTexture(t2d);
+
+ Material m = new Material();
+ m.setLightingEnable(false);
+ appearance.setMaterial(m);
+ appearance.setCapability(Appearance.ALLOW_TEXTURE_WRITE);
+ appearance.setCapability(Appearance.ALLOW_TEXTURE_READ);
+ appearance.setCapabilityIsFrequent(Appearance.ALLOW_TEXTURE_READ);
+ }else{
+ appearance.setTexture(t2d);
+ }
+
+ return appearance;
+ }
+
+ /**
+ * Returns the text string
+ *
+ * @since Java 3D 1.2.1
+ */
+ public String getString() {
+ return text;
+ }
+
+ /**
+ * Returns the color of the text
+ *
+ * @since Java 3D 1.2.1
+ */
+ public Color3f getColor() {
+ return color;
+ }
+
+ /**
+ * Returns the font
+ *
+ * @since Java 3D 1.2.1
+ */
+ public String getFontName() {
+ return fontName;
+ }
+
+ /**
+ * Returns the font size
+ *
+ * @since Java 3D 1.2.1
+ */
+ public int getFontSize() {
+ return fontSize;
+ }
+
+ /**
+ * Returns the font style
+ *
+ * @since Java 3D 1.2.1
+ */
+ public int getFontStyle() {
+ return fontStyle;
+ }
+
+}
+
+
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Triangle.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Triangle.java
new file mode 100644
index 0000000..7cd5ad4
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Triangle.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+class Triangle extends Object {
+ int v1, v2, v3; // This store the index into the list array.
+ // Not the index into vertex pool yet!
+
+ Triangle(int a, int b, int c) {
+ v1=a; v2=b; v3=c;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/Triangulator.java b/src/classes/share/org/jogamp/java3d/utils/geometry/Triangulator.java
new file mode 100644
index 0000000..85ece04
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/Triangulator.java
@@ -0,0 +1,1047 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+// ----------------------------------------------------------------------
+//
+// The reference to Fast Industrial Strength Triangulation (FIST) code
+// in this release by Sun Microsystems is related to Sun's rewrite of
+// an early version of FIST. FIST was originally created by Martin
+// Held and Joseph Mitchell at Stony Brook University and is
+// incorporated by Sun under an agreement with The Research Foundation
+// of SUNY (RFSUNY). The current version of FIST is available for
+// commercial use under a license agreement with RFSUNY on behalf of
+// the authors and Stony Brook University. Please contact the Office
+// of Technology Licensing at Stony Brook, phone 631-632-9009, for
+// licensing information.
+//
+// ----------------------------------------------------------------------
+
+package org.jogamp.java3d.utils.geometry;
+
+import java.util.Random;
+
+import org.jogamp.vecmath.Point2f;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Vector3f;
+
+import org.jogamp.java3d.internal.J3dUtilsI18N;
+
+/**
+ * Triangulator is a utility for turning arbitrary polygons into triangles
+ * so they can be rendered by Java 3D.
+ * Polygons can be concave, nonplanar, and can contain holes.
+ * @see GeometryInfo
+ */
+public class Triangulator extends Object {
+
+ GeometryInfo gInfo = null;
+
+ int faces[] = null;
+ int loops[] = null;
+ int chains[] = null;
+ Point2f points[] = null;
+ Triangle triangles[] = null;
+ ListNode list[] = null;
+
+ Random randomGen = null;
+
+ int numPoints = 0;
+ int maxNumPoints = 0;
+ int numList = 0;
+ int maxNumList = 0;
+ int numLoops = 0;
+ int maxNumLoops = 0;
+ int numTriangles = 0;
+ int maxNumTriangles = 0;
+
+ int numFaces = 0;
+ int numTexSets = 0;
+ // int maxNumFaces = 0;
+
+ int firstNode = 0;
+
+ int numChains = 0;
+ int maxNumChains = 0;
+
+ // For Clean class.
+ Point2f[] pUnsorted = null;
+ int maxNumPUnsorted = 0;
+
+ // For NoHash class.
+ boolean noHashingEdges = false;
+ boolean noHashingPnts = false;
+ int loopMin, loopMax;
+ PntNode vtxList[] = null;
+ int numVtxList = 0;
+ int numReflex = 0;
+ int reflexVertices;
+
+ // For Bridge class.
+ Distance distances[] = null;
+ int maxNumDist = 0;
+ Left leftMost[] = null;
+ int maxNumLeftMost = 0;
+
+ // For Heap class.
+ HeapNode heap[] = null;
+ int numHeap = 0;
+ int maxNumHeap = 0;
+ int numZero = 0;
+
+ // For Orientation class.
+ int maxNumPolyArea = 0;
+ double polyArea[] = null;
+
+ int stripCounts[] = null;
+ int vertexIndices[] = null;
+ Point3f vertices[] = null;
+ Object colors[] = null;
+ Vector3f normals[] = null;
+
+ boolean ccwLoop = true;
+
+ boolean earsRandom = true;
+ boolean earsSorted = true;
+
+ int identCntr; // Not sure what is this for. (Ask Martin)
+
+ // double epsilon = 1.0e-12;
+ double epsilon = 1.0e-12;
+
+ static final double ZERO = 1.0e-8;
+ static final int EARS_SEQUENCE = 0;
+ static final int EARS_RANDOM = 1;
+ static final int EARS_SORTED = 2;
+
+
+ static final int INC_LIST_BK = 100;
+ static final int INC_LOOP_BK = 20;
+ static final int INC_TRI_BK = 50;
+ static final int INC_POINT_BK = 100;
+ static final int INC_DIST_BK = 50;
+
+ private static final int DEBUG = 0;
+
+ /**
+ * Creates a new instance of the Triangulator.
+ * @deprecated This class is created automatically when needed in
+ * GeometryInfo and never needs to be used directly. Putting data
+ * into a GeometryInfo with primitive POLYGON_ARRAY automatically
+ * causes the triangulator to be created and used.
+ */
+ public Triangulator() {
+ earsRandom = false;
+ earsSorted = false;
+ }
+
+ /**
+ * Creates a new instance of a Triangulator.
+ * @deprecated This class is created automatically when needed in
+ * GeometryInfo and never needs to be used directly. Putting data
+ * into a GeometryInfo with primitive POLYGON_ARRAY automatically
+ * causes the triangulator to be created and used.
+ */
+ public Triangulator(int earOrder) {
+ switch(earOrder) {
+ case EARS_SEQUENCE:
+ earsRandom = false;
+ earsSorted = false;
+ break;
+ case EARS_RANDOM:
+ randomGen = new Random();
+ earsRandom = true;
+ earsSorted = false;
+ break;
+ case EARS_SORTED:
+ earsRandom = false;
+ earsSorted = true;
+ break;
+ default:
+ earsRandom = false;
+ earsSorted = false;
+ }
+
+ }
+
+ /**
+ * This routine converts the GeometryInfo object from primitive type
+ * POLYGON_ARRAY to primitive type TRIANGLE_ARRAY using polygon
+ * decomposition techniques.
+ *
+ * Example of usage:
+ * Triangulator tr = new Triangulator();
+ * tr.triangulate(ginfo); // ginfo contains the geometry.
+ * shape.setGeometry(ginfo.getGeometryArray()); // shape is a Shape3D.
+ *
+ * @param gi Geometry to be triangulated
+ **/
+ public void triangulate(GeometryInfo gi) {
+ int i, j, k;
+ int sIndex = 0, index, currLoop, lastInd, ind;
+ boolean proceed;
+ boolean reset = false, troubles = false;
+
+ boolean done[] = new boolean[1];
+ boolean gotIt[] = new boolean[1];
+
+ if (gi.getPrimitive() != GeometryInfo.POLYGON_ARRAY){
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("Triangulator0"));
+ }
+
+ gi.indexify();
+
+ vertices = gi.getCoordinates();
+ if(vertices != null)
+ vertexIndices = gi.getCoordinateIndices();
+ else
+ vertexIndices = null;
+
+ colors = gi.getColors();
+ normals = gi.getNormals();
+ this.gInfo= gi;
+
+
+ stripCounts = gi.getStripCounts();
+
+ faces = gi.getContourCounts();
+ if(faces == null) {
+ if(stripCounts == null)
+ System.out.println("StripCounts is null! Don't know what to do.");
+
+ faces = new int[stripCounts.length];
+ for(i=0; i
+ *
+ *
+ * @since Java 3D 1.5
+ */
+public class CompressedGeometryData extends Object {
+
+ private Header cgHeader;
+ private CompressedGeometryRetained retained;
+
+
+ /**
+ * Creates a new CompressedGeometryData object by copying
+ * the specified compressed geometry data into this object.
+ * If the version number of compressed geometry, as specified by
+ * the Header, is incompatible with the
+ * supported version of compressed geometry, then an exception
+ * will be thrown.
+ *
+ * @param hdr the compressed geometry header. This is copied
+ * into this CompressedGeometryData object.
+ *
+ * @param compressedGeometry the compressed geometry data. The
+ * geometry must conform to the format described in Appendix B of
+ * the Java 3D API Specification.
+ *
+ * @exception IllegalArgumentException if a problem is detected with the
+ * header.
+ */
+ public CompressedGeometryData(Header hdr,
+ byte[] compressedGeometry) {
+
+ this(hdr, compressedGeometry, false);
+ }
+
+ /**
+ * Creates a new CompressedGeometryData object. The
+ * specified compressed geometry data is either copied into this
+ * object or is accessed by reference.
+ * If the version number of compressed geometry, as specified by
+ * the Header, is incompatible with the
+ * supported version of compressed geometry, then an exception
+ * will be thrown.
+ *
+ * @param hdr the compressed geometry header. This is copied
+ * into the CompressedGeometryData object.
+ *
+ * @param compressedGeometry the compressed geometry data. The
+ * geometry must conform to the format described in Appendix B of
+ * the Java 3D API Specification.
+ *
+ * @param byReference a flag that indicates whether the data is copied
+ * into this compressed geometry object or is accessed by reference.
+ *
+ * @exception IllegalArgumentException if a problem is detected with the
+ * header.
+ */
+ public CompressedGeometryData(Header hdr,
+ byte[] compressedGeometry,
+ boolean byReference) {
+
+ if ((hdr.size + hdr.start) > compressedGeometry.length) {
+ throw new IllegalArgumentException(J3dUtilsI18N.getString("CompressedGeometry0"));
+ }
+
+ // Create a separate copy of the given header.
+ cgHeader = new Header();
+ hdr.copy(cgHeader);
+
+ // Create the retained object.
+ retained = new CompressedGeometryRetained();
+ this.retained.createCompressedGeometry(cgHeader, compressedGeometry, byReference);
+
+ // This constructor is designed to accept byte arrays that may contain
+ // possibly many large compressed geometry blocks interspersed with
+ // non-J3D-specific metadata. Only one of these blocks is used per
+ // CompressedGeometry object, so set the geometry offset to zero in
+ // the header if the data itself is copied.
+ if (!byReference)
+ cgHeader.start = 0;
+ }
+
+ /**
+ * Creates a new CompressedGeometryData object. The
+ * specified compressed geometry data is accessed by reference
+ * from the specified buffer.
+ * If the version number of compressed geometry, as specified by
+ * the Header, is incompatible with the
+ * supported version of compressed geometry, then an exception
+ * will be thrown.
+ *
+ * @param hdr the compressed geometry header. This is copied
+ * into the CompressedGeometryData object.
+ *
+ * @param compressedGeometry a buffer containing an NIO byte buffer
+ * of compressed geometry data. The
+ * geometry must conform to the format described in Appendix B of
+ * the Java 3D API Specification.
+ *
+ * @exception UnsupportedOperationException this method is not
+ * yet implemented
+ *
+ * @exception IllegalArgumentException if a problem is detected with the
+ * header,
+ * or if the java.nio.Buffer contained in the specified J3DBuffer
+ * is not a java.nio.ByteBuffer object.
+ *
+ * @see Header
+ */
+ public CompressedGeometryData(Header hdr,
+ J3DBuffer compressedGeometry) {
+
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+
+ /**
+ * Returns the size, in bytes, of the compressed geometry buffer.
+ * The size of the compressed geometry header is not included.
+ *
+ * @return the size, in bytes, of the compressed geometry buffer.
+ */
+ public int getByteCount() {
+ return cgHeader.size;
+ }
+
+ /**
+ * Copies the compressed geometry header from the CompressedGeometryData
+ * object into the passed in parameter.
+ *
+ * @param hdr the Header object into which to copy the
+ * CompressedGeometryData object's header; the offset field may differ
+ * from that which was originally specified if a copy of the original
+ * compressed geometry byte array was created.
+ */
+ public void getCompressedGeometryHeader(Header hdr) {
+ cgHeader.copy(hdr);
+ }
+
+ /**
+ * Retrieves the compressed geometry associated with the
+ * CompressedGeometryData object. Copies the compressed
+ * geometry from the CompressedGeometryData node into the given array.
+ * The array must be large enough to hold all of the bytes.
+ * The individual array elements must be allocated by the caller.
+ *
+ * @param compressedGeometry the array into which to copy the compressed
+ * geometry.
+ *
+ * @exception IllegalStateException if the data access mode for this
+ * object is by-reference.
+ *
+ * @exception ArrayIndexOutOfBoundsException if compressedGeometry byte
+ * array is not large enough to receive the compressed geometry
+ */
+ public void getCompressedGeometry(byte[] compressedGeometry) {
+ if (isByReference()) {
+ throw new IllegalStateException(
+ J3dUtilsI18N.getString("CompressedGeometry7"));
+ }
+
+ if (cgHeader.size > compressedGeometry.length) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dUtilsI18N.getString("CompressedGeometry4"));
+ }
+
+ this.retained.copy(compressedGeometry);
+ }
+
+ /**
+ * Decompresses the compressed geometry. Returns an array of Shape nodes
+ * containing the decompressed geometry objects, or null if the version
+ * number of the compressed geometry is incompatible with the decompressor
+ * in the current version of Java 3D.
+ *
+ * @return an array of Shape nodes containing the
+ * geometry decompressed from this CompressedGeometryData
+ * object, or null if its version is incompatible
+ */
+ public Shape3D[] decompress() {
+ CompressedGeometryRetained cgr = this.retained;
+
+ GeometryDecompressorShape3D decompressor =
+ new GeometryDecompressorShape3D();
+
+ // Decompress the geometry as TriangleStripArrays. A combination of
+ // TriangleStripArrays and TrianglesFanArrays is more compact but
+ // requires twice as many Shape3D objects, resulting in slower
+ // rendering performance.
+ //
+ // Using TriangleArray output is currently the fastest, given the
+ // strip sizes observed from various compressed geometry objects, but
+ // produces about twice as many vertices. TriangleStripArray produces
+ // the same number of Shape3D objects as TriangleArray using 1/2
+ // to 2/3 of the vertices, with only a marginal performance penalty.
+ //
+ return decompressor.toTriangleStripArrays(cgr);
+ }
+
+
+ /**
+ * Retrieves the data access mode for this CompressedGeometryData object.
+ *
+ * @return byReference
flag
+ * set to true
. In this mode, a reference to the input
+ * data is saved, but the data itself is not necessarily copied. Note
+ * that the compressed geometry header is still copied into this
+ * compressed geometry object. Data referenced by a
+ * CompressedGeometryData object must not be modified after the
+ * CompressedGeometryData object is constructed.
+ * Applications
+ * must exercise care not to violate this rule. If any referenced
+ * compressed geometry data is modified after construction,
+ * the results are undefined.
+ * true
if the data access mode for this
+ * CompressedGeometryData object is by-reference;
+ * false
if the data access mode is by-copying.
+ */
+ public boolean isByReference() {
+ return this.retained.isByReference();
+ }
+
+
+ /**
+ * Gets the compressed geometry data reference.
+ *
+ * @return the current compressed geometry data reference.
+ *
+ * @exception IllegalStateException if the data access mode for this
+ * object is not by-reference.
+ */
+ public byte[] getCompressedGeometryRef() {
+ if (!isByReference()) {
+ throw new IllegalStateException(
+ J3dUtilsI18N.getString("CompressedGeometry8"));
+ }
+
+ return this.retained.getReference();
+ }
+
+
+ /**
+ * Gets the compressed geometry data buffer reference, which is
+ * always null since NIO buffers are not supported for
+ * CompressedGeometryData objects.
+ *
+ * @return null
+ */
+ public J3DBuffer getCompressedGeometryBuffer() {
+ return null;
+ }
+
+
+ /**
+ * The Header class is a data container for the header information,
+ * used in conjunction with a CompressedGeometryData object.
+ * This information is used to aid the decompression of the compressed geometry.
+ *
+ * size
bytes of compressed geometry data are copied from the
+ * offset indicated by start
instead of copying the entire
+ * byte array. The getCompressedGeometry() method will return only the
+ * bytes used to construct the object, and the getCompressedGeometryHeader()
+ * method will return a header with the start
field set to 0.
+ */
+ public int start;
+
+ /**
+ * A point that defines the lower bound of the x,
+ * y, and z components for all positions in the
+ * compressed geometry buffer. If null, a lower bound of
+ * (-1,-1,-1) is assumed. Java 3D will use this information to
+ * construct a bounding box around compressed geometry objects
+ * that are used in nodes for which the auto compute bounds flag
+ * is true. The default value for this point is null.
+ */
+ public Point3d lowerBound = null;
+
+ /**
+ * A point that defines the upper bound of the x,
+ * y, and z components for all positions in the
+ * compressed geometry buffer. If null, an upper bound of (1,1,1)
+ * is assumed. Java 3D will use this information to construct a
+ * bounding box around compressed geometry objects that are used
+ * in nodes for which the auto compute bounds flag is true. The
+ * default value for this point is null.
+ */
+ public Point3d upperBound = null;
+
+ /**
+ * Creates a new Header object used for the
+ * creation of a CompressedGeometryData object.
+ * All instance data is declared public and no get or set methods are
+ * provided. All values are set to 0 by default and must be filled
+ * in by the application.
+ *
+ * @see CompressedGeometryData
+ */
+ public Header() {
+ }
+
+ /**
+ * Package-scoped method to copy current Header object
+ * to the passed-in Header object.
+ *
+ * @param hdr the Header object into which to copy the
+ * current Header.
+ */
+ void copy(Header hdr) {
+ hdr.majorVersionNumber = this.majorVersionNumber;
+ hdr.minorVersionNumber = this.minorVersionNumber;
+ hdr.minorMinorVersionNumber = this.minorMinorVersionNumber;
+ hdr.bufferType = this.bufferType;
+ hdr.bufferDataPresent = this.bufferDataPresent;
+ hdr.size = this.size;
+ hdr.start = this.start;
+ hdr.lowerBound = this.lowerBound;
+ hdr.upperBound = this.upperBound;
+ }
+
+ /**
+ * Returns a String describing the contents of the
+ * Header object.
+ *
+ * @return a String describing contents of the compressed geometry header
+ */
+ @Override
+ public String toString() {
+ String type = "UNKNOWN";
+ switch (bufferType) {
+ case POINT_BUFFER: type = "POINT_BUFFER"; break;
+ case LINE_BUFFER: type = "LINE_BUFFER"; break;
+ case TRIANGLE_BUFFER: type = "TRIANGLE_BUFFER"; break;
+ }
+
+ String data = "";
+ if ((bufferDataPresent & NORMAL_IN_BUFFER) != 0)
+ data = data + "NORMALS ";
+ if ((bufferDataPresent & COLOR_IN_BUFFER) != 0)
+ data = data + "COLORS ";
+ if ((bufferDataPresent & ALPHA_IN_BUFFER) != 0)
+ data = data + "ALPHA ";
+
+ String lbound = "null";
+ if (lowerBound != null)
+ lbound = lowerBound.toString();
+
+ String ubound = "null";
+ if (upperBound != null)
+ ubound = upperBound.toString();
+
+ return
+ "majorVersionNumber: " + majorVersionNumber + " " +
+ "minorVersionNumber: " + minorVersionNumber + " " +
+ "minorMinorVersionNumber: " + minorMinorVersionNumber + "\n" +
+ "bufferType: " + type + " " +
+ "bufferDataPresent: " + data + "\n" +
+ "size: " + size + " " +
+ "start: " + start + "\n" +
+ "lower bound: " + lbound + "\n" +
+ "upper bound: " + ubound + " ";
+ }
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressedGeometryFile.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressedGeometryFile.java
new file mode 100644
index 0000000..9b27ae3
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressedGeometryFile.java
@@ -0,0 +1,1009 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import org.jogamp.java3d.CapabilityNotSetException;
+
+//
+// The compressed geometry file format supported by this class has a 32
+// byte header followed by multiple compressed geometry objects.
+//
+// Each object consists of a block of compressed data and an 8-byte
+// individual block header describing its contents.
+//
+// The file ends with a directory data structure used for random access,
+// containing a 64-bit offset for each object in the order in which it
+// appears in the file. This is also used to find the size of the largest
+// object in the file and must be present.
+//
+
+/**
+ * This class provides methods to read and write compressed geometry resource
+ * files. These files usually end with the .cg extension and support
+ * sequential as well as random access to multiple compressed geometry
+ * objects.
+ *
+ * @since Java 3D 1.5
+ */
+public class CompressedGeometryFile {
+ private static final boolean print = false ;
+ private static final boolean benchmark = false ;
+
+ /**
+ * The magic number which identifies the compressed geometry file type.
+ */
+ static final int MAGIC_NUMBER = 0xbaddfab4 ;
+
+ /**
+ * Byte offset of the magic number from start of file.
+ */
+ static final int MAGIC_NUMBER_OFFSET = 0 ;
+
+ /**
+ * Byte offset of the major version number from start of file.
+ */
+ static final int MAJOR_VERSION_OFFSET = 4 ;
+
+ /**
+ * Byte offset of the minor version number from start of file.
+ */
+ static final int MINOR_VERSION_OFFSET = 8 ;
+
+ /**
+ * Byte offset of the minor minor version number from start of file.
+ */
+ static final int MINOR_MINOR_VERSION_OFFSET = 12 ;
+
+ /**
+ * Byte offset of the number of objects from start of file.
+ */
+ static final int OBJECT_COUNT_OFFSET = 16 ;
+
+ /**
+ * Byte offset of the directory offset from start of file.
+ * This offset is long word aligned since the directory offset is a long.
+ */
+ static final int DIRECTORY_OFFSET_OFFSET = 24 ;
+
+ /**
+ * File header total size in bytes.
+ */
+ static final int HEADER_SIZE = 32 ;
+
+ /**
+ * Byte offset of the object size from start of individual compressed
+ * geometry block.
+ */
+ static final int OBJECT_SIZE_OFFSET = 0 ;
+
+ /**
+ * Byte offset of the compressed geometry data descriptor from start of
+ * individual compressed geometry block.
+ */
+ static final int GEOM_DATA_OFFSET = 4 ;
+
+ /**
+ * Bits in compressed geometry data descriptor which encode the buffer type.
+ */
+ static final int TYPE_MASK = 0x03 ;
+
+ /**
+ * Bit in compressed geometry data descriptor encoding presence of normals.
+ */
+ static final int NORMAL_PRESENT_MASK = 0x04 ;
+
+ /**
+ * Bit in compressed geometry data descriptor encoding presence of colors.
+ */
+ static final int COLOR_PRESENT_MASK = 0x08 ;
+
+ /**
+ * Bit in compressed geometry data descriptor encoding presence of alphas.
+ */
+ static final int ALPHA_PRESENT_MASK = 0x10 ;
+
+ /**
+ * Value in compressed geometry data descriptor for a point buffer type.
+ */
+ static final int TYPE_POINT = 1 ;
+
+ /**
+ * Value in compressed geometry data descriptor for a line buffer type.
+ */
+ static final int TYPE_LINE = 2 ;
+
+ /**
+ * Value in compressed geometry data descriptor for a triangle buffer type.
+ */
+ static final int TYPE_TRIANGLE = 3 ;
+
+ /**
+ * Block header total size in bytes.
+ */
+ static final int BLOCK_HEADER_SIZE = 8 ;
+
+ // The name of the compressed geometry resource file.
+ String fileName = null ;
+
+ // The major, minor, and subminor version number of the most recent
+ // compressor used to compress any of the objects in the compressed
+ // geometry resource file.
+ int majorVersionNumber ;
+ int minorVersionNumber ;
+ int minorMinorVersionNumber ;
+
+ // The number of objects in the compressed geometry resource file.
+ int objectCount ;
+
+ // The index of the current object in the file.
+ int objectIndex = 0 ;
+
+ // The random access file associated with this instance.
+ RandomAccessFile cgFile = null ;
+
+ // The magic number identifying the file type.
+ int magicNumber ;
+
+ // These fields are set from each individual block of compressed geometry.
+ byte cgBuffer[] ;
+ int geomSize ;
+ int geomStart ;
+ int geomDataType ;
+
+ // The directory of object offsets is read from the end of the file.
+ long directory[] ;
+ long directoryOffset ;
+
+ // The object sizes are computed from the directory offsets. These are
+ // used to allocate a buffer large enough to hold the largest object and
+ // to determine how many consecutive objects can be read into that buffer.
+ int objectSizes[] ;
+ int bufferObjectStart ;
+ int bufferObjectCount ;
+ int bufferNextObjectCount ;
+ int bufferNextObjectOffset ;
+
+ // The shared compressed geometry header object.
+ CompressedGeometryData.Header cgh ;
+
+ // Flag indicating file update.
+ boolean fileUpdate = false ;
+
+ /**
+ * Construct a new CompressedGeometryFile instance associated with the
+ * specified file. An attempt is made to open the file with read-only
+ * access; if this fails then a FileNotFoundException is thrown.
+ *
+ * @param file path to the compressed geometry resource file
+ * @exception FileNotFoundException if file doesn't exist or
+ * cannot be read
+ * @exception IllegalArgumentException if the file is not a compressed
+ * geometry resource file
+ * @exception IOException if there is a header or directory read error
+ */
+ public CompressedGeometryFile(String file) throws IOException {
+ this(file, false) ;
+ }
+
+ /**
+ * Construct a new CompressedGeometryFile instance associated with the
+ * specified file.
+ *
+ * @param file path to the compressed geometry resource file
+ * @param rw if true, opens the file for read and write access or attempts
+ * to create one if it doesn't exist; if false, opens the file with
+ * read-only access
+ * @exception FileNotFoundException if file doesn't exist or
+ * access permissions disallow access
+ * @exception IllegalArgumentException if the file is not a compressed
+ * geometry resource file
+ * @exception IOException if there is a header or directory read error
+ */
+ public CompressedGeometryFile(String file, boolean rw) throws IOException {
+ // Open the file and read the file header.
+ open(file, rw) ;
+
+ // Copy the file name.
+ fileName = new String(file) ;
+
+ // Set up the file fields.
+ initialize() ;
+ }
+
+ /**
+ * Construct a new CompressedGeometryFile instance associated with a
+ * currently open RandomAccessFile.
+ *
+ * @param file currently open RandomAccessFile
+ * @exception IllegalArgumentException if the file is not a compressed
+ * geometry resource file
+ * @exception IOException if there is a header or directory read error
+ */
+ public CompressedGeometryFile(RandomAccessFile file) throws IOException {
+ // Copy the file reference.
+ cgFile = file ;
+
+ // Set up the file fields.
+ initialize() ;
+ }
+
+ /**
+ * Delete all compressed objects from this instance. This method may only
+ * be called after successfully creating a CompressedGeometryFile instance
+ * with read-write access, so a corrupted or otherwise invalid resource
+ * must be removed manually before it can be rewritten. The close()
+ * method must be called sometime after invoking clear() in order to write
+ * out the new directory structure.
+ *
+ * @exception IOException if clear fails
+ */
+ public void clear() throws IOException {
+ // Truncate the file.
+ cgFile.setLength(0) ;
+
+ // Set up the file fields.
+ initialize() ;
+ }
+
+ /**
+ * Return a string containing the file name associated with this instance
+ * or null if there is none.
+ *
+ * @return file name associated with this instance or null if there is
+ * none
+ */
+ public String getFileName() {
+ return fileName ;
+ }
+
+ /**
+ * Return the major version number of the most recent compressor used to
+ * compress any of the objects in this instance.
+ *
+ * @return major version number
+ */
+ public int getMajorVersionNumber() {
+ return majorVersionNumber ;
+ }
+
+ /**
+ * Return the minor version number of the most recent compressor used to
+ * compress any of the objects in this instance.
+ *
+ * @return minor version number
+ */
+ public int getMinorVersionNumber() {
+ return minorVersionNumber ;
+ }
+
+ /**
+ * Return the subminor version number of the most recent compressor used to
+ * compress any of the objects in this instance.
+ *
+ * @return subminor version number
+ */
+ public int getMinorMinorVersionNumber() {
+ return minorMinorVersionNumber ;
+ }
+
+ /**
+ * Return the number of compressed objects in this instance.
+ *
+ * @return number of compressed objects
+ */
+ public int getObjectCount() {
+ return objectCount ;
+ }
+
+ /**
+ * Return the current object index associated with this instance. This is
+ * the index of the object that would be returned by an immediately
+ * following call to the readNext() method. Its initial value is 0; -1
+ * is returned if the last object has been read.
+ *
+ * @return current object index, or -1 if at end
+ */
+ public int getCurrentIndex() {
+ if (objectIndex == objectCount)
+ return -1 ;
+ else
+ return objectIndex ;
+ }
+
+ /**
+ * Read the next compressed geometry object in the instance. This is
+ * initially the first object (index 0) in the instance; otherwise, it is
+ * whatever object is next after the last one read. The current object
+ * index is incremented by 1 after the read. When the last object is read
+ * the index becomes invalid and an immediately subsequent call to
+ * readNext() returns null.
+ *
+ *
+ * @return a CompressedGeometryData node component, or null if the last object
+ * has been read
+ * @exception IOException if read fails
+ */
+ public CompressedGeometryData readNext() throws IOException {
+ return readNext(cgBuffer.length) ;
+ }
+
+ /**
+ * Read all compressed geometry objects contained in the instance. The
+ * current object index becomes invalid; an immediately following call
+ * to readNext() will return null.
+ *
+ * @return an array of CompressedGeometryData node components.
+ * @exception IOException if read fails
+ */
+ public CompressedGeometryData[] read() throws IOException {
+ long startTime = 0 ;
+ CompressedGeometryData cg[] = new CompressedGeometryData[objectCount] ;
+
+ if (benchmark)
+ startTime = System.currentTimeMillis() ;
+
+ objectIndex = 0 ;
+ setFilePointer(directory[0]) ;
+ bufferNextObjectCount = 0 ;
+
+ for (int i = 0 ; i < objectCount ; i++)
+ cg[i] = readNext(cgBuffer.length) ;
+
+ if (benchmark) {
+ long t = System.currentTimeMillis() - startTime ;
+ System.out.println("read " + objectCount +
+ " objects " + cgFile.length() +
+ " bytes in " + (t/1000f) + " sec.") ;
+ System.out.println((cgFile.length()/(float)t) + " Kbytes/sec.") ;
+ }
+
+ return cg ;
+ }
+
+ /**
+ * Read the compressed geometry object at the specified index. The
+ * current object index is set to the subsequent object unless the last
+ * object has been read, in which case the index becomes invalid and an
+ * immediately following call to readNext() will return null.
+ *
+ * @param index compressed geometry object to read
+ * @return a CompressedGeometryData node component
+ * @exception IndexOutOfBoundsException if object index is
+ * out of range
+ * @exception IOException if read fails
+ */
+ public CompressedGeometryData read(int index) throws IOException {
+ objectIndex = index ;
+
+ if (objectIndex < 0) {
+ throw new IndexOutOfBoundsException
+ ("\nobject index must be >= 0") ;
+ }
+ if (objectIndex >= objectCount) {
+ throw new IndexOutOfBoundsException
+ ("\nobject index must be < " + objectCount) ;
+ }
+
+ // Check if object is in cache.
+ if ((objectIndex >= bufferObjectStart) &&
+ (objectIndex < bufferObjectStart + bufferObjectCount)) {
+ if (print) System.out.println("\ngetting object from cache\n") ;
+
+ bufferNextObjectOffset = (int)
+ (directory[objectIndex] - directory[bufferObjectStart]) ;
+
+ bufferNextObjectCount =
+ bufferObjectCount - (objectIndex - bufferObjectStart) ;
+
+ return readNext() ;
+
+ } else {
+ // Move file pointer to correct offset.
+ setFilePointer(directory[objectIndex]) ;
+
+ // Force a read from current offset. Disable cache read-ahead
+ // since cache hits are unlikely with random access.
+ bufferNextObjectCount = 0 ;
+ return readNext(objectSizes[objectIndex]) ;
+ }
+ }
+
+
+ /**
+ * Add a compressed geometry node component to the end of the instance.
+ * The current object index becomes invalid; an immediately following call
+ * to readNext() will return null. The close() method must be called at
+ * some later time in order to create a valid compressed geometry file.
+ *
+ * @param cg a compressed geometry node component
+ * @exception CapabilityNotSetException if unable to get compressed
+ * geometry data from the node component
+ * @exception IOException if write fails
+ */
+ public void write(CompressedGeometryData cg) throws IOException {
+ CompressedGeometryData.Header cgh = new CompressedGeometryData.Header() ;
+ cg.getCompressedGeometryHeader(cgh) ;
+
+ // Update the read/write buffer size if necessary.
+ if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) {
+ cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ;
+ if (print) System.out.println("\ncgBuffer: reallocated " +
+ (cgh.size+BLOCK_HEADER_SIZE) +
+ " bytes") ;
+ }
+
+ cg.getCompressedGeometry(cgBuffer) ;
+ write(cgh, cgBuffer) ;
+ }
+
+ /**
+ * Add a buffer of compressed geometry data to the end of the
+ * resource. The current object index becomes invalid; an immediately
+ * following call to readNext() will return null. The close() method must
+ * be called at some later time in order to create a valid compressed
+ * geometry file.
+ *
+ * @param cgh a CompressedGeometryData.Header object describing the data.
+ * @param geometry the compressed geometry data
+ * @exception IOException if write fails
+ */
+ public void write(CompressedGeometryData.Header cgh, byte geometry[])
+ throws IOException {
+
+ // Update the read/write buffer size if necessary. It won't be used
+ // in this method, but should be big enough to read any object in
+ // the file, including the one to be written.
+ if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) {
+ cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE] ;
+ if (print) System.out.println("\ncgBuffer: reallocated " +
+ (cgh.size+BLOCK_HEADER_SIZE) +
+ " bytes") ;
+ }
+
+ // Assuming backward compatibility, the version number of the file
+ // should be the maximum of all individual compressed object versions.
+ if ((cgh.majorVersionNumber > majorVersionNumber)
+ ||
+ ((cgh.majorVersionNumber == majorVersionNumber) &&
+ (cgh.minorVersionNumber > minorVersionNumber))
+ ||
+ ((cgh.majorVersionNumber == majorVersionNumber) &&
+ (cgh.minorVersionNumber == minorVersionNumber) &&
+ (cgh.minorMinorVersionNumber > minorMinorVersionNumber))) {
+
+ majorVersionNumber = cgh.majorVersionNumber ;
+ minorVersionNumber = cgh.minorVersionNumber ;
+ minorMinorVersionNumber = cgh.minorMinorVersionNumber ;
+
+ this.cgh.majorVersionNumber = cgh.majorVersionNumber ;
+ this.cgh.minorVersionNumber = cgh.minorVersionNumber ;
+ this.cgh.minorMinorVersionNumber = cgh.minorMinorVersionNumber ;
+ }
+
+ // Get the buffer type and see what vertex components are present.
+ int geomDataType = 0 ;
+
+ switch (cgh.bufferType) {
+ case CompressedGeometryData.Header.POINT_BUFFER:
+ geomDataType = TYPE_POINT ;
+ break ;
+ case CompressedGeometryData.Header.LINE_BUFFER:
+ geomDataType = TYPE_LINE ;
+ break ;
+ case CompressedGeometryData.Header.TRIANGLE_BUFFER:
+ geomDataType = TYPE_TRIANGLE ;
+ break ;
+ }
+
+ if ((cgh.bufferDataPresent &
+ CompressedGeometryData.Header.NORMAL_IN_BUFFER) != 0)
+ geomDataType |= NORMAL_PRESENT_MASK ;
+
+ if ((cgh.bufferDataPresent &
+ CompressedGeometryData.Header.COLOR_IN_BUFFER) != 0)
+ geomDataType |= COLOR_PRESENT_MASK ;
+
+ if ((cgh.bufferDataPresent &
+ CompressedGeometryData.Header.ALPHA_IN_BUFFER) != 0)
+ geomDataType |= ALPHA_PRESENT_MASK ;
+
+ // Allocate new directory and object size arrays if necessary.
+ if (objectCount == directory.length) {
+ long newDirectory[] = new long[2*objectCount] ;
+ int newObjectSizes[] = new int[2*objectCount] ;
+
+ System.arraycopy(directory, 0,
+ newDirectory, 0, objectCount) ;
+ System.arraycopy(objectSizes, 0,
+ newObjectSizes, 0, objectCount) ;
+
+ directory = newDirectory ;
+ objectSizes = newObjectSizes ;
+
+ if (print)
+ System.out.println("\ndirectory and size arrays: reallocated " +
+ (2*objectCount) + " entries") ;
+ }
+
+ // Update directory and object size array.
+ directory[objectCount] = directoryOffset ;
+ objectSizes[objectCount] = cgh.size + BLOCK_HEADER_SIZE ;
+ objectCount++ ;
+
+ // Seek to the directory and overwrite from there.
+ setFilePointer(directoryOffset) ;
+ cgFile.writeInt(cgh.size) ;
+ cgFile.writeInt(geomDataType) ;
+ cgFile.write(geometry, 0, cgh.size) ;
+ if (print)
+ System.out.println("\nwrote " + cgh.size +
+ " byte compressed object to " + fileName +
+ "\nfile offset " + directoryOffset) ;
+
+ // Update the directory offset.
+ directoryOffset += cgh.size + BLOCK_HEADER_SIZE ;
+
+ // Return end-of-file on next read.
+ objectIndex = objectCount ;
+
+ // Flag file update so close() will write out the directory.
+ fileUpdate = true ;
+ }
+
+ /**
+ * Release the resources associated with this instance.
+ * Write out final header and directory if contents were updated.
+ * This method must be called in order to create a valid compressed
+ * geometry resource file if any updates were made.
+ */
+ public void close() {
+ if (cgFile != null) {
+ try {
+ if (fileUpdate) {
+ writeFileDirectory() ;
+ writeFileHeader() ;
+ }
+ cgFile.close() ;
+ }
+ catch (IOException e) {
+ // Don't propagate this exception.
+ System.out.println("\nException: " + e.getMessage()) ;
+ System.out.println("failed to close " + fileName) ;
+ }
+ }
+ cgFile = null ;
+ cgBuffer = null ;
+ directory = null ;
+ objectSizes = null ;
+ }
+
+
+ //
+ // Open the file. Specifying a non-existent file creates a new one if
+ // access permissions allow.
+ //
+ void open(String fname, boolean rw)
+ throws FileNotFoundException, IOException {
+
+ cgFile = null ;
+ String mode ;
+
+ if (rw)
+ mode = "rw" ;
+ else
+ mode = "r" ;
+
+ try {
+ cgFile = new RandomAccessFile(fname, mode) ;
+ if (print) System.out.println("\n" + fname +
+ ": opened mode " + mode) ;
+ }
+ catch (FileNotFoundException e) {
+ // N.B. this exception is also thrown on access permission errors
+ throw new FileNotFoundException(e.getMessage() + "\n" + fname +
+ ": open mode " + mode + " failed") ;
+ }
+ }
+
+ //
+ // Seek to the specified offset in the file.
+ //
+ void setFilePointer(long offset) throws IOException {
+ cgFile.seek(offset) ;
+
+ // Reset number of objects that can be read sequentially from cache.
+ bufferNextObjectCount = 0 ;
+ }
+
+ //
+ // Initialize directory, object size array, read/write buffer, and the
+ // shared compressed geometry header.
+ //
+ void initialize() throws IOException {
+ int maxSize = 0 ;
+
+ if (cgFile.length() == 0) {
+ // New file for writing: allocate nominal initial sizes for arrays.
+ objectCount = 0 ;
+ cgBuffer = new byte[32768] ;
+ directory = new long[16] ;
+ objectSizes = new int[directory.length] ;
+
+ // Set fields as if they have been read.
+ magicNumber = MAGIC_NUMBER ;
+ majorVersionNumber = 1 ;
+ minorVersionNumber = 0 ;
+ minorMinorVersionNumber = 0 ;
+ directoryOffset = HEADER_SIZE ;
+
+ // Write the file header.
+ writeFileHeader() ;
+
+ } else {
+ // Read the file header.
+ readFileHeader() ;
+
+ // Check file type.
+ if (magicNumber != MAGIC_NUMBER) {
+ close() ;
+ throw new IllegalArgumentException
+ ("\n" + fileName + " is not a compressed geometry file") ;
+ }
+
+ // Read the directory and determine object sizes.
+ directory = new long[objectCount] ;
+ readDirectory(directoryOffset, directory) ;
+
+ objectSizes = new int[objectCount] ;
+ for (int i = 0 ; i < objectCount-1 ; i++) {
+ objectSizes[i] = (int)(directory[i+1] - directory[i]) ;
+ if (objectSizes[i] > maxSize) maxSize = objectSizes[i] ;
+ }
+
+ if (objectCount > 0) {
+ objectSizes[objectCount-1] =
+ (int)(directoryOffset - directory[objectCount-1]) ;
+
+ if (objectSizes[objectCount-1] > maxSize)
+ maxSize = objectSizes[objectCount-1] ;
+ }
+
+ // Allocate a buffer big enough to read the largest object.
+ cgBuffer = new byte[maxSize] ;
+
+ // Move to the first object.
+ setFilePointer(HEADER_SIZE) ;
+ }
+
+ // Set up common parts of the compressed geometry object header.
+ cgh = new CompressedGeometryData.Header() ;
+ cgh.majorVersionNumber = this.majorVersionNumber ;
+ cgh.minorVersionNumber = this.minorVersionNumber ;
+ cgh.minorMinorVersionNumber = this.minorMinorVersionNumber ;
+
+ if (print) {
+ System.out.println(fileName + ": " + objectCount + " objects") ;
+ System.out.println("magic number 0x" +
+ Integer.toHexString(magicNumber) +
+ ", version number " + majorVersionNumber +
+ "." + minorVersionNumber +
+ "." + minorMinorVersionNumber) ;
+ System.out.println("largest object is " + maxSize + " bytes") ;
+ }
+ }
+
+ //
+ // Read the file header.
+ //
+ void readFileHeader() throws IOException {
+ byte header[] = new byte[HEADER_SIZE] ;
+
+ try {
+ setFilePointer(0) ;
+ if (cgFile.read(header) != HEADER_SIZE) {
+ close() ;
+ throw new IOException("failed header read") ;
+ }
+ }
+ catch (IOException e) {
+ if (cgFile != null) {
+ close() ;
+ }
+ throw e ;
+ }
+
+ magicNumber =
+ ((header[MAGIC_NUMBER_OFFSET+0] & 0xff) << 24) |
+ ((header[MAGIC_NUMBER_OFFSET+1] & 0xff) << 16) |
+ ((header[MAGIC_NUMBER_OFFSET+2] & 0xff) << 8) |
+ ((header[MAGIC_NUMBER_OFFSET+3] & 0xff)) ;
+
+ majorVersionNumber =
+ ((header[MAJOR_VERSION_OFFSET+0] & 0xff) << 24) |
+ ((header[MAJOR_VERSION_OFFSET+1] & 0xff) << 16) |
+ ((header[MAJOR_VERSION_OFFSET+2] & 0xff) << 8) |
+ ((header[MAJOR_VERSION_OFFSET+3] & 0xff)) ;
+
+ minorVersionNumber =
+ ((header[MINOR_VERSION_OFFSET+0] & 0xff) << 24) |
+ ((header[MINOR_VERSION_OFFSET+1] & 0xff) << 16) |
+ ((header[MINOR_VERSION_OFFSET+2] & 0xff) << 8) |
+ ((header[MINOR_VERSION_OFFSET+3] & 0xff)) ;
+
+ minorMinorVersionNumber =
+ ((header[MINOR_MINOR_VERSION_OFFSET+0] & 0xff) << 24) |
+ ((header[MINOR_MINOR_VERSION_OFFSET+1] & 0xff) << 16) |
+ ((header[MINOR_MINOR_VERSION_OFFSET+2] & 0xff) << 8) |
+ ((header[MINOR_MINOR_VERSION_OFFSET+3] & 0xff)) ;
+
+ objectCount =
+ ((header[OBJECT_COUNT_OFFSET+0] & 0xff) << 24) |
+ ((header[OBJECT_COUNT_OFFSET+1] & 0xff) << 16) |
+ ((header[OBJECT_COUNT_OFFSET+2] & 0xff) << 8) |
+ ((header[OBJECT_COUNT_OFFSET+3] & 0xff)) ;
+
+ directoryOffset =
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+0] & 0xff) << 56) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+1] & 0xff) << 48) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+2] & 0xff) << 40) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+3] & 0xff) << 32) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+4] & 0xff) << 24) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+5] & 0xff) << 16) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+6] & 0xff) << 8) |
+ ((long)(header[DIRECTORY_OFFSET_OFFSET+7] & 0xff)) ;
+ }
+
+ //
+ // Write the file header based on current field values.
+ //
+ void writeFileHeader() throws IOException {
+ setFilePointer(0) ;
+ try {
+ cgFile.writeInt(MAGIC_NUMBER) ;
+ cgFile.writeInt(majorVersionNumber) ;
+ cgFile.writeInt(minorVersionNumber) ;
+ cgFile.writeInt(minorMinorVersionNumber) ;
+ cgFile.writeInt(objectCount) ;
+ cgFile.writeInt(0) ; // long word alignment
+ cgFile.writeLong(directoryOffset) ;
+ if (print)
+ System.out.println("wrote file header for " + fileName) ;
+ }
+ catch (IOException e) {
+ throw new IOException
+ (e.getMessage() +
+ "\ncould not write file header for " + fileName) ;
+ }
+ }
+
+ //
+ // Read the directory of compressed geometry object offsets.
+ //
+ void readDirectory(long offset, long[] directory)
+ throws IOException {
+
+ byte buff[] = new byte[directory.length * 8] ;
+ setFilePointer(offset) ;
+
+ try {
+ cgFile.read(buff) ;
+ if (print)
+ System.out.println("read " + buff.length + " byte directory") ;
+ }
+ catch (IOException e) {
+ throw new IOException
+ (e.getMessage() +
+ "\nfailed to read " + buff.length +
+ " byte directory, offset " + offset + " in file " + fileName) ;
+ }
+
+ for (int i = 0 ; i < directory.length ; i++) {
+ directory[i] =
+ ((long)(buff[i*8+0] & 0xff) << 56) |
+ ((long)(buff[i*8+1] & 0xff) << 48) |
+ ((long)(buff[i*8+2] & 0xff) << 40) |
+ ((long)(buff[i*8+3] & 0xff) << 32) |
+ ((long)(buff[i*8+4] & 0xff) << 24) |
+ ((long)(buff[i*8+5] & 0xff) << 16) |
+ ((long)(buff[i*8+6] & 0xff) << 8) |
+ ((long)(buff[i*8+7] & 0xff)) ;
+ }
+ }
+
+ //
+ // Write the file directory.
+ //
+ void writeFileDirectory() throws IOException {
+ setFilePointer(directoryOffset) ;
+
+ int directoryAlign = (int)(directoryOffset % 8) ;
+ if (directoryAlign != 0) {
+ // Align to long word before writing directory of long offsets.
+ byte bytes[] = new byte[8-directoryAlign] ;
+
+ try {
+ cgFile.write(bytes) ;
+ if (print)
+ System.out.println ("wrote " + (8-directoryAlign) +
+ " bytes long alignment") ;
+ }
+ catch (IOException e) {
+ throw new IOException
+ (e.getMessage() +
+ "\ncould not write " + directoryAlign +
+ " bytes to long word align directory for " + fileName) ;
+ }
+ directoryOffset += 8-directoryAlign ;
+ }
+
+ try {
+ for (int i = 0 ; i < objectCount ; i++)
+ cgFile.writeLong(directory[i]) ;
+
+ if (print)
+ System.out.println("wrote file directory for " + fileName) ;
+ }
+ catch (IOException e) {
+ throw new IOException
+ (e.getMessage() +
+ "\ncould not write directory for " + fileName) ;
+ }
+ }
+
+ //
+ // Get the next compressed object in the file, either from the read-ahead
+ // cache or from the file itself.
+ //
+ CompressedGeometryData readNext(int bufferReadLimit)
+ throws IOException {
+ if (objectIndex == objectCount)
+ return null ;
+
+ if (bufferNextObjectCount == 0) {
+ // No valid objects are in the cache.
+ int curSize = 0 ;
+ bufferObjectCount = 0 ;
+
+ // See how much we have room to read.
+ for (int i = objectIndex ; i < objectCount ; i++) {
+ if (curSize + objectSizes[i] > bufferReadLimit) break ;
+ curSize += objectSizes[i] ;
+ bufferObjectCount++ ;
+ }
+
+ // Try to read that amount.
+ try {
+ int n = cgFile.read(cgBuffer, 0, curSize) ;
+ if (print)
+ System.out.println("\nread " + n +
+ " bytes from " + fileName) ;
+ }
+ catch (IOException e) {
+ throw new IOException
+ (e.getMessage() +
+ "\nfailed to read " + curSize +
+ " bytes, object " + objectIndex + " in file " + fileName) ;
+ }
+
+ // Point at the first object in the buffer.
+ bufferObjectStart = objectIndex ;
+ bufferNextObjectCount = bufferObjectCount ;
+ bufferNextObjectOffset = 0 ;
+ }
+
+ // Get block header info.
+ geomSize =
+ ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+0]&0xff)<<24) |
+ ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+1]&0xff)<<16) |
+ ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+2]&0xff)<< 8) |
+ ((cgBuffer[bufferNextObjectOffset+OBJECT_SIZE_OFFSET+3]&0xff)) ;
+
+ geomDataType =
+ ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+0]&0xff) << 24) |
+ ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+1]&0xff) << 16) |
+ ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+2]&0xff) << 8) |
+ ((cgBuffer[bufferNextObjectOffset+GEOM_DATA_OFFSET+3]&0xff)) ;
+
+ // Get offset of compressed geometry data from start of buffer.
+ geomStart = bufferNextObjectOffset + BLOCK_HEADER_SIZE ;
+
+ if (print) {
+ System.out.println("\nobject " + objectIndex +
+ "\nfile offset " + directory[objectIndex] +
+ ", buffer offset " + bufferNextObjectOffset) ;
+ System.out.println("size " + geomSize + " bytes, " +
+ "data descriptor 0x" +
+ Integer.toHexString(geomDataType)) ;
+ }
+
+ // Update cache info.
+ bufferNextObjectOffset += objectSizes[objectIndex] ;
+ bufferNextObjectCount-- ;
+ objectIndex++ ;
+
+ return newCG(geomSize, geomStart, geomDataType) ;
+ }
+
+
+ //
+ // Construct and return a compressed geometry node.
+ //
+ CompressedGeometryData newCG(int geomSize,
+ int geomStart,
+ int geomDataType) {
+ cgh.size = geomSize ;
+ cgh.start = geomStart ;
+
+ if ((geomDataType & TYPE_MASK) == TYPE_POINT)
+ cgh.bufferType = CompressedGeometryData.Header.POINT_BUFFER ;
+ else if ((geomDataType & TYPE_MASK) == TYPE_LINE)
+ cgh.bufferType = CompressedGeometryData.Header.LINE_BUFFER ;
+ else if ((geomDataType & TYPE_MASK) == TYPE_TRIANGLE)
+ cgh.bufferType = CompressedGeometryData.Header.TRIANGLE_BUFFER ;
+
+ cgh.bufferDataPresent = 0 ;
+
+ if ((geomDataType & NORMAL_PRESENT_MASK) != 0)
+ cgh.bufferDataPresent |=
+ CompressedGeometryData.Header.NORMAL_IN_BUFFER ;
+
+ if ((geomDataType & COLOR_PRESENT_MASK) != 0)
+ cgh.bufferDataPresent |=
+ CompressedGeometryData.Header.COLOR_IN_BUFFER ;
+
+ if ((geomDataType & ALPHA_PRESENT_MASK) != 0)
+ cgh.bufferDataPresent |=
+ CompressedGeometryData.Header.ALPHA_IN_BUFFER ;
+
+ return new CompressedGeometryData(cgh, cgBuffer) ;
+ }
+
+ /**
+ * Release file resources when this object is garbage collected.
+ */
+ @Override
+ protected void finalize() {
+ close() ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressedGeometryRetained.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressedGeometryRetained.java
new file mode 100644
index 0000000..bda1df5
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressedGeometryRetained.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import org.jogamp.java3d.GeometryArray;
+
+/**
+ * The compressed geometry object is used to store geometry in a
+ * compressed format. Using compressed geometry reduces the amount
+ * of memory needed by a Java 3D application and increases the speed
+ * objects can be sent over the network. Once geometry decompression
+ * hardware support becomes available, increased rendering performance
+ * will also result from the use of compressed geometry.
+ */
+class CompressedGeometryRetained extends Object {
+
+ // If not in by-reference mode, a 48-byte header as defined by the
+ // GL_SUNX_geometry_compression OpenGL extension is always concatenated to
+ // the beginning of the compressed geometry data and copied along with the
+ // it into a contiguous array. This allows hardware decompression using
+ // the obsolete experimental GL_SUNX_geometry_compression extension if
+ // that is all that is available.
+ //
+ // This is completely distinct and not to be confused with the cgHeader
+ // field on the non-retained side, although much of the data is
+ // essentially the same.
+ private static final int HEADER_LENGTH = 48 ;
+
+ // These are the header locations examined.
+ private static final int HEADER_MAJOR_VERSION_OFFSET = 0 ;
+ private static final int HEADER_MINOR_VERSION_OFFSET = 1 ;
+ private static final int HEADER_MINOR_MINOR_VERSION_OFFSET = 2 ;
+ private static final int HEADER_BUFFER_TYPE_OFFSET = 3 ;
+ private static final int HEADER_BUFFER_DATA_OFFSET = 4 ;
+
+ // The OpenGL compressed geometry extensions use bits instead of
+ // enumerations to represent the type of compressed geometry.
+ static final byte TYPE_POINT = 1 ;
+ static final byte TYPE_LINE = 2 ;
+ static final byte TYPE_TRIANGLE = 4 ;
+
+ // Version number of this compressed geometry object.
+ int majorVersionNumber ;
+ int minorVersionNumber ;
+ int minorMinorVersionNumber ;
+
+ // These fields are used by the native execute() method.
+ int packedVersion ;
+ int bufferType ;
+ int bufferContents ;
+ int renderFlags ;
+ int offset ;
+ int size ;
+ byte[] compressedGeometry ;
+
+ // A reference to the original byte array with which this object was
+ // created. If hardware decompression is available but it doesn't support
+ // by-reference semantics, then an internal copy of the original byte array
+ // is made even when by-reference semantics have been requested.
+ private byte[] originalCompressedGeometry = null ;
+
+ // True if by-reference data access mode is in effect.
+ private boolean byReference = false ;
+
+ /**
+ * The package-scoped constructor.
+ */
+ CompressedGeometryRetained() {
+ }
+
+ /**
+ * Return true if the data access mode is by-reference.
+ */
+ boolean isByReference() {
+ return this.byReference ;
+ }
+
+ private void createByCopy(byte[] geometry) {
+ // Always copy a header along with the compressed geometry into a
+ // contiguous array in order to support hardware acceleration with the
+ // GL_SUNX_geometry_compression extension. The header is unnecessary
+ // if only the newer GL_SUN_geometry_compression API needs support.
+ compressedGeometry = new byte[HEADER_LENGTH + this.size] ;
+
+ compressedGeometry[HEADER_MAJOR_VERSION_OFFSET] =
+ (byte)this.majorVersionNumber ;
+
+ compressedGeometry[HEADER_MINOR_VERSION_OFFSET] =
+ (byte)this.minorVersionNumber ;
+
+ compressedGeometry[HEADER_MINOR_MINOR_VERSION_OFFSET] =
+ (byte)this.minorMinorVersionNumber ;
+
+ compressedGeometry[HEADER_BUFFER_TYPE_OFFSET] =
+ (byte)this.bufferType ;
+
+ compressedGeometry[HEADER_BUFFER_DATA_OFFSET] =
+ (byte)this.bufferContents ;
+
+ System.arraycopy(geometry, this.offset,
+ compressedGeometry, HEADER_LENGTH, this.size) ;
+
+ this.offset = HEADER_LENGTH ;
+ }
+
+ /**
+ * Creates the retained compressed geometry data. Data from the header is
+ * always copied; the compressed geometry is copied as well if the data
+ * access mode is not by-reference.
+ *
+ * @param hdr the compressed geometry header
+ * @param geometry the compressed geometry
+ * @param byReference if true then by-reference semantics requested
+ */
+ void createCompressedGeometry(CompressedGeometryData.Header hdr,
+ byte[] geometry, boolean byReference) {
+
+ this.byReference = byReference ;
+
+//// this.centroid.set(geoBounds.getCenter());
+//// recompCentroid = false;
+ this.majorVersionNumber = hdr.majorVersionNumber ;
+ this.minorVersionNumber = hdr.minorVersionNumber ;
+ this.minorMinorVersionNumber = hdr.minorMinorVersionNumber ;
+
+ this.packedVersion =
+ (hdr.majorVersionNumber << 24) |
+ (hdr.minorVersionNumber << 16) |
+ (hdr.minorMinorVersionNumber << 8) ;
+
+ switch(hdr.bufferType) {
+ case CompressedGeometryData.Header.POINT_BUFFER:
+ this.bufferType = TYPE_POINT ;
+ break ;
+ case CompressedGeometryData.Header.LINE_BUFFER:
+ this.bufferType = TYPE_LINE ;
+ break ;
+ case CompressedGeometryData.Header.TRIANGLE_BUFFER:
+ this.bufferType = TYPE_TRIANGLE ;
+ break ;
+ }
+
+ this.bufferContents = hdr.bufferDataPresent ;
+ this.renderFlags = 0 ;
+
+ this.size = hdr.size ;
+ this.offset = hdr.start ;
+
+ if (byReference) {
+ // Assume we can use the given reference, but maintain a second
+ // reference in case a copy is later needed.
+ this.compressedGeometry = geometry;
+ this.originalCompressedGeometry = geometry;
+ } else {
+ // Copy the original data into a format that can be used by both
+ // the software and native hardware decompressors.
+ createByCopy(geometry);
+ this.originalCompressedGeometry = null;
+ }
+ }
+
+ /**
+ * Return a vertex format mask that's compatible with GeometryArray
+ * objects.
+ */
+ int getVertexFormat() {
+ int vertexFormat = GeometryArray.COORDINATES;
+
+ if ((bufferContents & CompressedGeometryData.Header.NORMAL_IN_BUFFER) != 0) {
+ vertexFormat |= GeometryArray.NORMALS;
+ }
+
+ if ((bufferContents & CompressedGeometryData.Header.COLOR_IN_BUFFER) != 0) {
+ if ((bufferContents & CompressedGeometryData.Header.ALPHA_IN_BUFFER) != 0) {
+ vertexFormat |= GeometryArray.COLOR_4;
+ } else {
+ vertexFormat |= GeometryArray.COLOR_3;
+ }
+ }
+
+ return vertexFormat ;
+ }
+
+ /**
+ * Return a buffer type that's compatible with CompressedGeometryData.Header.
+ */
+ int getBufferType() {
+ switch(this.bufferType) {
+ case TYPE_POINT:
+ return CompressedGeometryData.Header.POINT_BUFFER ;
+ case TYPE_LINE:
+ return CompressedGeometryData.Header.LINE_BUFFER ;
+ default:
+ case TYPE_TRIANGLE:
+ return CompressedGeometryData.Header.TRIANGLE_BUFFER ;
+ }
+ }
+
+ /**
+ * Copies compressed geometry data into the given array of bytes.
+ * The internal header information is not copied.
+ *
+ * @param buff array of bytes into which to copy compressed geometry
+ */
+ void copy(byte[] buff) {
+ System.arraycopy(compressedGeometry, offset, buff, 0, size) ;
+ }
+
+ /**
+ * Returns a reference to the original compressed geometry byte array,
+ * which may have been copied even if by-reference semantics have been
+ * requested. It will be null if byCopy is in effect.
+ *
+ * @return reference to array of bytes containing the compressed geometry.
+ */
+ byte[] getReference() {
+ return originalCompressedGeometry ;
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStream.java b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStream.java
new file mode 100644
index 0000000..5000b33
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/geometry/compression/CompressionStream.java
@@ -0,0 +1,2338 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.geometry.compression;
+
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.jogamp.java3d.Appearance;
+import org.jogamp.java3d.Geometry;
+import org.jogamp.java3d.GeometryArray;
+import org.jogamp.java3d.GeometryStripArray;
+import org.jogamp.java3d.IndexedGeometryArray;
+import org.jogamp.java3d.IndexedGeometryStripArray;
+import org.jogamp.java3d.IndexedLineArray;
+import org.jogamp.java3d.IndexedLineStripArray;
+import org.jogamp.java3d.IndexedQuadArray;
+import org.jogamp.java3d.IndexedTriangleArray;
+import org.jogamp.java3d.IndexedTriangleFanArray;
+import org.jogamp.java3d.IndexedTriangleStripArray;
+import org.jogamp.java3d.J3DBuffer;
+import org.jogamp.java3d.LineArray;
+import org.jogamp.java3d.LineStripArray;
+import org.jogamp.java3d.Material;
+import org.jogamp.java3d.QuadArray;
+import org.jogamp.java3d.Shape3D;
+import org.jogamp.java3d.TriangleArray;
+import org.jogamp.java3d.TriangleFanArray;
+import org.jogamp.java3d.TriangleStripArray;
+import org.jogamp.vecmath.Color3f;
+import org.jogamp.vecmath.Color4f;
+import org.jogamp.vecmath.Point3d;
+import org.jogamp.vecmath.Point3f;
+import org.jogamp.vecmath.Point3i;
+import org.jogamp.vecmath.Vector3f;
+
+import org.jogamp.java3d.internal.BufferWrapper;
+import org.jogamp.java3d.utils.geometry.GeometryInfo;
+
+/**
+ * This class is used as input to a geometry compressor. It collects elements
+ * such as vertices, normals, colors, mesh references, and quantization
+ * parameters in an ordered stream. This stream is then traversed during
+ * the compression process and used to build the compressed output buffer.
+ *
+ * @see GeometryCompressor
+ *
+ * @since Java 3D 1.5
+ */
+public class CompressionStream {
+ //
+ // NOTE: For now, copies are made of all GeometryArray vertex components
+ // even when by-reference access is available.
+ //
+ // TODO: Retrofit all CompressionStreamElements and MeshBuffer to handle
+ // offsets to vertex data array references so that vertex components don't
+ // have to be copied. New CompressionStreamElements could be defined to
+ // set the current array reference during the quantization pass, or the
+ // reference could be included in every CompressionStreamElement along
+ // with the data offsets.
+ //
+ // TODO: Quantize on-the-fly when adding GeometryArray vertex data so that
+ // CompressionStreamElements don't need references to the original float,
+ // double, or byte data. Quantization is currently a separate pass since
+ // the 1st pass adds vertex data and gets the total object bounds, but
+ // this can be computed by merging the bounds of each GeometryArray
+ // compressed into a single object. The 2nd pass quantization is still
+ // needed for vertex data which isn't retrieved from a GeometryArray; for
+ // example, apps that might use the addVertex() methods directly instead
+ // of addGeometryArray().
+ //
+ // TODO: To further optimize memory, create new subclasses of
+ // CompressionStream{Color, Normal} for bundled attributes and add them as
+ // explicit stream elements. Then CompressionStreamVertex won't need to
+ // carry references to them. This memory savings might be negated by the
+ // extra overhead of adding more elements to the stream, however.
+ //
+ // TODO: Keep the absolute quantized values in the mesh buffer mirror so
+ // that unmeshed CompressionStreamElements don't need to carry them.
+ //
+ // TODO: Support texture coordinate compression even though Level II is
+ // not supported by any hardware decompressor on any graphics card.
+ // Software decompression is still useful for applications interested in
+ // minimizing file space, transmission time, and object loading time.
+ //
+ private static final boolean debug = false ;
+ private static final boolean benchmark = false ;
+
+ // Mesh buffer normal substitution is unavailable in Level I.
+ private static final boolean noMeshNormalSubstitution = true ;
+
+ /**
+ * This flag indicates that a vertex starts a new triangle or line strip.
+ */
+ static final int RESTART = 1 ;
+
+ /**
+ * This flag indicates that the next triangle in the strip is defined by
+ * replacing the middle vertex of the previous triangle in the strip.
+ * Equivalent to REPLACE_OLDEST for line strips.
+ */
+ static final int REPLACE_MIDDLE = 2 ;
+
+ /**
+ * This flag indicates that the next triangle in the strip is defined by
+ * replacing the oldest vertex of the previous triangle in the strip.
+ * Equivalent to REPLACE_MIDDLE for line strips.
+ */
+ static final int REPLACE_OLDEST = 3 ;
+
+ /**
+ * This flag indicates that a vertex is to be pushed into the mesh buffer.
+ */
+ static final int MESH_PUSH = 1 ;
+
+ /**
+ * This flag indicates that a vertex does not use the mesh buffer.
+ */
+ static final int NO_MESH_PUSH = 0 ;
+
+ /**
+ * Byte to float scale factor for scaling byte color components.
+ */
+ static final float ByteToFloatScale = 1.0f/255.0f;
+
+ /**
+ * Type of this stream, either CompressedGeometryData.Header.POINT_BUFFER,
+ * CompressedGeometryData.Header.LINE_BUFFER, or
+ * CompressedGeometryData.Header.TRIANGLE_BUFFER
+ */
+ int streamType ;
+
+ /**
+ * A mask indicating which components are present in each vertex, as
+ * defined by GeometryArray.
+ */
+ int vertexComponents ;
+
+ /**
+ * Boolean indicating colors are bundled with the vertices.
+ */
+ boolean vertexColors ;
+
+ /**
+ * Boolean indicating RGB colors are bundled with the vertices.
+ */
+ boolean vertexColor3 ;
+
+ /**
+ * Boolean indicating RGBA colors are bundled with the vertices.
+ */
+ boolean vertexColor4 ;
+
+ /**
+ * Boolean indicating normals are bundled with the vertices.
+ */
+ boolean vertexNormals ;
+
+ /**
+ * Boolean indicating texture coordinates are present.
+ */
+ boolean vertexTextures ;
+
+ /**
+ * Boolean indicating that 2D texture coordinates are used.
+ * Currently only used to skip over textures in interleaved data.
+ */
+ boolean vertexTexture2 ;
+
+ /**
+ * Boolean indicating that 3D texture coordinates are used.
+ * Currently only used to skip over textures in interleaved data.
+ */
+ boolean vertexTexture3 ;
+
+ /**
+ * Boolean indicating that 4D texture coordinates are used.
+ * Currently only used to skip over textures in interleaved data.
+ */
+ boolean vertexTexture4 ;
+
+ /**
+ * Axes-aligned box enclosing all vertices in model coordinates.
+ */
+ Point3d mcBounds[] = new Point3d[2] ;
+
+ /**
+ * Axes-aligned box enclosing all vertices in normalized coordinates.
+ */
+ Point3d ncBounds[] = new Point3d[2] ;
+
+ /**
+ * Axes-aligned box enclosing all vertices in quantized coordinates.
+ */
+ Point3i qcBounds[] = new Point3i[2] ;
+
+ /**
+ * Center for normalizing positions to the unit cube.
+ */
+ double center[] = new double[3] ;
+
+ /**
+ * Maximum position range along the 3 axes.
+ */
+ double positionRangeMaximum ;
+
+ /**
+ * Scale for normalizing positions to the unit cube.
+ */
+ double scale ;
+
+ /**
+ * Current position component (X, Y, and Z) quantization value. This can
+ * range from 1 to 16 bits and has a default of 16.textureNonPowerOfTwoAvailable
property is set to true.
+ *
+ * @since Java 3D 1.5
+ */
+ public static final int ALLOW_NON_POWER_OF_TWO = 0x08;
+
+ /*
+ * Private declaration for BufferedImage allocation
+ */
+ private static ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+ private static int[] nBits = {8, 8, 8, 8};
+ private static int[] bandOffset = { 0, 1, 2, 3};
+ private static ComponentColorModel colorModel = new ComponentColorModel(cs, nBits, true, false, Transparency.TRANSLUCENT, 0);
+
+ private Texture2D tex = null;
+ private BufferedImage bufferedImage = null;
+ private ImageComponent2D imageComponent = null;
+ private int textureFormat = Texture.RGBA;
+ private int imageComponentFormat = ImageComponent.FORMAT_RGBA;
+ private int flags;
+ private boolean byRef = false;
+ private boolean yUp = false;
+ private boolean forcePowerOfTwo = true;
+
+ /**
+ * Contructs a TextureLoader object using the specified BufferedImage
+ * and default format RGBA
+ * @param bImage The BufferedImage used for loading the texture
+ *
+ * @exception NullPointerException if bImage is null
+ */
+ public TextureLoader(BufferedImage bImage) {
+ this(bImage, null, 0);
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified BufferedImage
+ * and format
+ * @param bImage The BufferedImage used for loading the texture
+ * @param format The format specifies which channels to use
+ *
+ * @exception NullPointerException if bImage is null
+ */
+ public TextureLoader(BufferedImage bImage, String format) {
+ this(bImage, format, 0);
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified BufferedImage,
+ * option flags and default format RGBA
+ * @param bImage The BufferedImage used for loading the texture
+ * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
+ *
+ * @exception NullPointerException if bImage is null
+ */
+ public TextureLoader(BufferedImage bImage, int flags) {
+ this(bImage, null, flags);
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified BufferedImage,
+ * format and option flags
+ * @param bImage The BufferedImage used for loading the texture
+ * @param format The format specifies which channels to use
+ * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
+ *
+ * @exception NullPointerException if bImage is null
+ */
+ public TextureLoader(BufferedImage bImage, String format, int flags) {
+ if (bImage == null) {
+ throw new NullPointerException();
+ }
+
+ parseFormat(format);
+ this.flags = flags;
+ bufferedImage = bImage;
+ if (format==null)
+ chooseFormat(bufferedImage);
+
+ if ((flags & BY_REFERENCE) != 0) {
+ byRef = true;
+ }
+ if ((flags & Y_UP) != 0) {
+ yUp = true;
+ }
+ if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) {
+ forcePowerOfTwo = false;
+ }
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified Image
+ * and default format RGBA
+ * @param image The Image used for loading the texture
+ * @param observer The associated image observer
+ *
+ * @exception NullPointerException if image is null
+ * @exception ImageException if there is a problem loading the image
+ */
+ public TextureLoader(Image image, Component observer) {
+ this(image, null, 0, observer);
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified Image
+ * and format
+ * @param image The Image used for loading the texture
+ * @param format The format specifies which channels to use
+ * @param observer The associated image observer
+ *
+ * @exception NullPointerException if image is null
+ * @exception ImageException if there is a problem loading the image
+ */
+ public TextureLoader(Image image, String format, Component observer) {
+ this(image, format, 0, observer);
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified Image
+ * flags and default format RGBA
+ * @param image The Image used for loading the texture
+ * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
+ * @param observer The associated image observer
+ *
+ * @exception NullPointerException if image is null
+ * @exception ImageException if there is a problem loading the image
+ */
+ public TextureLoader(Image image, int flags, Component observer) {
+ this(image, null, flags, observer);
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified Image
+ * format and option flags
+ * @param image The Image used for loading the texture
+ * @param format The format specifies which channels to use
+ * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
+ * @param observer The associated image observer
+ *
+ * @exception NullPointerException if image is null
+ * @exception ImageException if there is a problem loading the image
+ */
+ public TextureLoader(Image image, String format, int flags,
+ Component observer) {
+
+ if (image == null) {
+ throw new NullPointerException();
+ }
+
+ if (observer == null) {
+ observer = new java.awt.Container();
+ }
+
+ parseFormat(format);
+ this.flags = flags;
+ bufferedImage = createBufferedImage(image, observer);
+
+ if (bufferedImage==null) {
+ throw new ImageException("Error loading image: " + image.toString());
+ }
+
+ if (format==null)
+ chooseFormat(bufferedImage);
+
+ if ((flags & BY_REFERENCE) != 0) {
+ byRef = true;
+ }
+ if ((flags & Y_UP) != 0) {
+ yUp = true;
+ }
+ if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) {
+ forcePowerOfTwo = false;
+ }
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified file
+ * and default format RGBA
+ * @param fname The file that specifies an Image to load the texture with
+ * @param observer The associated image observer
+ *
+ * @exception ImageException if there is a problem reading the image
+ */
+ public TextureLoader(String fname, Component observer) {
+ this(fname, null, 0, observer);
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified file,
+ * and format
+ * @param fname The file that specifies an Image to load the texture with
+ * @param format The format specifies which channels to use
+ * @param observer The associated image observer
+ *
+ * @exception ImageException if there is a problem reading the image
+ */
+ public TextureLoader(String fname, String format, Component observer) {
+ this(fname, format, 0, observer);
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified file,
+ * option flags and default format RGBA
+ * @param fname The file that specifies an Image to load the texture with
+ * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
+ * @param observer The associated image observer
+ *
+ * @exception ImageException if there is a problem reading the image
+ */
+ public TextureLoader(String fname, int flags, Component observer) {
+ this(fname, null, flags, observer);
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified file,
+ * format and option flags
+ * @param fname The file that specifies an Image to load the texture with
+ * @param format The format specifies which channels to use
+ * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
+ * @param observer The associated image observer
+ *
+ * @exception ImageException if there is a problem reading the image
+ */
+ public TextureLoader(final String fname, String format, int flags,
+ Component observer) {
+
+ if (observer == null) {
+ observer = new java.awt.Container();
+ }
+
+ bufferedImage = (BufferedImage)
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ @Override
+ public Object run() {
+ try {
+ return ImageIO.read(new File(fname));
+ } catch (IOException e) {
+ throw new ImageException(e);
+ }
+ }
+ }
+ );
+
+ if (bufferedImage==null) {
+ throw new ImageException("Error loading image: " + fname);
+ }
+
+ parseFormat(format);
+ this.flags = flags;
+
+ if (format==null)
+ chooseFormat(bufferedImage);
+
+ if ((flags & BY_REFERENCE) != 0) {
+ byRef = true;
+ }
+ if ((flags & Y_UP) != 0) {
+ yUp = true;
+ }
+ if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) {
+ forcePowerOfTwo = false;
+ }
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified URL
+ * and default format RGBA
+ * @param url The URL that specifies an Image to load the texture with
+ * @param observer The associated image observer
+ *
+ * @exception ImageException if there is a problem reading the image
+ */
+ public TextureLoader(URL url, Component observer) {
+ this(url, null, 0, observer);
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified URL,
+ * and format
+ * @param url The URL that specifies an Image to load the texture with
+ * @param format The format specifies which channels to use
+ * @param observer The associated image observer
+ *
+ * @exception ImageException if there is a problem reading the image
+ */
+ public TextureLoader(URL url, String format, Component observer) {
+ this(url, format, 0, observer);
+ }
+
+ /**
+ * Contructs a TextureLoader object using the specified URL,
+ * option flags and default format RGBA
+ * @param url The URL that specifies an Image to load the texture with
+ * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
+ * @param observer The associated image observer
+ *
+ * @exception ImageException if there is a problem reading the image
+ */
+ public TextureLoader(URL url, int flags, Component observer) {
+ this(url, null, flags, observer);
+ }
+ /**
+ * Contructs a TextureLoader object using the specified URL,
+ * format and option flags
+ * @param url The url that specifies an Image to load the texture with
+ * @param format The format specifies which channels to use
+ * @param flags The flags specify what options to use in texture loading (generate mipmap etc)
+ * @param observer The associated image observer
+ *
+ * @exception ImageException if there is a problem reading the image
+ */
+ public TextureLoader(final URL url, String format, int flags,
+ Component observer) {
+
+ if (observer == null) {
+ observer = new java.awt.Container();
+ }
+
+ bufferedImage = (BufferedImage)
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ @Override
+ public Object run() {
+ try {
+ return ImageIO.read(url);
+ } catch (IOException e) {
+ throw new ImageException(e);
+ }
+ }
+ }
+ );
+
+ if (bufferedImage==null) {
+ throw new ImageException("Error loading image: " + url.toString());
+ }
+
+ parseFormat(format);
+ this.flags = flags;
+
+ if (format==null)
+ chooseFormat(bufferedImage);
+
+ if ((flags & BY_REFERENCE) != 0) {
+ byRef = true;
+ }
+ if ((flags & Y_UP) != 0) {
+ yUp = true;
+ }
+ if ((flags & ALLOW_NON_POWER_OF_TWO) != 0) {
+ forcePowerOfTwo = false;
+ }
+ }
+
+
+ /**
+ * Returns the associated ImageComponent2D object
+ *
+ * @return The associated ImageComponent2D object
+ */
+ public ImageComponent2D getImage() {
+ if (imageComponent == null)
+ imageComponent = new ImageComponent2D(imageComponentFormat,
+ bufferedImage, byRef, yUp);
+ return imageComponent;
+ }
+
+ /**
+ * Returns the scaled ImageComponent2D object
+ *
+ * @param xScale The X scaling factor
+ * @param yScale The Y scaling factor
+ *
+ * @return The scaled ImageComponent2D object
+ */
+ public ImageComponent2D getScaledImage(float xScale, float yScale) {
+ if (xScale == 1.0f && yScale == 1.0f)
+ return getImage();
+ else
+ return(new ImageComponent2D(imageComponentFormat,
+ getScaledImage(bufferedImage,
+ xScale, yScale),
+ byRef, yUp));
+ }
+
+ /**
+ * Returns the scaled ImageComponent2D object
+ *
+ * @param width The desired width
+ * @param height The desired height
+ *
+ * @return The scaled ImageComponent2D object
+ */
+ public ImageComponent2D getScaledImage(int width, int height) {
+
+ if (bufferedImage.getWidth() == width &&
+ bufferedImage.getHeight() == height)
+ return getImage();
+ else
+ return(new ImageComponent2D(imageComponentFormat,
+ getScaledImage(bufferedImage,
+ width, height),
+ byRef, yUp));
+ }
+
+ /**
+ * Returns the associated Texture object.
+ *
+ * @return The associated Texture object
+ */
+ public Texture getTexture() {
+ ImageComponent2D[] scaledImageComponents = null;
+ BufferedImage[] scaledBufferedImages = null;
+ if (tex == null) {
+
+ int width;
+ int height;
+
+ if (forcePowerOfTwo) {
+ width = getClosestPowerOf2(bufferedImage.getWidth());
+ height = getClosestPowerOf2(bufferedImage.getHeight());
+ } else {
+ width = bufferedImage.getWidth();
+ height = bufferedImage.getHeight();
+ }
+
+ if ((flags & GENERATE_MIPMAP) != 0) {
+
+ BufferedImage origImage = bufferedImage;
+ int newW = width;
+ int newH = height;
+ int level = Math.max(computeLog(width), computeLog(height)) + 1;
+ scaledImageComponents = new ImageComponent2D[level];
+ scaledBufferedImages = new BufferedImage[level];
+ tex = new Texture2D(tex.MULTI_LEVEL_MIPMAP, textureFormat,
+ width, height);
+
+ for (int i = 0; i < level; i++) {
+ scaledBufferedImages[i] = getScaledImage(origImage, newW, newH);
+ scaledImageComponents[i] = new ImageComponent2D(
+ imageComponentFormat, scaledBufferedImages[i],
+ byRef, yUp);
+
+ tex.setImage(i, scaledImageComponents[i]);
+ if (forcePowerOfTwo) {
+ if (newW > 1) newW >>= 1;
+ if (newH > 1) newH >>= 1;
+ } else {
+ if (newW > 1) {
+ newW = (int) Math.floor(newW / 2.0);
+ }
+ if (newH > 1) {
+ newH = (int) Math.floor(newH / 2.0);
+ }
+ }
+ origImage = scaledBufferedImages[i];
+ }
+
+ } else {
+ scaledImageComponents = new ImageComponent2D[1];
+ scaledBufferedImages = new BufferedImage[1];
+
+ // Create texture from image
+ scaledBufferedImages[0] = getScaledImage(bufferedImage,
+ width, height);
+ scaledImageComponents[0] = new ImageComponent2D(
+ imageComponentFormat, scaledBufferedImages[0],
+ byRef, yUp);
+
+ tex = new Texture2D(tex.BASE_LEVEL, textureFormat, width, height);
+
+ tex.setImage(0, scaledImageComponents[0]);
+ }
+ tex.setMinFilter(tex.BASE_LEVEL_LINEAR);
+ tex.setMagFilter(tex.BASE_LEVEL_LINEAR);
+ }
+
+ return tex;
+ }
+
+ // create a BufferedImage from an Image object
+ private BufferedImage createBufferedImage(Image image,
+ Component observer) {
+
+ int status;
+
+ observer.prepareImage(image, null);
+ while(true) {
+ status = observer.checkImage(image, null);
+ if ((status & ImageObserver.ERROR) != 0) {
+ return null;
+ } else if ((status & ImageObserver.ALLBITS) != 0) {
+ break;
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {}
+ }
+
+ int width = image.getWidth(observer);
+ int height = image.getHeight(observer);
+
+ WritableRaster wr =
+ java.awt.image.Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ width, height,
+ width * 4, 4,
+ bandOffset, null);
+ BufferedImage bImage = new BufferedImage(colorModel, wr, false, null);
+
+ java.awt.Graphics g = bImage.getGraphics();
+ g.drawImage(image, 0, 0, observer);
+
+ return bImage;
+ }
+
+ /**
+ * Choose the correct ImageComponent and Texture format for the given
+ * image
+ */
+ private void chooseFormat(BufferedImage image) {
+ switch (image.getType()) {
+ case BufferedImage.TYPE_4BYTE_ABGR :
+ case BufferedImage.TYPE_INT_ARGB :
+ imageComponentFormat = ImageComponent.FORMAT_RGBA;
+ textureFormat = Texture.RGBA;
+ break;
+ case BufferedImage.TYPE_3BYTE_BGR :
+ case BufferedImage.TYPE_INT_BGR:
+ case BufferedImage.TYPE_INT_RGB:
+ imageComponentFormat = ImageComponent.FORMAT_RGB;
+ textureFormat = Texture.RGB;
+ break;
+ case BufferedImage.TYPE_CUSTOM:
+ if (is4ByteRGBAOr3ByteRGB(image)) {
+ SampleModel sm = image.getSampleModel();
+ if (sm.getNumBands() == 3) {
+ //System.out.println("ChooseFormat Custom:TYPE_4BYTE_ABGR");
+ imageComponentFormat = ImageComponent.FORMAT_RGB;
+ textureFormat = Texture.RGB;
+ }
+ else {
+ imageComponentFormat = ImageComponent.FORMAT_RGBA;
+ //System.out.println("ChooseFormat Custom:TYPE_3BYTE_BGR");
+ textureFormat = Texture.RGBA;
+ }
+ }
+ break;
+ default :
+ // System.err.println("Unoptimized Image Type "+image.getType());
+ imageComponentFormat = ImageComponent.FORMAT_RGBA;
+ textureFormat = Texture.RGBA;
+ break;
+ }
+ }
+
+ private boolean is4ByteRGBAOr3ByteRGB(RenderedImage ri) {
+ boolean value = false;
+ int i;
+ int biType = getImageType(ri);
+ if (biType != BufferedImage.TYPE_CUSTOM)
+ return false;
+ ColorModel cm = ri.getColorModel();
+ ColorSpace cs = cm.getColorSpace();
+ SampleModel sm = ri.getSampleModel();
+ boolean isAlphaPre = cm.isAlphaPremultiplied();
+ int csType = cs.getType();
+ if ( csType == ColorSpace.TYPE_RGB) {
+ int numBands = sm.getNumBands();
+ if (sm.getDataType() == DataBuffer.TYPE_BYTE) {
+ if (cm instanceof ComponentColorModel &&
+ sm instanceof PixelInterleavedSampleModel) {
+ PixelInterleavedSampleModel csm =
+ (PixelInterleavedSampleModel) sm;
+ int[] offs = csm.getBandOffsets();
+ ComponentColorModel ccm = (ComponentColorModel)cm;
+ int[] nBits = ccm.getComponentSize();
+ boolean is8Bit = true;
+ for (i=0; i < numBands; i++) {
+ if (nBits[i] != 8) {
+ is8Bit = false;
+ break;
+ }
+ }
+ if (is8Bit &&
+ offs[0] == 0 &&
+ offs[1] == 1 &&
+ offs[2] == 2) {
+ if (numBands == 3) {
+ value = true;
+ }
+ else if (offs[3] == 3 && !isAlphaPre) {
+ value = true;
+ }
+ }
+ }
+ }
+ }
+ return value;
+ }
+
+ private int getImageType(RenderedImage ri) {
+ int imageType = BufferedImage.TYPE_CUSTOM;
+ int i;
+
+ if (ri instanceof BufferedImage) {
+ return ((BufferedImage)ri).getType();
+ }
+ ColorModel cm = ri.getColorModel();
+ ColorSpace cs = cm.getColorSpace();
+ SampleModel sm = ri.getSampleModel();
+ int csType = cs.getType();
+ boolean isAlphaPre = cm.isAlphaPremultiplied();
+ if ( csType != ColorSpace.TYPE_RGB) {
+ if (csType == ColorSpace.TYPE_GRAY &&
+ cm instanceof ComponentColorModel) {
+ if (sm.getDataType() == DataBuffer.TYPE_BYTE) {
+ imageType = BufferedImage.TYPE_BYTE_GRAY;
+ } else if (sm.getDataType() == DataBuffer.TYPE_USHORT) {
+ imageType = BufferedImage.TYPE_USHORT_GRAY;
+ }
+ }
+ }
+ // RGB , only interested in BYTE ABGR and BGR for now
+ // all others will be copied to a buffered image
+ else {
+ int numBands = sm.getNumBands();
+ if (sm.getDataType() == DataBuffer.TYPE_BYTE) {
+ if (cm instanceof ComponentColorModel &&
+ sm instanceof PixelInterleavedSampleModel) {
+ PixelInterleavedSampleModel csm =
+ (PixelInterleavedSampleModel) sm;
+ int[] offs = csm.getBandOffsets();
+ ComponentColorModel ccm = (ComponentColorModel)cm;
+ int[] nBits = ccm.getComponentSize();
+ boolean is8Bit = true;
+ for (i=0; i < numBands; i++) {
+ if (nBits[i] != 8) {
+ is8Bit = false;
+ break;
+ }
+ }
+ if (is8Bit &&
+ offs[0] == numBands-1 &&
+ offs[1] == numBands-2 &&
+ offs[2] == numBands-3) {
+ if (numBands == 3) {
+ imageType = BufferedImage.TYPE_3BYTE_BGR;
+ }
+ else if (offs[3] == 0) {
+ imageType = (isAlphaPre
+ ? BufferedImage.TYPE_4BYTE_ABGR_PRE
+ : BufferedImage.TYPE_4BYTE_ABGR);
+ }
+ }
+ }
+ }
+ }
+ return imageType;
+ }
+
+ // initialize appropriate format for ImageComponent and Texture
+ private void parseFormat(String format) {
+ if (format==null)
+ return;
+
+ if (format.equals("RGBA")) {
+ imageComponentFormat = ImageComponent.FORMAT_RGBA;
+ textureFormat = Texture.RGBA;
+
+ } else if (format.equals("RGBA4")) {
+ imageComponentFormat = ImageComponent.FORMAT_RGBA4;
+ textureFormat = Texture.RGBA;
+
+ } else if (format.equals("RGB5_A1")) {
+ imageComponentFormat = ImageComponent.FORMAT_RGB5_A1;
+ textureFormat = Texture.RGBA;
+
+ } else if (format.equals("RGB")) {
+ imageComponentFormat = ImageComponent.FORMAT_RGB;
+ textureFormat = Texture.RGB;
+
+ } else if (format.equals("RGB4")) {
+ imageComponentFormat = ImageComponent.FORMAT_RGB4;
+ textureFormat = Texture.RGB;
+
+ } else if (format.equals("RGB5")) {
+ imageComponentFormat = ImageComponent.FORMAT_RGB5;
+ textureFormat = Texture.RGB;
+
+ } else if (format.equals("R3_G3_B2")) {
+ imageComponentFormat = ImageComponent.FORMAT_R3_G3_B2;
+ textureFormat = Texture.RGB;
+
+ } else if (format.equals("LUM8_ALPHA8")) {
+ imageComponentFormat = ImageComponent.FORMAT_LUM8_ALPHA8;
+ textureFormat = Texture.LUMINANCE_ALPHA;
+
+ } else if (format.equals("LUM4_ALPHA4")) {
+ imageComponentFormat = ImageComponent.FORMAT_LUM4_ALPHA4;
+ textureFormat = Texture.LUMINANCE_ALPHA;
+
+ } else if (format.equals("LUMINANCE")) {
+ imageComponentFormat = ImageComponent.FORMAT_CHANNEL8;
+ textureFormat = Texture.LUMINANCE;
+
+ } else if (format.equals("ALPHA")) {
+ imageComponentFormat = ImageComponent.FORMAT_CHANNEL8;
+ textureFormat = Texture.ALPHA;
+ }
+ }
+
+ // return a scaled image of given width and height
+ private BufferedImage getScaledImage(BufferedImage origImage,
+ int width, int height) {
+
+ int origW = origImage.getWidth();
+ int origH = origImage.getHeight();
+ float xScale = (float)width/(float)origW;
+ float yScale = (float)height/(float)origH;
+
+ return (getScaledImage(origImage, xScale, yScale));
+ }
+
+ // return a scaled image of given x and y scale
+ private BufferedImage getScaledImage(BufferedImage origImage,
+ float xScale, float yScale) {
+
+
+ // System.err.println("(1) origImage " + origImage);
+ // If the image is already the requested size, no need to scale
+ if (xScale == 1.0f && yScale == 1.0f)
+ return origImage;
+ else {
+ int scaleW = (int)(origImage.getWidth() * xScale + 0.5);
+ int scaleH = (int)(origImage.getHeight() * yScale + 0.5);
+
+ int origImageType = origImage.getType();
+ BufferedImage scaledImage;
+ WritableRaster wr;
+
+ if (origImageType != BufferedImage.TYPE_CUSTOM) {
+ WritableRaster origWr = origImage.getRaster();
+ wr = origWr.createCompatibleWritableRaster(0, 0, scaleW, scaleH);
+ scaledImage = new BufferedImage(scaleW, scaleH, origImageType);
+ } else {
+ int numComponents = origImage.getSampleModel().getNumBands();
+ int[] bandOffset = new int[numComponents];
+ int[] nBits = new int[numComponents];
+ for (int ii=0; ii < numComponents; ii++) {
+ bandOffset[ii] = ii;
+ nBits[ii] = 8;
+ }
+
+ wr = java.awt.image.Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ scaleW, scaleH,
+ scaleW * numComponents, numComponents,
+ bandOffset, null);
+
+ int imageType;
+
+ switch (numComponents) {
+ case 1:
+ imageType = BufferedImage.TYPE_BYTE_GRAY;
+ break;
+ case 3:
+ imageType = BufferedImage.TYPE_3BYTE_BGR;
+ break;
+ case 4:
+ imageType = BufferedImage.TYPE_4BYTE_ABGR;
+ break;
+ default:
+ throw new ImageException("Illegal number of bands : " + numComponents);
+
+ }
+
+ scaledImage = new BufferedImage(scaleW, scaleH, imageType);
+ }
+
+ scaledImage.setData(wr);
+ java.awt.Graphics2D g2 = scaledImage.createGraphics();
+ AffineTransform at = AffineTransform.getScaleInstance(xScale,
+ yScale);
+ g2.transform(at);
+ g2.drawImage(origImage, 0, 0, null);
+
+ return scaledImage;
+ }
+ }
+
+ private int computeLog(int value) {
+ int i = 0;
+
+ if (value == 0) return -1;
+ for (;;) {
+ if (value == 1)
+ return i;
+ value >>= 1;
+ i++;
+ }
+ }
+
+ private int getClosestPowerOf2(int value) {
+
+ if (value < 1)
+ return value;
+
+ int powerValue = 1;
+ for (;;) {
+ powerValue *= 2;
+ if (value < powerValue) {
+ // Found max bound of power, determine which is closest
+ int minBound = powerValue/2;
+ if ((powerValue - value) >
+ (value - minBound))
+ return minBound;
+ else
+ return powerValue;
+ }
+ }
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/image/package.html b/src/classes/share/org/jogamp/java3d/utils/image/package.html
new file mode 100644
index 0000000..27b3560
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/image/package.html
@@ -0,0 +1,11 @@
+
+
+
+ *
+ * PickCanvas pickCanvas = new PickCanvas(canvas, scene);
+ * pickCanvas.setMode(PickInfo.PICK_GEOMETRY);
+ * pickCanvas.setFlags(PickInfo.NODE | PickInfo.CLOSEST_INTERSECTION_POINT);
+ * pickCanvas.setTolerance(4.0f);
+ *
+ *
+ * pickCanvas.setShapeLocation(mouseEvent);
+ * PickInfo[] pickInfos = pickCanvas.pickAll();
+ *
org.jogamp.java3d.utils.geometry.Primitive)
.
+ * For example, the intersection would indicate which triangle out of a
+ * triangle strip was intersected.
+ * The methods which return primitive data will have one value if the primitive
+ * is
+ * a point, two values if the primitive is a line, three values if the primitive
+ * is a triangle and four values if the primitive is quad.
+ *
+ *
+ * Vector3f getNormal(PickIntersection pi, int vertexIndex) {
+ * int index;
+ * Vector3d normal = new Vector3f();
+ * GeometryArray ga = pickIntersection.getGeometryArray();
+ * if (pickIntersection.geometryIsIndexed()) {
+ * index = ga.getNormalIndex(vertexIndex);
+ * } else {
+ * index = vertexIndex;
+ * }
+ * ga.getNormal(index, normal);
+ * return normal;
+ * }
+ *
+ *
+ *
+ *
+ * PickInfo.SCENEGRAPHPATH
- request for computed SceneGraphPath.
+ * PickInfo.NODE
- request for computed intersected Node.
+ * PickInfo.LOCAL_TO_VWORLD
- request for computed local to virtual world transform.
+ * PickInfo.CLOSEST_INTERSECTION_POINT
- request for closest intersection point.
+ * PickInfo.CLOSEST_DISTANCE
- request for the distance of closest intersection.
+ * PickInfo.CLOSEST_GEOM_INFO
- request for only the closest intersection geometry information.
+ * PickInfo.ALL_GEOM_INFO
- request for all intersection geometry information.
+ * getNode(int)
+ * to return a
+ * Shape3D
node from
+ * the SceneGraphPath
.
+ */
+ public static final int TYPE_SHAPE3D = 0x1;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * Morph
node from
+ * the SceneGraphPath
.
+ */
+ public static final int TYPE_MORPH = 0x2;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+
+ * to return a
+ * Primitive
node from
+ * the SceneGraphPath
.
+ */
+ public static final int TYPE_PRIMITIVE = 0x4;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * Link
node from
+ * the SceneGraphPath
.
+ */
+ public static final int TYPE_LINK = 0x8;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * Group
node from
+ * the SceneGraphPath
.
+ */
+ public static final int TYPE_GROUP = 0x10;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * TransformGroup
node from
+ * the SceneGraphPath
.
+ */
+ public static final int TYPE_TRANSFORM_GROUP = 0x20;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * BranchGroup
node from
+ * the SceneGraphPath
.
+ */
+ public static final int TYPE_BRANCH_GROUP = 0x40;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * Switch
node from
+ * the SceneGraphPath
.
+ */
+ public static final int TYPE_SWITCH = 0x80;
+
+
+ private static final int ALL_FLAGS =
+ PickInfo.SCENEGRAPHPATH |
+ PickInfo.NODE |
+ PickInfo.LOCAL_TO_VWORLD |
+ PickInfo.CLOSEST_INTERSECTION_POINT |
+ PickInfo.CLOSEST_DISTANCE |
+ PickInfo.CLOSEST_GEOM_INFO |
+ PickInfo.ALL_GEOM_INFO;
+
+ private final boolean debug = false;
+ protected boolean userDefineShape = false;
+
+ PickShape pickShape;
+
+ /** Used to store the BranchGroup used for picking */
+ BranchGroup pickRootBG = null;
+ /** Used to store the Locale used for picking */
+ Locale pickRootL = null;
+
+ /** Used to store a reference point used in determining how "close" points
+ are.
+ */
+ Point3d start = null;
+
+ int mode = PickInfo.PICK_BOUNDS;
+ int flags = PickInfo.NODE;
+
+ /* ============================ METHODS ============================ */
+
+ /**
+ * Constructor with BranchGroup to be picked.
+ */
+ public PickTool (BranchGroup b) {
+ pickRootBG = b;
+ }
+
+ /**
+ * Constructor with the Locale to be picked.
+ */
+ public PickTool (Locale l) {
+ pickRootL = l;
+ }
+
+ /** Returns the BranchGroup to be picked if the tool was initialized
+ with a BranchGroup, null otherwise.
+ */
+ public BranchGroup getBranchGroup() {
+ return pickRootBG;
+ }
+
+ /**
+ * Returns the Locale to be picked if the tool was initialized with
+ * a Locale, null otherwise.
+ */
+ public Locale getLocale () {
+ return pickRootL;
+ }
+
+ // Methods used to define the pick shape
+
+ /** Sets the pick shape to a user-provided PickShape object
+ * @param ps The pick shape to pick against.
+ * @param startPt The start point to use for distance calculations
+ */
+ public void setShape (PickShape ps, Point3d startPt) {
+ this.pickShape = ps;
+ this.start = startPt;
+ userDefineShape = (ps != null);
+ }
+
+ /** Sets the pick shape to use a user-provided Bounds object
+ * @param bounds The bounds to pick against.
+ * @param startPt The start point to use for distance calculations
+ */
+ public void setShapeBounds (Bounds bounds, Point3d startPt) {
+ this.pickShape = (PickShape) new PickBounds (bounds);
+ this.start = startPt;
+ userDefineShape = true;
+ }
+
+ /** Sets the picking detail mode. The default is PickInfo.PICK_BOUNDS.
+ * @param mode One of PickInfo.PICK_BOUNDS or PickInfo.PICK_GEOMETRY.
+ * @exception IllegalArgumentException if mode is not a legal value
+ */
+ public void setMode (int mode) {
+ if ((mode != PickInfo.PICK_BOUNDS) && (mode != PickInfo.PICK_GEOMETRY)) {
+ throw new java.lang.IllegalArgumentException();
+ }
+ this.mode = mode;
+ }
+
+ /** Gets the picking detail mode.
+ */
+ public int getMode () {
+ return mode;
+ }
+
+ /** Sets the PickInfo content flags. The default is PickInfo.NODE.
+ * @param flags specified as one or more individual bits that are
+ * bitwise "OR"ed together :
+ *
+ *
+ * @exception IllegalArgumentException if any other bits besides the above are set.
+ */
+ public void setFlags (int flags) {
+ if ((flags & ~ALL_FLAGS) != 0) {
+ throw new java.lang.IllegalArgumentException();
+ }
+ this.flags = flags;
+ }
+
+ /** Gets the PickInfo content flags.
+ */
+ public int getFlags () {
+ return flags;
+ }
+
+ /** Sets the pick shape to a PickRay.
+ * @param start The start of the ray
+ * @param dir The direction of the ray
+ */
+ public void setShapeRay (Point3d start, Vector3d dir) {
+ this.pickShape = (PickShape) new PickRay (start, dir);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Sets the pick shape to a PickSegment.
+ @param start The start of the segment
+ @param end The end of the segment
+ */
+ public void setShapeSegment (Point3d start, Point3d end) {
+ this.pickShape = (PickShape) new PickSegment (start, end);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Sets the pick shape to a capped PickCylinder
+ * @param start The start of axis of the cylinder
+ * @param end The end of the axis of the cylinder
+ * @param radius The radius of the cylinder
+ */
+ public void setShapeCylinderSegment (Point3d start, Point3d end,
+ double radius) {
+ this.pickShape = (PickShape)
+ new PickCylinderSegment (start, end, radius);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Sets the pick shape to an infinite PickCylinder.
+ * @param start The start of axis of the cylinder
+ * @param dir The direction of the axis of the cylinder
+ * @param radius The radius of the cylinder
+ */
+ public void setShapeCylinderRay (Point3d start, Vector3d dir,
+ double radius) {
+ this.pickShape = (PickShape) new PickCylinderRay (start, dir, radius);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Sets the pick shape to a capped PickCone
+ * @param start The start of axis of the cone
+ * @param end The end of the axis of the cone
+ * @param angle The angle of the cone
+ */
+ public void setShapeConeSegment (Point3d start, Point3d end,
+ double angle) {
+ this.pickShape = (PickShape) new PickConeSegment (start, end, angle);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Sets the pick shape to an infinite PickCone.
+ * @param start The start of axis of the cone
+ * @param dir The direction of the axis of the cone
+ * @param angle The angle of the cone
+ */
+ public void setShapeConeRay (Point3d start, Vector3d dir,
+ double angle) {
+ this.pickShape = (PickShape) new PickConeRay (start, dir, angle);
+ this.start = start;
+ userDefineShape = true;
+ }
+
+ /** Returns the PickShape for this object. */
+ public PickShape getPickShape () {
+ return pickShape;
+ }
+
+ /** Returns the start postion used for distance measurement. */
+ public Point3d getStartPosition () {
+ return start;
+ }
+
+ /** Selects all the nodes that intersect the PickShape.
+ @return An array of PickInfo.SCENEGRAPHPATH
- request for computed SceneGraphPath.
+ * PickInfo.NODE
- request for computed intersected Node.
+ * PickInfo.LOCAL_TO_VWORLD
- request for computed local to virtual world transform.
+ * PickInfo.CLOSEST_INTERSECTION_POINT
- request for closest intersection point.
+ * PickInfo.CLOSEST_DISTANCE
- request for the distance of closest intersection.
+ * PickInfo.CLOSEST_GEOM_INFO
- request for only the closest intersection geometry information.
+ * PickInfo.ALL_GEOM_INFO
- request for all intersection geometry information.
+ * PickInfo
objects which will contain
+ information about the picked instances. null
if nothing was
+ picked.
+ */
+ public PickInfo[] pickAll () {
+ PickInfo[] pickInfos = null;
+ if (pickRootBG != null) {
+ pickInfos = pickRootBG.pickAll(mode, flags, pickShape);
+ } else if (pickRootL != null) {
+ pickInfos = pickRootL.pickAll(mode, flags, pickShape);
+ }
+ return pickInfos;
+ }
+
+ /** Select one of the nodes that intersect the PickShape
+ @return A PickInfo
object which will contain
+ information about the picked instance. null
if nothing
+ was picked.
+ */
+ public PickInfo pickAny () {
+ PickInfo pickInfo = null;
+ if (pickRootBG != null) {
+ pickInfo = pickRootBG.pickAny(mode, flags, pickShape);
+ } else if (pickRootL != null) {
+ pickInfo = pickRootL.pickAny(mode, flags, pickShape);
+ }
+ return pickInfo;
+ }
+
+ /** Select all the nodes that intersect the
+ PickShape, returned sorted. The "closest" object will be returned first.
+ See note above to see how "closest" is determined.
+ PickInfo
objects which will contain
+ information
+ about the picked instances. null
if nothing was picked.
+ */
+ public PickInfo[] pickAllSorted () {
+ PickInfo[] pickInfos = null;
+ if (pickRootBG != null) {
+ pickInfos = pickRootBG.pickAllSorted(mode, flags, pickShape);
+ } else if (pickRootL != null) {
+ pickInfos = pickRootL.pickAllSorted(mode, flags, pickShape);
+ }
+ return pickInfos;
+ }
+
+ /** Select the closest node that
+ intersects the PickShape. See note above to see how "closest" is
+ determined.
+ PickInfo
object which will contain
+ information about the picked instance. null
if nothing
+ was picked.
+ */
+ public PickInfo pickClosest () {
+ // System.out.println("PickTool : pickClosest ...");
+ PickInfo pickInfo = null;
+ if (pickRootBG != null) {
+ pickInfo = pickRootBG.pickClosest(mode, flags, pickShape);
+ } else if (pickRootL != null) {
+ pickInfo = pickRootL.pickClosest(mode, flags, pickShape);
+ }
+ // System.out.println(" -- pickInfo is " + pickInfo);
+
+ return pickInfo;
+ }
+
+ /** Get the first node of a certain type up the SceneGraphPath
+ *@param type the type of node we are interested in
+ *@return a Node object
+ *
+ * @exception NullPointerException if pickInfo does not contain a
+ * Scenegraphpath or a picked node
+ */
+
+ public Node getNode (PickInfo pickInfo, int type) {
+
+ // System.out.println("pickInfo is " + pickInfo);
+
+ if (pickInfo == null) {
+ return null;
+ }
+
+ SceneGraphPath sgp = pickInfo.getSceneGraphPath();
+ Node pickedNode = pickInfo.getNode();
+ // System.out.println("sgp = " + sgp + " pickedNode = " + pickedNode);
+
+
+ /*
+ * Do not check for null for pickNode and sgp.
+ * Will throw NPE if pickedNode or sgp isn't set in pickInfo
+ */
+
+ if ((pickedNode instanceof Shape3D) && ((type & TYPE_SHAPE3D) != 0)){
+ if (debug) System.out.println("Shape3D found");
+ return pickedNode;
+ }
+ else if ((pickedNode instanceof Morph) && ((type & TYPE_MORPH) != 0)){
+ if (debug) System.out.println("Morph found");
+ return pickedNode;
+ }
+ else {
+ for (int j=sgp.nodeCount()-1; j>=0; j--){
+ Node pNode = sgp.getNode(j);
+ if (debug) System.out.println("looking at node " + pNode);
+
+ if ((pNode instanceof Primitive) &&
+ ((type & TYPE_PRIMITIVE) != 0)){
+ if (debug) System.out.println("Primitive found");
+ return pNode;
+ }
+ else if ((pNode instanceof Link) && ((type & TYPE_LINK) != 0)){
+ if (debug) System.out.println("Link found");
+ return pNode;
+ }
+ else if ((pNode instanceof Switch) && ((type & TYPE_SWITCH) != 0)){
+ if (debug) System.out.println("Switch found");
+ return pNode;
+ }
+ else if ((pNode instanceof TransformGroup) &&
+ ((type & TYPE_TRANSFORM_GROUP) != 0)){
+ if (debug) System.out.println("xform group found");
+ return pNode;
+ }
+ else if ((pNode instanceof BranchGroup) &&
+ ((type & TYPE_BRANCH_GROUP) != 0)){
+ if (debug) System.out.println("Branch group found");
+ return pNode;
+ }
+ else if ((pNode instanceof Group) && ((type & TYPE_GROUP) != 0)){
+ if (debug) System.out.println("Group found");
+ return pNode;
+ }
+ }
+ }
+ return null; // should not be reached
+ }
+
+
+} // PickTool
+
+
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickMouseBehavior.java b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickMouseBehavior.java
new file mode 100644
index 0000000..3b1862f
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickMouseBehavior.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.pickfast.behaviors;
+
+import java.awt.AWTEvent;
+import java.awt.Event;
+import java.awt.event.MouseEvent;
+import java.util.Enumeration;
+
+import org.jogamp.java3d.Behavior;
+import org.jogamp.java3d.Bounds;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.TransformGroup;
+import org.jogamp.java3d.WakeupCriterion;
+import org.jogamp.java3d.WakeupOnAWTEvent;
+import org.jogamp.java3d.WakeupOr;
+
+import org.jogamp.java3d.utils.pickfast.PickCanvas;
+import org.jogamp.java3d.utils.pickfast.PickTool;
+
+
+/**
+ * Base class that allows users to adding picking and mouse manipulation to
+ * the scene graph (see PickDragBehavior for an example of how to extend
+ * this base class). This class is useful for interactive apps.
+ */
+
+public abstract class PickMouseBehavior extends Behavior {
+
+ protected PickCanvas pickCanvas;
+
+ protected WakeupCriterion[] conditions;
+ protected WakeupOr wakeupCondition;
+ protected boolean buttonPress = false;
+
+ protected TransformGroup currGrp;
+ protected static final boolean debug = false;
+ protected MouseEvent mevent;
+
+ /**
+ * Creates a PickMouseBehavior given current canvas, root of the tree to
+ * operate on, and the bounds.
+ */
+ public PickMouseBehavior(Canvas3D canvas, BranchGroup root, Bounds bounds){
+ super();
+ currGrp = new TransformGroup();
+ currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+ currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
+ root.addChild(currGrp);
+ pickCanvas = new PickCanvas(canvas, root);
+ }
+
+ /**
+ * Sets the pick mode
+ * @see PickTool#setMode
+ **/
+ public void setMode(int pickMode) {
+ pickCanvas.setMode(pickMode);
+ }
+
+ /**
+ * Returns the pickMode
+ * @see PickTool#getMode
+ */
+
+ public int getMode() {
+ return pickCanvas.getMode();
+ }
+
+ /**
+ * Sets the pick tolerance
+ * @see PickCanvas#setTolerance
+ */
+ public void setTolerance(float tolerance) {
+ pickCanvas.setTolerance(tolerance);
+ }
+
+ /**
+ * Returns the pick tolerance
+ * @see PickCanvas#getTolerance
+ */
+ public float getTolerance() {
+ return pickCanvas.getTolerance();
+ }
+
+ @Override
+ public void initialize() {
+
+ conditions = new WakeupCriterion[2];
+ conditions[0] = new WakeupOnAWTEvent(Event.MOUSE_MOVE);
+ conditions[1] = new WakeupOnAWTEvent(Event.MOUSE_DOWN);
+ wakeupCondition = new WakeupOr(conditions);
+
+ wakeupOn(wakeupCondition);
+ }
+
+ private void processMouseEvent(MouseEvent evt) {
+ buttonPress = false;
+
+ if (evt.getID()==MouseEvent.MOUSE_PRESSED |
+ evt.getID()==MouseEvent.MOUSE_CLICKED) {
+ buttonPress = true;
+ return;
+ }
+ else if (evt.getID() == MouseEvent.MOUSE_MOVED) {
+ // Process mouse move event
+ }
+ }
+
+ @Override
+ public void processStimulus (Enumeration criteria) {
+ WakeupCriterion wakeup;
+ AWTEvent[] evt = null;
+ int xpos = 0, ypos = 0;
+
+ while(criteria.hasMoreElements()) {
+ wakeup = (WakeupCriterion)criteria.nextElement();
+ if (wakeup instanceof WakeupOnAWTEvent)
+ evt = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
+ }
+
+ if (evt[0] instanceof MouseEvent){
+ mevent = (MouseEvent) evt[0];
+
+ if (debug)
+ System.out.println("got mouse event");
+ processMouseEvent((MouseEvent)evt[0]);
+ xpos = mevent.getPoint().x;
+ ypos = mevent.getPoint().y;
+ }
+
+ if (debug)
+ System.out.println("mouse position " + xpos + " " + ypos);
+
+ if (buttonPress){
+ updateScene(xpos, ypos);
+ }
+ wakeupOn (wakeupCondition);
+ }
+
+
+ /** Subclasses shall implement this update function
+ */
+ public abstract void updateScene(int xpos, int ypos);
+
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickRotateBehavior.java b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickRotateBehavior.java
new file mode 100644
index 0000000..3913175
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/PickRotateBehavior.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.pickfast.behaviors;
+
+import org.jogamp.java3d.Bounds;
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.PickInfo;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.TransformGroup;
+
+import org.jogamp.java3d.utils.behaviors.mouse.MouseBehaviorCallback;
+import org.jogamp.java3d.utils.behaviors.mouse.MouseRotate;
+import org.jogamp.java3d.utils.pickfast.PickTool;
+
+/**
+ * A mouse behavior that allows user to pick and rotate scene graph objects.
+ * Common usage:
+ *
+ *
+ * PickRotateBehavior behavior = new PickRotateBehavior(canvas, root, bounds);
+ * root.addChild(behavior);
+ *
setupCallback
method.
+ * When the picked object moves, the registered object's
+ * transformChanged
method is invoked.
+ */
+
+public interface PickingCallback {
+
+ public final static int ROTATE=0;
+ public final static int TRANSLATE=1;
+ public final static int ZOOM=2;
+
+ /**
+ * The user made a selection but nothing was
+ * actually picked
+ */
+ public final static int NO_PICK=3;
+
+ /**
+ * Called by the Pick Behavior with which this callback
+ * is registered each time the Picked object is moved
+ */
+ public void transformChanged( int type, TransformGroup tg );
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/package.html b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/package.html
new file mode 100644
index 0000000..e814f82
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/pickfast/behaviors/package.html
@@ -0,0 +1,11 @@
+
+
+
+ *
+ * PickCanvas pickCanvas = new PickCanvas(canvas, scene);
+ * pickCanvas.setMode(PickTool.GEOMETRY_INTERSECT_INFO);
+ * pickCanvas.setTolerance(4.0f);
+ *
+ *
+ * pickCanvas.setShapeLocation(mouseEvent);
+ * PickResult[] results = pickCanvas.pickAll();
+ *
org.jogamp.java3d.utils.geometry.Primitive)
.
+ * For example, the intersection would indicate which triangle out of a
+ * triangle strip was intersected.
+ * The methods which return primitive data will have one value if the primitive
+ * is
+ * a point, two values if the primitive is a line, three values if the primitive
+ * is a triangle and four values if the primitive is quad.
+ *
+ *
+ * Vector3f getNormal(PickIntersection pi, int vertexIndex) {
+ * int index;
+ * Vector3d normal = new Vector3f();
+ * GeometryArray ga = pickIntersection.getGeometryArray();
+ * if (pickIntersection.geometryIsIndexed()) {
+ * index = ga.getNormalIndex(vertexIndex);
+ * } else {
+ * index = vertexIndex;
+ * }
+ * ga.getNormal(index, normal);
+ * return normal;
+ * }
+ *
PickTool.setCapabilties(Node, int)
+ * can be used to set the capability bits
+ * to allow this data to be inquired.
+ */
+public class PickIntersection {
+
+ /* OPEN ISSUES:
+ -- Tex coordinates always use texCoordSet == 0.
+ */
+
+ /* =================== ATTRIBUTES ======================= */
+
+
+ // init by constructor:
+
+ /** PickResult for intersection is part of */
+ PickResult pickResult = null;
+
+ // init by intersection:
+ /** Distance between start point and intersection point (see comment above)*/
+ double distance = -1;
+
+ /** index of GeometryArray in PickResult */
+ int geomIndex = 0;
+
+ /** Indices of the intersected primitive */
+ int[] primitiveVertexIndices = null;
+
+ /** VWorld coordinates of intersected primitive */
+ Point3d[] primitiveCoordinatesVW = null;
+
+ /** VWorld Coordinates of the intersection point */
+ Point3d pointCoordinatesVW = null;
+
+ // Derived data
+
+ // Geometry
+ GeometryArray geom = null;
+ IndexedGeometryArray iGeom = null;
+ boolean hasNormals = false;
+ boolean hasColors = false;
+ boolean hasTexCoords = false;
+
+ // Primitive
+ /* indices for the different data types */
+ int[] primitiveCoordinateIndices;
+ int[] primitiveNormalIndices;
+ int[] primitiveColorIndices;
+ int[] primitiveTexCoordIndices;
+
+
+ /* Local coordinates of the intersected primitive */
+ Point3d[] primitiveCoordinates = null;
+
+ /* Normals of the intersected primitive */
+ Vector3f[] primitiveNormals = null;
+
+ /* Colors of the intersected primitive */
+ Color4f[] primitiveColors = null;
+
+ /* TextureCoordinates of the intersected primitive */
+ TexCoord3f[] primitiveTexCoords = null;
+
+ // Intersection point
+
+ /** Local Coordinates of the intersection point */
+ Point3d pointCoordinates = null;
+
+ /** Normal at the intersection point */
+ Vector3f pointNormal = null;
+
+ /** Color at the intersection point */
+ Color4f pointColor = null;
+
+ /** TexCoord at the intersection point */
+ TexCoord3f pointTexCoord = null;
+
+ // Closest Vertex
+ /** Index of the closest vertex */
+ int closestVertexIndex = -1;
+
+ /** Coordinates of the closest vertex */
+ Point3d closestVertexCoordinates = null;
+
+ /** Coordinates of the closest vertex (World coordinates) */
+ Point3d closestVertexCoordinatesVW = null;
+
+ /** Weight factors for interpolation, values correspond to vertex indices,
+ * sum == 1
+ */
+ double[] interpWeights;
+
+ static final boolean debug = false;
+
+ // Axis constants
+ static final int X_AXIS = 1;
+ static final int Y_AXIS = 2;
+ static final int Z_AXIS = 3;
+
+ // Tolerance for numerical stability
+ static final double TOL = 1.0e-5;
+
+ /* =================== METHODS ======================= */
+
+ /** Constructor
+ @param pickResult The pickResult this intersection is part of.
+ */
+ PickIntersection (PickResult pr, GeometryArray geomArr) {
+
+ // pr can't be null.
+ pickResult = pr;
+ geom = geomArr;
+ if (geom == null) {
+ GeometryArray[] ga = pickResult.getGeometryArrays();
+ geom = ga[geomIndex];
+
+ }
+
+ if (geom instanceof IndexedGeometryArray) {
+ iGeom = (IndexedGeometryArray)geom;
+ }
+ int vertexFormat = geom.getVertexFormat();
+ hasColors = (0 != (vertexFormat &
+ (GeometryArray.COLOR_3 | GeometryArray.COLOR_4)));
+ hasNormals = (0 != (vertexFormat & GeometryArray.NORMALS));
+ hasTexCoords = (0 != (vertexFormat &
+ (GeometryArray.TEXTURE_COORDINATE_2 |
+ GeometryArray.TEXTURE_COORDINATE_3)));
+ }
+
+ /**
+ String representation of this object
+ */
+ @Override
+ public String toString () {
+ String rt = new String ("PickIntersection: ");
+ rt += " pickResult = "+pickResult + "\n";
+ rt += " geomIndex = "+geomIndex + "\n";
+ if (distance != -1) rt += " dist:"+distance + "\n";
+ if (pointCoordinates != null) rt += " pt:" + pointCoordinates + "\n";
+ if (pointCoordinatesVW != null) rt += " ptVW:" + pointCoordinatesVW + "\n";
+
+ if (primitiveCoordinateIndices != null) {
+ rt += " prim coordinate ind:" + "\n";
+ for (int i=0;iPickTool.setCapabilties(Node, int)
+ * can
+ * be used to ensure correct capabilites are set. Inquiring data which is not
+ * available due to capabilties not being set will generate a
+ * CapabilityNotSet
exception.
+ * getNode(int)
+ * to return a
+ * Shape3D
node from
+ * the SceneGraphPath
.
+ */
+ public static final int SHAPE3D = 0x1;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * Morph
node from
+ * the SceneGraphPath
.
+ */
+ public static final int MORPH = 0x2;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+
+ * to return a
+ * Primitive
node from
+ * the SceneGraphPath
.
+ */
+ public static final int PRIMITIVE = 0x4;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * Link
node from
+ * the SceneGraphPath
.
+ */
+ public static final int LINK = 0x8;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * Group
node from
+ * the SceneGraphPath
.
+ */
+ public static final int GROUP = 0x10;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * TransformGroup
node from
+ * the SceneGraphPath
.
+ */
+ public static final int TRANSFORM_GROUP = 0x20;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * BranchGroup
node from
+ * the SceneGraphPath
.
+ */
+ public static final int BRANCH_GROUP = 0x40;
+
+ /**
+ * Flag to pass to
+ * getNode(int)
+ * to return a
+ * Switch
node from
+ * the SceneGraphPath
.
+ */
+ public static final int SWITCH = 0x80;
+
+
+
+ /* =================== ATTRIBUTES ======================= */
+ static boolean debug = false;
+
+ /** if true, find only the first intersection */
+ private boolean firstIntersectOnly = false;
+
+ /** Stored SceneGraphPath */
+ private SceneGraphPath pickedSceneGraphPath = null;
+
+ /** Picked node: shape3d, text3d, etc. */
+ private Node pickedNode = null;
+
+ /** GeometryArray(s) of the picked node */
+ private GeometryArray[] geometryArrays = null;
+
+ /** Shape3Ds from CompressedGeometry on the picked node */
+ private Shape3D[] compressGeomShape3Ds = null;
+
+ /** Transform to World Coordinates */
+ private Transform3D localToVWorld = null;
+
+ /** the pick shape to use for intersections */
+ private PickShape pickShape = null;
+ /* data derived from the pick shape */
+ private int pickShapeType = -1;
+ private Vector3d pickShapeDir = null;
+ private Point3d pickShapeStart = null;
+ private Point3d pickShapeEnd = null;
+ private Bounds pickShapeBounds = null;
+
+ static final Point3d zeroPnt = new Point3d();
+
+ /** ArrayList to store intersection results
+ * Used in PickTool
+ */
+ ArrayList intersections = null;
+
+ // internal constants used for intersections
+ static final double FUZZ = 1E-6; /* fuzziness factor used to determine
+ if two lines are parallel */
+ static final int PICK_SHAPE_RAY = 1;
+ static final int PICK_SHAPE_SEGMENT = 2;
+ static final int PICK_SHAPE_POINT = 3;
+ static final int PICK_SHAPE_BOUNDING_BOX = 4;
+ static final int PICK_SHAPE_BOUNDING_SPHERE = 5;
+ static final int PICK_SHAPE_BOUNDING_POLYTOPE = 6;
+ static final int PICK_SHAPE_CYLINDER = 7;
+ static final int PICK_SHAPE_CONE = 8;
+
+ static final double EPS = 1.0e-13;
+
+
+ /* =================== METHODS ======================= */
+
+ /** Default constructor. */
+ PickResult () { }
+
+ /** Construct a PickResult using a SceneGraphPath
+ @param sgp SceneGraphPath associated with this PickResult
+ @param ps The pickShape to intersect against
+ */
+ public PickResult (SceneGraphPath sgp, PickShape ps) {
+ pickedSceneGraphPath = sgp;
+ pickedNode = sgp.getObject();
+ localToVWorld = sgp.getTransform();
+ pickShape = ps;
+ initPickShape();
+ }
+
+
+ /** Construct a PickResult using the Node and localToVWorld transform
+ @param pn The picked node.
+ @param l2vw The local to VWorld transformation for the node
+ @param ps The PickShape to intersect against
+ @throws IllegalArgumentException If the node is not a Morph or Shape3D.
+ */
+ public PickResult (Node pn, Transform3D l2vw, PickShape ps) {
+ if ((pn instanceof Shape3D) || (pn instanceof Morph)) {
+ pickedNode = pn;
+ localToVWorld = l2vw;
+ pickShape = ps;
+ initPickShape();
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ void initPickShape() {
+ if(pickShape instanceof PickRay) {
+ if (pickShapeStart == null) pickShapeStart = new Point3d();
+ if (pickShapeDir == null) pickShapeDir = new Vector3d();
+ ((PickRay) pickShape).get (pickShapeStart, pickShapeDir);
+ pickShapeType = PICK_SHAPE_RAY;
+ } else if (pickShape instanceof PickSegment) {
+ if (pickShapeStart == null) pickShapeStart = new Point3d();
+ if (pickShapeEnd == null) pickShapeEnd = new Point3d();
+ if (pickShapeDir == null) pickShapeDir = new Vector3d();
+ ((PickSegment)pickShape).get(pickShapeStart, pickShapeEnd);
+ pickShapeDir.set (pickShapeEnd.x - pickShapeStart.x,
+ pickShapeEnd.y - pickShapeStart.y,
+ pickShapeEnd.z - pickShapeStart.z);
+ pickShapeType = PICK_SHAPE_SEGMENT;
+ } else if (pickShape instanceof PickBounds) {
+ pickShapeBounds = ((PickBounds) pickShape).get();
+ if ( pickShapeBounds instanceof BoundingBox )
+ pickShapeType = PICK_SHAPE_BOUNDING_BOX;
+ else if( pickShapeBounds instanceof BoundingSphere )
+ pickShapeType = PICK_SHAPE_BOUNDING_SPHERE;
+ else if( pickShapeBounds instanceof BoundingPolytope )
+ pickShapeType = PICK_SHAPE_BOUNDING_POLYTOPE;
+ } else if(pickShape instanceof PickPoint) {
+ throw new RuntimeException ("PickPoint doesn't make sense for geometry-based picking. Java 3D doesn't have spatial information of the surface. Should use PickBounds with BoundingSphere and set radius to a epsilon tolerance.");
+ } else if (pickShape instanceof PickCylinder) {
+ pickShapeType = PICK_SHAPE_CYLINDER;
+ } else if (pickShape instanceof PickCone) {
+ pickShapeType = PICK_SHAPE_CONE;
+ } else {
+ throw new
+ RuntimeException("PickShape not supported for intersection");
+ }
+ }
+
+ /** Get the SceneGraphPath. This will be null if the non SceneGraphPath
+ * constructor was used.
+ */
+ public SceneGraphPath getSceneGraphPath() {
+ /* Q: should this return a copy */
+ return pickedSceneGraphPath;
+ }
+
+
+ /** Get the localToVworld transform for the Node
+ */
+ public Transform3D getLocalToVworld() {
+ return localToVWorld;
+ }
+
+ /** Get the GeometryArray at index 0 for the picked node
+ */
+ public GeometryArray getGeometryArray() {
+ if (geometryArrays == null) {
+ storeGeometry();
+ }
+ return geometryArrays[0];
+ }
+
+ /** Get the array of GeometryArrays for the picked node
+ */
+ public GeometryArray[] getGeometryArrays() {
+ if (geometryArrays == null) {
+ storeGeometry();
+ }
+ return geometryArrays;
+ }
+
+ /** Get the number of GeometryArrays for the picked node
+ */
+ public int numGeometryArrays() {
+ if (geometryArrays == null) {
+ storeGeometry();
+ }
+ return geometryArrays.length;
+ }
+
+ /** Get the number of Shape3Ds that came from decompressing a
+ CompressedGeometry on the picked node.
+ */
+ public int numCompressedGeometryShape3Ds() {
+ if (geometryArrays == null) {
+ storeGeometry();
+ }
+ if (compressGeomShape3Ds == null) {
+ return 0;
+ } else {
+ return compressGeomShape3Ds.length;
+ }
+ }
+
+ /** Get the array of Shape3Ds that came from decompressing a
+ CompressedGeometry on the picked node.
+ */
+ public Shape3D[] getCompressedGeometryShape3Ds() {
+ if (geometryArrays == null) {
+ storeGeometry();
+ }
+ if (compressGeomShape3Ds == null) {
+ return null;
+ } else {
+ return compressGeomShape3Ds;
+ }
+ }
+
+ /** Get the PickShape used for intersections
+ */
+ public PickShape getPickShape() {
+ return pickShape;
+ }
+
+ /** Set the PickResult to find only the first intersection of the PickShape
+ * with the Node. The default is false
(all intersections are
+ * found)
+ */
+ public void setFirstIntersectOnly(boolean flag) {
+ firstIntersectOnly = flag;
+ }
+
+ /** Return the "first intersection only" value. */
+ public boolean getFirstPickEnable() {
+ return firstIntersectOnly;
+ }
+
+ /** Returns the number of PickIntersections in the PickResult.
+ @return the number of intersections
+ */
+ public int numIntersections () {
+ if (intersections == null) {
+ generateIntersections();
+ }
+ return intersections.size();
+ }
+
+ /** Returns a specific PickIntersection object
+ @param index the index number
+ @return the PickIntersection referenced by the index number
+ */
+ public PickIntersection getIntersection (int index) {
+ if (intersections == null) {
+ generateIntersections();
+ }
+ return (PickIntersection) intersections.get (index);
+ }
+
+ /** Gets the PickIntersection in this PickResult that is closest to a point
+ @param pt the point to use for distance calculations
+ @return the closest PickIntersection object
+ */
+ public PickIntersection getClosestIntersection (Point3d pt) {
+ PickIntersection pi = null;
+ PickIntersection curPi = null;
+ Point3d curPt = null;
+ double minDist = Double.MAX_VALUE;
+ double curDist = 0.0;
+
+ if (pt == null) return null;
+
+ if (intersections == null) {
+ generateIntersections();
+ }
+
+ for (int i=0;i
+ *
+ * PickTool.setCapabilities(Node, int)
+ * can be used before the scene graph is
+ * made live to set the
+ * capabilities of Shape3D, Morph or Geometry
+ * nodes to allow picking.
+ * setCapabilities(Node, int)
to set
+ * the Node's capabilities to allow intersection tests, but not
+ * inquire information about the intersections (use for GEOMETRY mode).
+ * @see PickTool#setCapabilities
+ */
+ public static final int INTERSECT_TEST = 0x1001;
+
+ /**
+ * Flag to pass to
setCapabilities(Node, int)
to set
+ * the Node's capabilities to allow inquiry of the intersection
+ * coordinate information.
+ * @see PickTool#setCapabilities
+ */
+ public static final int INTERSECT_COORD = 0x1002;
+
+ /**
+ * Flag to pass to
setCapabilities(Node, int)
+ *
+ * Only nodes (not nodeComponents) affect intergraph dependencies
+ */
+ private void addInterGraphDependency( SymbolTableData symbol ) {
+ HashSet set = (HashSet)branchGraphDependencies.get( currentBranchGraphID );
+ if (set==null) {
+ set = new HashSet();
+ branchGraphDependencies.set( currentBranchGraphID, set );
+ }
+
+ set.add(symbol);
+ }
+
+ /**
+ * Update the reference count for the node component.
+ *
+ * Called during NodeComponentState.addSubReference()
+ */
+ public void incNodeComponentRefCount( int nodeID ) {
+ if (nodeID==0) return;
+
+ SymbolTableData symbol = getSymbol( nodeID );
+
+ ((NodeComponentState)symbol.nodeState).addSubReference();
+
+ if (symbol.referenceCount==1)
+ sharedNodes.add( symbol );
+ symbol.referenceCount++;
+ }
+
+ /**
+ * Add a refernce to the specified node
+ * Also returns the nodes id
+ */
+ @Override
+ public int addReference( SceneGraphObject node ) {
+ if (node==null) return 0;
+
+ SymbolTableData symbol = getSymbol( node );
+
+ if (symbol==null) {
+ if (node instanceof org.jogamp.java3d.Node) {
+ symbol = createDanglingSymbol( node );
+ if (symbol.branchGraphID != currentBranchGraphID ) {
+ //System.out.println("------------- Adding Reference "+symbol.nodeID+" "+node ); // TODO - remove
+ addInterGraphDependency( symbol );
+ sharedNodes.add( symbol );
+ }
+ } else {
+ symbol = createNodeComponentSymbol( node );
+ }
+ return symbol.nodeID;
+ } else {
+ return addReference( symbol );
+ }
+ }
+
+ /**
+ * Add a refernce to the specified node
+ * Also returns the nodes id
+ */
+ public int addReference( SymbolTableData symbol ) {
+
+ if (symbol!=null) {
+ if (symbol.referenceCount==1)
+ sharedNodes.add( symbol );
+ symbol.referenceCount++;
+
+ if (symbol.j3dNode instanceof org.jogamp.java3d.NodeComponent && symbol.referenceCount>1) {
+ ((NodeComponentState)symbol.nodeState).addSubReference();
+ }
+
+ if (symbol.branchGraphID != currentBranchGraphID &&
+ symbol.j3dNode instanceof org.jogamp.java3d.Node ) {
+ // System.out.println("------------- Adding Reference "+symbol.nodeID+" "+symbol.j3dNode ); // TODO - remove
+ addInterGraphDependency( symbol );
+ }
+ } else {
+ throw new SGIORuntimeException("Null Symbol");
+ }
+
+ return symbol.nodeID;
+ }
+
+ /**
+ * Add a refernce to the BranchGraph root
+ * Also returns the nodes id
+ *
+ * Used to associate graphs with a locale without storing the graph at the
+ * current time.
+ */
+ public int addBranchGraphReference( SceneGraphObject node, int branchGraphID ) {
+ if (node==null) return 0;
+
+ SymbolTableData symbol = getSymbol( node );
+
+ if (symbol!=null) {
+ if (symbol.referenceCount==1)
+ sharedNodes.add( symbol );
+ symbol.referenceCount++;
+ } else {
+ symbol = new SymbolTableData( nodeID++, node, null, -3 );
+ j3dNodeIndex.put( node, symbol );
+ nodeIDIndex.add( symbol );
+ danglingReferences.put( node, symbol );
+ }
+
+ symbol.branchGraphID = branchGraphID;
+ for(int i=branchGraphs.size(); i to set
+ * the Node's capabilities to allow inquiry of all intersection
+ * information.
+ * @see PickTool#setCapabilities
+ */
+ public static final int INTERSECT_FULL = 0x1004;
+
+ /* ============================ METHODS ============================ */
+
+ /**
+ * Constructor with BranchGroup to be picked.
+ */
+ public PickTool (BranchGroup b) {
+ pickRootBG = b;
+ }
+
+ /** Returns the BranchGroup to be picked if the tool was initialized
+ with a BranchGroup, null otherwise.
+ */
+ public BranchGroup getBranchGroup() {
+ return pickRootBG;
+ }
+
+ /**
+ * Constructor with the Locale to be picked.
+ */
+ public PickTool (Locale l) {
+ pickRootL = l;
+ }
+
+ /**
+ * Returns the Locale to be picked if the tool was initialized with
+ * a Locale, null otherwise.
+ */
+ public Locale getLocale () {
+ return pickRootL;
+ }
+
+
+ /**
+ * @deprecated This method does nothing other than return its
+ * input parameter.
+ */
+ public Locale setBranchGroup (Locale l) {
+ return l;
+ }
+
+ /**
+ * Sets the capabilities on the Node and it's components to allow
+ * picking at the specified detail level.
+ *
+ * without a detail message.
+ */
+ public SGIORuntimeException() {
+ }
+
+
+ /**
+ * Constructs an instance of PickResult
objects which will contain
+ information about the picked instances. null
if nothing was
+ picked.
+ */
+ public PickResult[] pickAll () {
+ PickResult[] retval = null;
+ switch (mode) {
+ case BOUNDS:
+ retval = pickAll(pickShape);
+ break;
+ case GEOMETRY:
+ retval = pickGeomAll(pickShape);
+ break;
+ case GEOMETRY_INTERSECT_INFO:
+ retval = pickGeomAllIntersect(pickShape);
+ break;
+ default:
+ throw new RuntimeException("Invalid pick mode");
+ }
+ return retval;
+ }
+
+ /** Select one of the nodes that intersect the PickShape
+ @return A PickResult
object which will contain
+ information about the picked instance. null
if nothing
+ was picked.
+ */
+ public PickResult pickAny () {
+ PickResult retval = null;
+ switch (mode) {
+ case BOUNDS:
+ retval = pickAny(pickShape);
+ break;
+ case GEOMETRY:
+ retval = pickGeomAny(pickShape);
+ break;
+ case GEOMETRY_INTERSECT_INFO:
+ retval = pickGeomAnyIntersect(pickShape);
+ break;
+ default:
+ throw new RuntimeException("Invalid pick mode");
+ }
+ return retval;
+ }
+
+ /** Select all the nodes that intersect the
+ PickShape, returned sorted. The "closest" object will be returned first.
+ See note above to see how "closest" is determined.
+ PickResult
objects which will contain
+ information
+ about the picked instances. null
if nothing was picked.
+ */
+ public PickResult[] pickAllSorted () {
+ PickResult[] retval = null;
+
+ // System.out.println ("PickTool.pickAllSorted.");
+
+ switch (mode) {
+ case BOUNDS:
+ // System.out.println ("PickTool.pickAllSorted : Bounds");
+ retval = pickAllSorted(pickShape);
+ break;
+ case GEOMETRY:
+ // System.out.println ("PickTool.pickAllSorted : Geometry");
+ // TODO - BugId 4351050.
+ // pickGeomAllSorted is broken for PickCone and PickCylinder :
+ // The current Shape3D.intersect() API doesn't return the distance for
+ // PickCone and PickCylinder.
+ // 2) TODO - BugId 4351579.
+ // pickGeomClosest is broken for multi-geometry Shape3D node :
+ // The current Shape3D.intersect() API does't return the closest intersected
+ // geometry.
+ retval = pickGeomAllSorted(pickShape);
+
+ break;
+ case GEOMETRY_INTERSECT_INFO:
+ // System.out.println ("PickShape " + pickShape);
+ // System.out.println ("PickTool.pickAllSorted : GEOMETRY_INTERSECT_INFO");
+ retval = pickGeomAllSortedIntersect(pickShape);
+ break;
+ default:
+ throw new RuntimeException("Invalid pick mode");
+ }
+ return retval;
+ }
+
+ /** Select the closest node that
+ intersects the PickShape. See note above to see how "closest" is
+ determined.
+ PickResult
object which will contain
+ information about the picked instance. null
if nothing
+ was picked.
+ */
+ public PickResult pickClosest () {
+ PickResult retval = null;
+ switch (mode) {
+ case BOUNDS:
+ retval = pickClosest(pickShape);
+ break;
+ case GEOMETRY:
+ // System.out.println("pickCloset -- Geometry based picking");
+ // 1) TODO - BugId 4351050.
+ // pickGeomClosest is broken for PickCone and PickCylinder :
+ // The current Shape3D.intersect() API doesn't return the distance for
+ // PickCone and PickCylinder.
+ // 2) TODO - BugId 4351579.
+ // pickGeomClosest is broken for multi-geometry Shape3D node :
+ // The current Shape3D.intersect() API does't return the closest intersected
+ // geometry.
+ retval = pickGeomClosest(pickShape);
+
+ break;
+ case GEOMETRY_INTERSECT_INFO:
+ // System.out.println ("PickShape " + pickShape);
+ // System.out.println ("PickTool.pickClosest : GEOMETRY_INTERSECT_INFO");
+ retval = pickGeomClosestIntersect(pickShape);
+ break;
+ default:
+ throw new RuntimeException("Invalid pick mode");
+ }
+ return retval;
+ }
+
+ private PickResult[] pickAll (PickShape pickShape) {
+ PickResult[] pr = null;
+ SceneGraphPath[] sgp = null;
+
+ if (pickRootBG != null) {
+ sgp = pickRootBG.pickAll (pickShape);
+ } else if (pickRootL != null) {
+ sgp = pickRootL.pickAll (pickShape);
+ }
+ if (sgp == null) return null; // no match
+
+ // Create PickResult array
+ pr = new PickResult [sgp.length];
+ for (int i=0;i
+ *
+ * PickRotateBehavior behavior = new PickRotateBehavior(canvas, root, bounds);
+ * root.addChild(behavior);
+ *
setupCallback
method.
+ * When the picked object moves, the registered object's
+ * transformChanged
method is invoked.
+ */
+
+public interface PickingCallback {
+
+ public final static int ROTATE=0;
+ public final static int TRANSLATE=1;
+ public final static int ZOOM=2;
+
+ /**
+ * The user made a selection but nothing was
+ * actually picked
+ */
+ public final static int NO_PICK=3;
+
+ /**
+ * Called by the Pick Behavior with which this callback
+ * is registered each time the Picked object is moved
+ */
+ public void transformChanged( int type, TransformGroup tg );
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/package.html b/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/package.html
new file mode 100644
index 0000000..32ba40f
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/picking/behaviors/package.html
@@ -0,0 +1,12 @@
+
+
+NoSuchNameException
without detail message.
+ */
+ public NamedObjectException() {
+ }
+
+
+ /**
+ * Constructs an NoSuchNameException
with the specified detail message.
+ * @param msg the detail message.
+ */
+ public NamedObjectException(String msg) {
+ super(msg);
+ }
+}
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/ObjectNotLoadedException.java b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/ObjectNotLoadedException.java
new file mode 100644
index 0000000..073ee01
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/ObjectNotLoadedException.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.scenegraph.io;
+
+/**
+ * The named object has not been loaded so it's instance can not be returned
+ */
+public class ObjectNotLoadedException extends java.lang.Exception {
+
+ /**
+ * Creates new ObjectNotLoadedException
without detail message.
+ */
+ public ObjectNotLoadedException() {
+ }
+
+
+ /**
+ * Constructs an ObjectNotLoadedException
with the specified detail message.
+ * @param msg the detail message.
+ */
+ public ObjectNotLoadedException(String msg) {
+ super(msg);
+ }
+}
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphFileReader.java b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphFileReader.java
new file mode 100644
index 0000000..853257e
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphFileReader.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.scenegraph.io;
+
+import java.io.IOException;
+
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.SceneGraphObject;
+
+import org.jogamp.java3d.utils.scenegraph.io.retained.RandomAccessFileControl;
+import org.jogamp.java3d.utils.universe.ConfiguredUniverse;
+
+/**
+ * Read Java3D BranchGraphs and/or Universe from a file. Individual branchgraphs or an
+ * entire Universe can be read and references (shared nodes and components)
+ * between the graphs are handled correctly.
+ */
+public class SceneGraphFileReader extends java.lang.Object {
+
+ private RandomAccessFileControl fileControl;
+
+ /**
+ * Creates new SceneGraphFileReader.
+ */
+ public SceneGraphFileReader( java.io.File file ) throws IOException {
+ fileControl = new RandomAccessFileControl();
+ fileControl.openFile( file );
+ }
+
+ /**
+ * Create and return a ConfiguredUniverse with the PlatformGeometry, ViewerAvatar,
+ * and Locales saved in the file. The MultiTransformGroup between the ViewingPlatform
+ * and the View is also restored. Universe configuration information is retrieved
+ * via ConfiguredUniverse.getConfigURL()
.getBranchGraphPosition
.index
universe
may be null.
+ * This call will overwrite any existing universe, fileDescription and
+ * userData in the file.universe
is not
+ * a supported universe class. Currently SimpleUniverse and ConfiguredUniverse
+ * are supported.
+ */
+ public SceneGraphFileWriter( java.io.File file,
+ SimpleUniverse universe,
+ boolean writeUniverseContent,
+ String fileDescription,
+ java.io.Serializable fileUserData) throws IOException, UnsupportedUniverseException {
+ fileControl = new RandomAccessFileControl();
+ this.file = file;
+ file.createNewFile();
+
+ if (!file.canWrite())
+ throw new IOException( "Can not Write to File" );
+
+ fileControl.createFile( file, universe, writeUniverseContent, fileDescription, fileUserData );
+ }
+
+ /**
+ * Write the graph to the end of the file.
+ *
+ * close() MUST be called when IO is complete. If close() is not called
+ * the file contents will be undefined.
+ */
+ public void writeBranchGraph( BranchGroup graph ) throws IOException {
+ writeBranchGraph( graph, null );
+ }
+
+ /**
+ * Write a branch graph and some user associated data to the
+ * end of the file.
+ *
+ * close() MUST be called when IO is complete. If close() is not called
+ * the file contents will be undefined.
+ */
+ public void writeBranchGraph( BranchGroup graph,
+ java.io.Serializable data ) throws IOException {
+ fileControl.writeBranchGraph( graph, data );
+ }
+
+ /**
+ * Add a named reference to a SceneGraphObject in the file.
+ *
+ * object
must have been written to the file before this method is
+ * called. If the object is not in the file a NamedObjectException will be thrown.
+ *
+ * Adding duplicate names will result in the old name being overwritten.
+ * Different names can reference the same object
+ */
+ public void addObjectName( String name, SceneGraphObject object ) throws NamedObjectException {
+ fileControl.addNamedObject( name, object );
+ }
+
+ /**
+ * Close the file and cleanup internal data structures.
+ */
+ public void close() throws IOException {
+ fileControl.close();
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphIO.java b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphIO.java
new file mode 100644
index 0000000..683e057
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphIO.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.scenegraph.io;
+
+/**
+ * Implement this interface in any classes that subclass a Java3D SceneGraphObject
+ * in order to have your class handled correctly by scenegraph.io.
+ *
+ * More information and example code is provided here.
+ *
+ * Classes that implement this interface MUST have a no-arg constructor
+ */
+public interface SceneGraphIO {
+
+ /**
+ * The method is called before writeSGObject and gives the user the chance
+ * to create references to other Nodes and NodeComponents.
+ *
+ * References take the form of a nodeID, of type integer. Every SceneGraphObject
+ * is assigned a unique ID.
+ *
+ * The user must save the reference information in writeSGObject
+ *
+ * @param ref provides methods to create references to a SceneGraphObject
+ */
+ public void createSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref );
+
+ /**
+ * Within this method the user should restore references to the SceneGraphObjects
+ * whose nodeID's were created with createSceneGraphObjectReferences
+ * This method is called once the all objects in the scenegraph have been loaded.
+ *
+ *
+ * @param ref provides methods to resolve references to a SceneGraphObject
+ */
+ public void restoreSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref );
+
+ /**
+ * This method should store all the local state of the object and any references
+ * to other SceneGraphObjects into out
.
+ *
+ * This is called after data for the parent SceneGraphObject has been written to
+ * the out
.
+ *
+ * @param out the output stream
+ */
+ public void writeSceneGraphObject( java.io.DataOutput out ) throws java.io.IOException;
+
+ /**
+ * This is called after the object has been constructed and the superclass SceneGraphObject
+ * data has been read from in
.
+ *
+ * The user should restore all state infomation written in writeSGObject
+ *
+ * @param in the input stream
+ */
+ public void readSceneGraphObject( java.io.DataInput in ) throws java.io.IOException;
+
+ /**
+ * Flag indicating for children of this object should be saved
+ *
+ * This method only has an effect if this is a subclass of Group.
+ *
+ * If this returns true then all children of this Group will be saved.
+ *
+ * If it returns false then the children are not saved.
+ */
+ public boolean saveChildren();
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphObjectReferenceControl.java b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphObjectReferenceControl.java
new file mode 100644
index 0000000..ed60374
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphObjectReferenceControl.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.scenegraph.io;
+
+/**
+ * Provides and resolves references to SceneGraphObjects to enable
+ * persistant references in user defined SceneGraphObjects implementing
+ * the SceneGraphIO interface.
+ */
+public interface SceneGraphObjectReferenceControl {
+
+ /**
+ * Add a reference to the scenegraph object specified and return
+ * the nodeID for the object
+ *
+ * Use only during the save cycle
+ */
+ public int addReference( org.jogamp.java3d.SceneGraphObject object );
+
+ /**
+ * Given a nodeID return the corresponding scene graph object.
+ *
+ * Use only during the load cycle
+ */
+ public org.jogamp.java3d.SceneGraphObject resolveReference( int nodeID );
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphStateProvider.java b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphStateProvider.java
new file mode 100644
index 0000000..070fad6
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphStateProvider.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.scenegraph.io;
+
+import org.jogamp.java3d.utils.scenegraph.io.state.javax.media.j3d.SceneGraphObjectState;
+
+/**
+ * This interface allows developers to provide their own custom IO control for
+ * subclasses of SceneGraphObjects. As the Scene Graph is being saved any
+ * SceneGraphObject in the graph that implements this interface must provide
+ * it's state class which is responsible for saving the entire state of
+ * that object.
+ */
+public interface SceneGraphStateProvider {
+
+ /**
+ * Returns the State class
+ *
+ * @return Class that will perform the IO for the SceneGraphObject
+ */
+ public Class extends SceneGraphObjectState> getStateClass();
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphStreamReader.java b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphStreamReader.java
new file mode 100644
index 0000000..60bacac
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphStreamReader.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.scenegraph.io;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.Canvas3D;
+
+import org.jogamp.java3d.utils.scenegraph.io.retained.StreamControl;
+import org.jogamp.java3d.utils.universe.ConfiguredUniverse;
+
+/**
+ * Read and create a (set) of Java3D BranchGraphs or Universe from a Java Stream.
+ */
+public class SceneGraphStreamReader extends java.lang.Object {
+
+ private StreamControl control;
+ private DataInputStream in;
+
+ /** Creates new SceneGraphStreamReader and reads the file header information */
+ public SceneGraphStreamReader( InputStream stream ) throws IOException {
+ in = new DataInputStream( stream );
+ control = new StreamControl( in );
+ control.readStreamHeader();
+ }
+
+ /**
+ * Read and create the universe. If the BranchGraphs were written then
+ * they will be added to the universe before it is returned.
+ */
+ public ConfiguredUniverse readUniverse() throws IOException {
+ return control.readUniverse(in, true, null);
+ }
+
+ /**
+ * Read and create the universe. If the BranchGraphs were written then
+ * they will be added to the universe before it is returned.
+ * @param canvas The Canvas3D to associate with the universe.
+ */
+ public ConfiguredUniverse readUniverse(Canvas3D canvas) throws IOException {
+ return control.readUniverse(in, true, canvas);
+ }
+
+ /**
+ * Read and return the graph from the stream.
+ * namedObjects
map will be updated with any objects that
+ * were named during the write process
+ */
+ public BranchGroup readBranchGraph( HashMap namedObjects ) throws IOException {
+ return control.readBranchGraph( namedObjects );
+ }
+
+ /**
+ * Set the ClassLoader used to load the scene graph objects and
+ * deserialize user data
+ */
+ public void setClassLoader( ClassLoader classLoader ) {
+ control.setClassLoader( classLoader );
+ }
+
+ /**
+ * Get the ClassLoader used to load the scene graph objects and
+ * deserialize user data
+ */
+ public ClassLoader getClassLoader() {
+ return control.getClassLoader();
+ }
+
+ /**
+ * Close the SceneGraphStreamReader stream
+ *
+ * @since Java 3D 1.5.1
+ */
+ public void close() throws IOException {
+ in.close();
+ control.close();
+ }
+
+}
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphStreamWriter.java b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphStreamWriter.java
new file mode 100644
index 0000000..103a44d
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/SceneGraphStreamWriter.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.scenegraph.io;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.jogamp.java3d.BranchGroup;
+import org.jogamp.java3d.DanglingReferenceException;
+
+import org.jogamp.java3d.utils.scenegraph.io.retained.StreamControl;
+import org.jogamp.java3d.utils.universe.SimpleUniverse;
+
+/**
+ * Writes a Java3D SceneGraph to a Java OutputStream.universe
to the Stream.writeContent
is true then all BranchGraphs attached to the
+ * universe will be saved. If it is false then only the universe
+ * data structures will be output (PlatformGeometry, ViewerAvatar, Locales,
+ * and the MultiTransformGroup between the ViewingPlatform and the View).writeContent
is true then all the BranchGraphs
+ * attached to the Locales of the universe must have the
+ * ALLOW_DETACH capability set. If they do not, a CapabilityNotSetException
+ * will be thrownnamedObjects
can contain a mapping between a key and a SceneGraphObject
+ * in the graph. During the read process this can be used to locate nodes
+ * in the graph.
+ */
+ public void writeBranchGraph( BranchGroup graph, HashMap namedObjects ) throws IOException, DanglingReferenceException, NamedObjectException {
+ // TODO Add namedObjects to SymbolTable
+ control.addNamedObjects( namedObjects );
+ control.writeBranchGraph( graph, null );
+ }
+
+ /**
+ * Close the SceneGraphStreamWriter and the associated stream
+ */
+ public void close() throws IOException {
+ control.close();
+ out.close();
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/UnresolvedBehavior.java b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/UnresolvedBehavior.java
new file mode 100644
index 0000000..78f8f82
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/UnresolvedBehavior.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.scenegraph.io;
+
+/**
+ * This Behavior is used in place of any behaviors which can not
+ * be instantiated when a scene graph is read. This behavior is
+ * always disabled when it initalizes. It just provides an indicator
+ * in the scene graph that a Behavior is missing.
+ *
+ * This normally means the Behavior is not present in the classpath.
+ */
+public class UnresolvedBehavior extends org.jogamp.java3d.Behavior {
+
+ @Override
+ public void initialize() {
+ setEnable(false);
+ }
+
+ @Override
+ public void processStimulus(java.util.Enumeration enumeration) {
+ }
+
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/UnsupportedUniverseException.java b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/UnsupportedUniverseException.java
new file mode 100644
index 0000000..38d3cd4
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/UnsupportedUniverseException.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.scenegraph.io;
+
+/**
+ * Thrown if the VirtualUniverse subclass is not supported
+ * by the writeUniverse calls.
+ *
+ * Currently only org.jogamp.java3d.utils.universe.SimpleUniverse is supported
+ */
+public class UnsupportedUniverseException extends java.lang.Exception {
+
+ /**
+ * Creates new UnsupportedUniverseException
without detail message.
+ */
+ public UnsupportedUniverseException() {
+ }
+
+
+ /**
+ * Constructs an UnsupportedUniverseException
with the specified detail message.
+ * @param msg the detail message.
+ */
+ public UnsupportedUniverseException(String msg) {
+ super(msg);
+ }
+}
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/doc-files/extensibility.html b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/doc-files/extensibility.html
new file mode 100644
index 0000000..d77e9bd
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/doc-files/extensibility.html
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+Using your own Classes with scenegraph.io
+
+
+public class MyBranchGroup extends org.jogamp.java3d.BranchGroup {
+ private int myData;
+ ....
+}
+
+
+
+
+
+
+
+Behavior Example
+
+
+public class BehaviorIO extends org.jogamp.java3d.Behavior implements SceneGraphIO
+ private TransformGroup target; // The TG on which this behavior acts
+ private int targetRef; // Object Reference for target
+
+ public void createSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
+ targetRef = ref.addReference( target );
+ }
+
+ public void restoreSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
+ target = (TransformGroup)ref.resolveReference( targetRef );
+ }
+
+ public void writeSceneGraphObject( java.io.DataOutput out ) throws IOException {
+ out.writeInt( targetRef );
+ }
+
+ public void readSceneGraphObject( java.io.DataInput in ) throws IOException {
+ targetRef = in.readInt();
+ }
+
+ // This has no effect as this is not a subclass of Group
+ public boolean saveChildren() {
+ return true;
+ }
+
+`BlackBox' Group Example
+
+This example is a Group node that creates its subgraph during
+its instantiation. An example where you might use this is to
+represent some geometry that is loaded from an external file format
+such a OpenFLT.
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/package.html b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/package.html
new file mode 100644
index 0000000..73e795c
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/package.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+public class House extends Group implements SceneGraphIO {
+ public House() {
+ super();
+ this.addChild( OpenFlightLoader.load( "/dir/house.flt" );
+ }
+
+ public void createSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
+ // No references
+ }
+
+ public void restoreSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
+ // No references
+ }
+
+ public void writeSceneGraphObject( java.io.DataOutput out ) throws IOException {
+ // No local state
+ }
+
+ public void readSceneGraphObject( java.io.DataInput in ) throws IOException {
+ // No local state
+ }
+
+ public boolean saveChildren() {
+ // Don't save the children as they will be restored by the openflightloader
+ return false;
+ }
+
+j3d.io.UseSuperClassIfNoChildClass when this property is present the load
+operation will attempt to avoid failure if Scene Graph nodes are not present
+in the classpath. For example if a developer has subclassed BranchGroup with a
+class called MyBG but has not
+implemented the SceneGraphIO interface when the API saves the graph the
+superclass (ie BranchGroup) data will be stored. When the scene is loaded
+normally MyBG must be in the classpath otherwise the load will fail. If this
+property is set then the superclass node (ie BranchGroup) will be instantiated
+when MyBG is missing. Obviously, if MyBG contained any state information
+then this will be lost.
+SGIORuntimeException
+ * with the specified detail message.
+ *
+ * @param msg the detail message.
+ */
+ public SGIORuntimeException(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/retained/StreamControl.java b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/retained/StreamControl.java
new file mode 100644
index 0000000..bb68718
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/scenegraph/io/retained/StreamControl.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.scenegraph.io.retained;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.jogamp.java3d.BranchGroup;
+
+import org.jogamp.java3d.utils.scenegraph.io.state.javax.media.j3d.SceneGraphObjectState;
+
+/**
+ * Provides the infrastructure for ScenGraphStream Reader and Writer
+ */
+public class StreamControl extends Controller {
+
+ protected String FILE_IDENT = new String( "j3dsf" );
+
+ private DataInputStream inputStream;
+ private DataOutputStream outputStream;
+
+ public StreamControl( DataOutputStream out ) {
+ super();
+ outputStream = out;
+ symbolTable = new SymbolTable( this );
+ }
+
+ public StreamControl( DataInputStream in ) {
+ super();
+ inputStream = in;
+ symbolTable = new SymbolTable( this );
+ }
+
+ /**
+ * Prepare the Stream for writing, by sending header information
+ */
+ public void writeStreamHeader() throws IOException {
+ outputStream.writeUTF( FILE_IDENT );
+ outputStream.writeInt( outputFileVersion );
+ }
+
+ public void readStreamHeader() throws IOException {
+ String ident = inputStream.readUTF();
+ if ( ident.equals("demo_j3s") )
+ throw new IOException( "Use Java 3D Fly Through I/O instead of Java 3D Scenegraph I/O" );
+
+ if ( !ident.equals("j3dsf") )
+ throw new IOException(
+ "This is a File - use SceneGraphFileReader instead");
+
+ currentFileVersion = inputStream.readInt();
+
+ if (currentFileVersion > outputFileVersion ) {
+ throw new IOException("Unsupported file version. This file was written using a new version of the SceneGraph IO API, please update your installtion to the latest version");
+ }
+ }
+
+ /**
+ * Add the named objects to the symbol table
+ */
+ public void addNamedObjects( HashMap namedObjects ) {
+ symbolTable.addNamedObjects( namedObjects );
+ }
+
+ /**
+ * The BranchGraph userData is not supported in a stream and will be
+ * ignored.
+ *
+ * However the data in the userData field of the BranchGroup will be
+ * stored in the stream
+ */
+ @Override
+ public void writeBranchGraph( BranchGroup bg, java.io.Serializable userData ) throws IOException {
+ try {
+ SymbolTableData symbol = symbolTable.getSymbol( bg );
+
+ if (symbol==null) {
+ symbol = symbolTable.createSymbol( bg );
+ symbol.branchGraphID = -1; // This is a new BranchGraph so set the ID to -1
+ } // which will cause setBranchGraphRoot to assign a new ID.
+
+ symbolTable.setBranchGraphRoot( symbol, 0 );
+ symbolTable.startUnsavedNodeComponentFrame();
+ SceneGraphObjectState state = createState( bg, symbol );
+ writeObject( outputStream, state );
+ writeNodeComponents( outputStream );
+ symbolTable.endUnsavedNodeComponentFrame();
+
+ if (symbolTable.branchGraphHasDependencies( symbol.branchGraphID ))
+ throw new org.jogamp.java3d.DanglingReferenceException();
+
+ symbolTable.clearUnshared();
+ symbolTable.writeTable( outputStream );
+ } catch( SGIORuntimeException e ) {
+ throw new IOException( e.getMessage() );
+ }
+ }
+
+ public BranchGroup readBranchGraph( HashMap namedObjects ) throws IOException {
+ try {
+ SceneGraphObjectState state = readObject( inputStream );
+ readNodeComponents( inputStream );
+ symbolTable.readTable( inputStream, true );
+
+ symbolTable.setBranchGraphRoot( state.getSymbol(), 0 );
+
+ state.buildGraph();
+
+ if (namedObjects!=null)
+ symbolTable.getNamedObjectMap( namedObjects );
+
+ return (BranchGroup)state.getNode();
+ } catch( SGIORuntimeException e ) {
+ throw new IOException( e.getMessage() );
+ }
+ }
+
+ /**
+ * Read the set of branchgraps.
+ *
+ * Used by readUniverse
+ *
+ * RandomAccessFileControl will read the graphs in the array,
+ * StreamControl expects the graphs to follow the universe in the
+ * stream so it will read graphs.length branchgraphs.
+ */
+ @Override
+ protected void readBranchGraphs( int[] graphs ) throws IOException {
+ for(int i=0; imap
+ */
+ public void addNamedObjects( HashMap map ) {
+ if (map!=null)
+ namedObjects.putAll( map );
+ }
+
+ /**
+ * Return the SceneGraphObject associated with the name
+ */
+ public SceneGraphObject getNamedObject( String name ) throws NamedObjectException, ObjectNotLoadedException {
+ Object obj = namedObjects.get( name );
+ if (obj==null)
+ throw new NamedObjectException( "Unknown name :"+name );
+
+ if (obj instanceof SceneGraphObject)
+ return (SceneGraphObject)obj;
+ else {
+ SymbolTableData symbol = getSymbol( ((Integer)obj).intValue() );
+ if (symbol==null || symbol.j3dNode==null)
+ throw new ObjectNotLoadedException( ((Integer)obj).toString() );
+ return symbol.j3dNode;
+ }
+ }
+
+ /**
+ * Get all the names of the named objects
+ */
+ public String[] getNames() {
+ return (String[])namedObjects.keySet().toArray( new String[] {} );
+ }
+
+ /**
+ * Add the namedObject mappings to map
+ */
+ public void getNamedObjectMap( HashMap map ) {
+ map.putAll( namedObjects );
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+
+ for(int i=0; iformatMatrixRows(3, 3, m)
, where m
is a
+ * an array of doubles retrieved from the given Matrix3d.
+ *
+ * @param m3 matrix to be formatted
+ * @return matrix rows formatted into strings
+ */
+ static String[] formatMatrixRows(Matrix3d m3) {
+ double[] m = new double[9] ;
+ m[0] = m3.m00 ; m[1] = m3.m01 ; m[2] = m3.m02 ;
+ m[3] = m3.m10 ; m[4] = m3.m11 ; m[5] = m3.m12 ;
+ m[6] = m3.m20 ; m[7] = m3.m21 ; m[8] = m3.m22 ;
+
+ return formatMatrixRows(3, 3, m) ;
+ }
+
+ /**
+ * Calls formatMatrixRows(4, 4, m)
, where m
is a
+ * an array of doubles retrieved from the given Matrix4d.
+ *
+ * @param m4 matrix to be formatted
+ * @return matrix rows formatted into strings
+ */
+ static String[] formatMatrixRows(Matrix4d m4) {
+ double[] m = new double[16] ;
+ m[0] = m4.m00 ; m[1] = m4.m01 ; m[2] = m4.m02 ; m[3] = m4.m03 ;
+ m[4] = m4.m10 ; m[5] = m4.m11 ; m[6] = m4.m12 ; m[7] = m4.m13 ;
+ m[8] = m4.m20 ; m[9] = m4.m21 ; m[10] = m4.m22 ; m[11] = m4.m23 ;
+ m[12] = m4.m30 ; m[13] = m4.m31 ; m[14] = m4.m32 ; m[15] = m4.m33 ;
+
+ return formatMatrixRows(4, 4, m) ;
+ }
+
+ /**
+ * Formats a matrix with fixed fractional digits and integer padding to
+ * align the decimal points in columns. Non-negative numbers print up to
+ * 7 integer digits, while negative numbers print up to 6 integer digits
+ * to account for the negative sign. 6 fractional digits are printed.
+ *
+ * @param rowCount number of rows in the matrix
+ * @param colCount number of columns in the matrix
+ * @param m matrix to be formatted
+ * @return matrix rows formatted into strings
+ */
+ static String[] formatMatrixRows(int rowCount, int colCount, double[] m) {
+ DecimalFormat df = new DecimalFormat("0.000000") ;
+ FieldPosition fp = new FieldPosition(DecimalFormat.INTEGER_FIELD) ;
+ StringBuffer sb0 = new StringBuffer() ;
+ StringBuffer sb1 = new StringBuffer() ;
+ String[] rows = new String[rowCount] ;
+
+ for (int i = 0 ; i < rowCount ; i++) {
+ sb0.setLength(0) ;
+ for (int j = 0 ; j < colCount ; j++) {
+ sb1.setLength(0) ;
+ df.format(m[i*colCount+j], sb1, fp) ;
+ int pad = 8 - fp.getEndIndex() ;
+ for (int k = 0 ; k < pad ; k++) {
+ sb1.insert(0, " ") ;
+ }
+ sb0.append(sb1) ;
+ }
+ rows[i] = sb0.toString() ;
+ }
+ return rows ;
+ }
+
+ /**
+ * Returns the String representation of this command.
+ *
+ * @return string representing this command
+ */
+ @Override
+ public String toString() {
+ String[] lines = null ;
+ StringBuffer sb = new StringBuffer("(") ;
+
+ for (int i = 0 ; i < argc ; i++) {
+ if (argv[i] instanceof Matrix3d) {
+ lines = formatMatrixRows((Matrix3d)argv[i]) ;
+ sb.append("\n ((" + lines[0] + ")\n") ;
+ sb.append(" (" + lines[1] + ")\n") ;
+ sb.append(" (" + lines[2] + "))") ;
+ if (i != (argc - 1)) sb.append("\n") ;
+ }
+ else if (argv[i] instanceof Matrix4d) {
+ lines = formatMatrixRows((Matrix4d)argv[i]) ;
+ sb.append("\n ((" + lines[0] + ")\n") ;
+ sb.append(" (" + lines[1] + ")\n") ;
+ sb.append(" (" + lines[2] + ")\n") ;
+ sb.append(" (" + lines[3] + "))") ;
+ if (i != (argc - 1)) sb.append("\n") ;
+ }
+ else {
+ if (i > 0) sb.append(" ") ;
+ sb.append(argv[i].toString()) ;
+ }
+ }
+
+ sb.append(")") ;
+ return sb.toString() ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfigContainer.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigContainer.java
new file mode 100644
index 0000000..1a7001b
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigContainer.java
@@ -0,0 +1,1544 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StreamTokenizer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Loads a Java 3D configuration file and creates a container of named objects
+ * that will effect the viewing configuration specified in the file. These
+ * can include Viewers, ViewingPlatforms, ViewPlatformBehaviors, InputDevices,
+ * Sensors, and other objects.NewObject
and ObjectProperty
configuration
+ * commands.
+ *
+ * @see ConfiguredUniverse
+ * @see
+ * The Java 3D Configuration File
+ * @see
+ * Example Configuration Files
+ *
+ * @since Java 3D 1.3.1
+ */
+public class ConfigContainer {
+ //
+ // The configuration object database is implemented with a HashMap which
+ // maps their class names to ArrayList objects which contain the actual
+ // instances. The latter are used since the instances of a given class
+ // must be evaluated in the order in which they were created.
+ // LinkedHashMap is available in JDK 1.4 but currently this code must run
+ // under JDK 1.3.1 as well.
+ //
+ private Map baseNameMap = new HashMap() ;
+
+ // Map containing named canvases for each view.
+ private Map viewCanvasMap = new HashMap() ;
+
+ // Read-only Maps for the public interface to the configuration database.
+ private ReadOnlyMap bodyMap = null ;
+ private ReadOnlyMap environmentMap = null ;
+ private ReadOnlyMap viewerMap = null ;
+ private ReadOnlyMap deviceMap = null ;
+ private ReadOnlyMap sensorMap = null ;
+ private ReadOnlyMap behaviorMap = null ;
+ private ReadOnlyMap platformMap = null ;
+ private ReadOnlyMap genericObjectMap = null ;
+
+ // Read-only Sets for the public interface to the configuration database.
+ private ReadOnlySet bodies = null ;
+ private ReadOnlySet environments = null ;
+ private ReadOnlySet viewers = null ;
+ private ReadOnlySet devices = null ;
+ private ReadOnlySet sensors = null ;
+ private ReadOnlySet behaviors = null ;
+ private ReadOnlySet platforms = null ;
+ private ReadOnlySet genericObjects = null ;
+
+ // The number of TransformGroups to include in ViewingPlatforms.
+ private int transformCount = 1 ;
+
+ // The visibility status of Viewer AWT components.
+ private boolean setVisible = false ;
+
+ private ClassLoader classLoader = ClassLoader.getSystemClassLoader();
+
+ /**
+ * The name of the file this ConfigContainer is currently loading.
+ */
+ String currentFileName = null ;
+
+ /**
+ * Creates a new ConfigContainer and loads the configuration file at the
+ * specified URL. All ViewingPlatform instances are created with a single
+ * TransformGroup and all Viewer components are initially invisible.
+ *
+ * @param userConfig URL of the configuration file to load
+ */
+ public ConfigContainer(URL userConfig) {
+ this(userConfig, false, 1, true) ;
+ }
+
+ /**
+ * Creates a new ConfigContainer and loads the configuration file at the
+ * specified URL. All ViewingPlatform instances are created with a single
+ * TransformGroup and all Viewer components are initially invisible.
+ *
+ * @param userConfig URL of the configuration file to load
+ * @param classLoader the class loader to use to load classes specified
+ * in the config file.
+ */
+ public ConfigContainer(URL userConfig, ClassLoader classLoader) {
+ this(userConfig, false, 1, true, classLoader) ;
+ }
+
+ /**
+ * Creates a new ConfigContainer and loads the configuration file at the
+ * specified URL. Any ViewingPlatform instantiated by the configuration
+ * file will be created with the specified number of transforms. Viewer
+ * components may be set initially visible or invisible with the
+ * setVisible
flag.
+ *
+ * @param userConfig URL of the configuration file to load
+ * @param setVisible if true, setVisible(true)
is called on
+ * all Viewers
+ * @param transformCount number of transforms to be included in any
+ * ViewingPlatform created; must be greater than 0
+ */
+ public ConfigContainer(URL userConfig,
+ boolean setVisible, int transformCount) {
+
+ this(userConfig, setVisible, transformCount, true) ;
+ }
+
+ /**
+ * Creates a new ConfigContainer and loads the configuration file at the
+ * specified URL. Any ViewingPlatform instantiated by the configuration
+ * file will be created with the specified number of transforms. Viewer
+ * components may be set initially visible or invisible with the
+ * setVisible
flag.
+ *
+ * @param userConfig URL of the configuration file to load
+ * @param setVisible if true, setVisible(true)
is called on
+ * all Viewers
+ * @param transformCount number of transforms to be included in any
+ * ViewingPlatform created; must be greater than 0
+ * @param classLoader the class loader to use to load classes specified
+ * in the config file.
+ */
+ public ConfigContainer(URL userConfig,
+ boolean setVisible, int transformCount,
+ ClassLoader classLoader) {
+
+ this(userConfig, setVisible, transformCount, true, classLoader) ;
+ }
+
+ /**
+ * Package-scoped constructor for ConfigContainer. This provides an
+ * additional flag, attachBehaviors
, which indicates whether
+ * or not ViewPlatformBehaviors should be attached to the ViewingPlatforms
+ * specified for them.setViewingPlatform
in order to look up the actual Sensor,
+ * Viewer, Behavior, etc., instances associated with the names provided
+ * them from the configuration file.initialize
method is called,
+ * or to 2) define properties that accept object instances directly, and
+ * then use the newer Device, Sensor, ViewPlatform, etc., built-in
+ * commands in the configuration file. These built-ins will return an
+ * object instance from a name.
+ *
+ * @param userConfig URL of the configuration file to load
+ * @param setVisible if true, setVisible(true)
is called on
+ * all Viewers
+ * @param transformCount number of transforms to be included in any
+ * ViewingPlatform created; must be greater than 0
+ * @param attachBehaviors if true, attach ViewPlatformBehaviors to the
+ * appropriate ViewingPlatforms
+ */
+ ConfigContainer(URL userConfig, boolean setVisible,
+ int transformCount, boolean attachBehaviors) {
+
+ if (transformCount < 1)
+ throw new IllegalArgumentException
+ ("transformCount must be greater than 0") ;
+
+ loadConfig(userConfig) ;
+ processConfig(setVisible, transformCount, attachBehaviors) ;
+ }
+
+ /**
+ * Package scoped constructor that adds the ability to set the ClassLoader
+ * which will be used to load any app specific classes specified in the
+ * configuration file. By default SystemClassLoader is used.
+ */
+ ConfigContainer(URL userConfig, boolean setVisible,
+ int transformCount, boolean attachBehaviors,
+ ClassLoader classLoader) {
+ this(userConfig, setVisible, transformCount, attachBehaviors);
+ this.classLoader = classLoader;
+ }
+
+ /**
+ * Open, parse, and load the contents of a configuration file.
+ *
+ * @param userConfig location of the configuration file
+ */
+ private void loadConfig(URL userConfig) {
+ InputStream inputStream = null ;
+ StreamTokenizer streamTokenizer = null ;
+ String lastFileName = currentFileName ;
+
+ currentFileName = userConfig.toString() ;
+ try {
+ inputStream = userConfig.openStream() ;
+ Reader r = new BufferedReader(new InputStreamReader(inputStream)) ;
+ streamTokenizer = new StreamTokenizer(r) ;
+ }
+ catch (IOException e) {
+ throw new IllegalArgumentException(
+ e + "\nUnable to open " + currentFileName) ;
+ }
+
+ //
+ // Set up syntax tables for the tokenizer.
+ //
+ // It would be nice to allow '/' as a word constituent for URL strings
+ // and Unix paths, but then the scanner won't ignore "//" and "/* */"
+ // comment style syntax. Treating '/' as an ordinary character will
+ // allow comments to work, but then '/' becomes a single token which
+ // has to be concatenated with subsequent tokens to reconstruct the
+ // original word string.
+ //
+ // It is cleaner to just require quoting for forward slashes. '/'
+ // should still be treated as an ordinary character however, so that a
+ // non-quoted URL string or Unix path will be treated as a syntax
+ // error instead of a comment.
+ //
+ streamTokenizer.ordinaryChar('/') ;
+ streamTokenizer.wordChars('_', '_') ;
+ streamTokenizer.wordChars('$', '$') ; // for ${...} Java property
+ streamTokenizer.wordChars('{', '}') ; // substitution in word tokens
+ streamTokenizer.slashSlashComments(true) ;
+ streamTokenizer.slashStarComments(true) ;
+
+ // Create an s-expression parser to use for all top-level (0) commands.
+ ConfigSexpression sexp = new ConfigSexpression() ;
+
+ // Loop through all top-level commands. Boolean.FALSE is returned
+ // after the last one is evaluated.
+ while (sexp.parseAndEval(this, streamTokenizer, 0) != Boolean.FALSE) ;
+
+ // Close the input stream.
+ try {
+ inputStream.close() ;
+ }
+ catch (IOException e) {
+ throw new IllegalArgumentException(
+ e + "\nUnable to close " + currentFileName) ;
+ }
+
+ // Restore current file name.
+ currentFileName = lastFileName ;
+ }
+
+ /**
+ * This method gets called from the s-expression parser to process a
+ * configuration command.
+ *
+ * @param elements tokenized list of sexp elements
+ * @param lineNumber command line number
+ */
+ void evaluateCommand(ArrayList elements, int lineNumber) {
+ ConfigObject co ;
+ ConfigCommand cmd ;
+
+ // Create a command object.
+ cmd = new ConfigCommand(elements, currentFileName, lineNumber) ;
+
+ // Process the command according to its type.
+ switch (cmd.type) {
+ case ConfigCommand.CREATE:
+ co = createConfigObject(cmd) ;
+ addConfigObject(co) ;
+ break ;
+ case ConfigCommand.ALIAS:
+ co = createConfigAlias(cmd) ;
+ addConfigObject(co) ;
+ break ;
+ case ConfigCommand.PROPERTY:
+ co = findConfigObject(cmd.baseName, cmd.instanceName) ;
+ co.setProperty(cmd) ;
+ break ;
+ case ConfigCommand.INCLUDE:
+ if (! (cmd.argv[1] instanceof String)) {
+ throw new IllegalArgumentException
+ ("Include file must be a URL string") ;
+ }
+ URL url = null ;
+ String urlString = (String)cmd.argv[1] ;
+ try {
+ url = new URL(urlString) ;
+ }
+ catch (MalformedURLException e) {
+ throw new IllegalArgumentException(e.toString()) ;
+ }
+ loadConfig(url) ;
+ break ;
+ case ConfigCommand.IGNORE:
+ break ;
+ default:
+ throw new IllegalArgumentException
+ ("Unknown command \"" + cmd.commandName + "\"") ;
+ }
+ }
+
+ /**
+ * Instantiates and initializes an object that extends the ConfigObject
+ * base class. The class name of the object is derived from the
+ * command, which is of the following form:findConfigObjects(baseName, true)
.
+ * Aliases are filtered out so that all returned instances are unique.
+ *
+ * @param baseName base name of desired config object class
+ * @return ArrayList of config object instances of the desired base
+ * class, or null if instances of the base class don't exist
+ */
+ Collection findConfigObjects(String baseName) {
+ return findConfigObjects(baseName, true) ;
+ }
+
+
+ /**
+ * Find instances of config objects with the given base name.
+ *
+ * @param baseName base name of desired config object class
+ * @param filterAlias if true, aliases are filtered out so that all
+ * returned instances are unique
+ * @return ArrayList of config object instances of the desired base
+ * class, or null if instances of the base class don't exist
+ */
+ Collection findConfigObjects(String baseName, boolean filterAlias) {
+ ArrayList instances ;
+
+ instances = (ArrayList)baseNameMap.get(baseName) ;
+ if (instances == null || instances.size() == 0) {
+ return null ; // This is not an error.
+ }
+
+ if (filterAlias) {
+ ArrayList output = new ArrayList() ;
+ for (int i = 0 ; i < instances.size() ; i++) {
+ ConfigObject configObject = (ConfigObject)instances.get(i) ;
+
+ if (! configObject.isAlias) {
+ output.add(configObject) ;
+ }
+ }
+ return output ;
+ }
+ else {
+ return instances ;
+ }
+ }
+
+ /**
+ * Returns the ConfigObject associated with the name in the given
+ * ConfigCommand. This is used for evaluating retained built-in commands
+ * after the config file has already been parsed. The parser won't catch
+ * any of the exceptions generated by this method, so the error messages
+ * are wrapped accordingly.
+ *
+ * @param basename base name of the config object
+ * @param cmd command containing the name in argv[1]
+ * @return the found ConfigObject
+ */
+ private ConfigObject findConfigObject(String baseName, ConfigCommand cmd) {
+ if (cmd.argc != 2 || !(cmd.argv[1] instanceof String))
+ throw new IllegalArgumentException
+ (ConfigObject.errorMessage
+ (cmd, "Parameter must be a single string")) ;
+ try {
+ return findConfigObject(baseName, (String)cmd.argv[1]) ;
+ }
+ catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException
+ (ConfigObject.errorMessage(cmd, e.getMessage())) ;
+ }
+ }
+
+ /**
+ * This method gets called from a ConfigObject to evaluate a retained
+ * built-in command nested within a property command. These are commands
+ * that can't be evaluated until the entire config file is parsed.
+ *
+ * @param cmd the built-in command
+ * @return object representing result of evaluation
+ */
+ Object evaluateBuiltIn(ConfigCommand cmd) {
+ int argc = cmd.argc ;
+ Object[] argv = cmd.argv ;
+
+ if (cmd.commandName.equals("ConfigContainer")) {
+ // return a reference to this ConfigContainer
+ return this ;
+ }
+ else if (cmd.commandName.equals("Canvas3D")) {
+ // Look for canvases in the screen database.
+ return ((ConfigScreen)findConfigObject("Screen", cmd)).j3dCanvas ;
+ }
+ else if (baseNameMap.get(cmd.commandName) != null) {
+ // Handle commands of the form ({objectType} name) that return the
+ // object associated with the name.
+ return findConfigObject(cmd.commandName, cmd).targetObject ;
+ }
+ else {
+ // So far no other retained built-in commands.
+ throw new IllegalArgumentException
+ (ConfigObject.errorMessage(cmd, "Unknown built-in command \"" +
+ cmd.commandName + "\"")) ;
+ }
+ }
+
+ /**
+ * Process the configuration after parsing the configuration file.
+ * Note: the processing order of the various config objects is
+ * significant.
+ *
+ * @param setVisible true if Viewer components should be visible
+ * @param transformCount number of TransformGroups with which
+ * ViewingPlatforms should be created
+ * @param attachBehaviors true if behaviors should be attached to
+ * ViewingPlatforms
+ */
+ private void processConfig(boolean setVisible,
+ int transformCount, boolean attachBehaviors) {
+
+ Collection c, s, pe, vp ;
+ this.setVisible = setVisible ;
+ this.transformCount = transformCount ;
+
+ c = findConfigObjects("PhysicalBody") ;
+ if (c != null) {
+ processPhysicalBodies(c) ;
+ }
+
+ pe = findConfigObjects("PhysicalEnvironment") ;
+ if (pe != null) {
+ processPhysicalEnvironments(pe) ;
+ }
+
+ c = findConfigObjects("View") ;
+ if (c != null) {
+ processViews(c, setVisible) ;
+ }
+
+ c = findConfigObjects("Device") ;
+ s = findConfigObjects("Sensor") ;
+ if (c != null) {
+ processDevices(c, s, pe) ;
+ }
+
+ vp = findConfigObjects("ViewPlatform") ;
+ if (vp != null) {
+ processViewPlatforms(vp, transformCount) ;
+ }
+
+ c = findConfigObjects("ViewPlatformBehavior") ;
+ if (c != null) {
+ processViewPlatformBehaviors(c, vp, attachBehaviors) ;
+ }
+
+ c = findConfigObjects("Object") ;
+ if (c != null) {
+ processGenericObjects(c) ;
+ }
+ }
+
+ // Process config physical environments into Java 3D physical
+ // environments.
+ private void processPhysicalEnvironments(Collection c) {
+ Iterator i = c.iterator() ;
+ while (i.hasNext()) {
+ ConfigPhysicalEnvironment e = (ConfigPhysicalEnvironment)i.next() ;
+ e.targetObject = e.createJ3dPhysicalEnvironment() ;
+ }
+ }
+
+ // Process config physical bodys into Java 3D physical bodies.
+ private void processPhysicalBodies(Collection c) {
+ Iterator i = c.iterator() ;
+ while (i.hasNext()) {
+ ConfigPhysicalBody b = (ConfigPhysicalBody)i.next() ;
+ b.targetObject = b.createJ3dPhysicalBody() ;
+ }
+ }
+
+ // Process config views into Java 3D Views and then create Viewer objects
+ // for them. This should only be called after all physical bodies and
+ // physical environments have been processed.
+ private void processViews(Collection c, boolean setVisible) {
+ Iterator i = c.iterator() ;
+ while (i.hasNext()) {
+ ConfigView v = (ConfigView)i.next() ;
+ v.targetObject = v.createViewer(setVisible) ;
+ }
+ }
+
+ // Process config devices into Java 3D input devices. This should be done
+ // only after all views have been processed, as some InputDevice
+ // implementations require the AWT components associated with a view.
+ private void processDevices(Collection c, Collection s, Collection p) {
+ ConfigDevice cd = null ;
+ Iterator i = c.iterator() ;
+ while (i.hasNext()) {
+ cd = (ConfigDevice)i.next() ;
+ cd.targetObject = cd.createInputDevice() ;
+ }
+
+ // Process device properties only after all InputDevices have been
+ // instantiated. Some InputDevice properties require references
+ // to other InputDevice implementations.
+ i = c.iterator() ;
+ while (i.hasNext()) ((ConfigDevice)i.next()).processProperties() ;
+
+ // Initialize the devices only after all have been instantiated, as
+ // some InputDevices implementations are slaved to the first one
+ // created and will not initialize otherwise (e.g. LogitechTracker).
+ i = c.iterator() ;
+ while (i.hasNext()) {
+ cd = (ConfigDevice)i.next() ;
+ if (! cd.j3dInputDevice.initialize())
+ throw new RuntimeException
+ (cd.errorMessage(cd.creatingCommand,
+ "could not initialize device \"" +
+ cd.instanceName + "\"")) ;
+ }
+
+ // An InputDevice implementation will have created all its Sensors by
+ // the time initialize() returns. Retrieve and configure them here.
+ if (s != null) {
+ i = s.iterator() ;
+ while (i.hasNext()) {
+ ConfigSensor cs = (ConfigSensor)i.next() ;
+ cs.configureSensor() ;
+ cs.targetObject = cs.j3dSensor ;
+ }
+ }
+
+ // Iterate through the PhysicalEnvironments and process the devices.
+ if (p != null) {
+ i = p.iterator() ;
+ while (i.hasNext())
+ ((ConfigPhysicalEnvironment)i.next()).processDevices() ;
+ }
+ }
+
+ // Process config view platforms into Java 3D viewing platforms.
+ private void processViewPlatforms(Collection c, int numTransforms) {
+ Iterator i = c.iterator() ;
+ while (i.hasNext()) {
+ ConfigViewPlatform cvp = (ConfigViewPlatform)i.next() ;
+ cvp.targetObject = cvp.createViewingPlatform(numTransforms) ;
+ }
+ }
+
+ // Process the configured view platform behaviors.
+ private void processViewPlatformBehaviors(Collection behaviors,
+ Collection viewPlatforms,
+ boolean attach) {
+ Iterator i = behaviors.iterator() ;
+ while (i.hasNext()) {
+ ConfigViewPlatformBehavior b =
+ (ConfigViewPlatformBehavior)i.next() ;
+ b.targetObject = b.createViewPlatformBehavior() ;
+ }
+
+ // Process properties only after all behaviors are instantiated.
+ i = behaviors.iterator() ;
+ while (i.hasNext())
+ ((ConfigViewPlatformBehavior)i.next()).processProperties() ;
+
+ // Attach behaviors to platforms after properties processed.
+ if (attach && viewPlatforms != null) {
+ i = viewPlatforms.iterator() ;
+ while (i.hasNext())
+ ((ConfigViewPlatform)i.next()).processBehavior() ;
+ }
+ }
+
+ // Process generic objects.
+ private void processGenericObjects(Collection objects) {
+ Iterator i = objects.iterator() ;
+ while (i.hasNext()) {
+ ConfigObject o = (ConfigObject)i.next() ;
+ o.targetObject = o.createTargetObject() ;
+ }
+
+ // Process properties only after all target objects are instantiated.
+ i = objects.iterator() ;
+ while (i.hasNext()) ((ConfigObject)i.next()).processProperties() ;
+ }
+
+ // Returns a read-only Set containing all unique Java 3D objects of the
+ // specified base class.
+ private ReadOnlySet createSet(String baseName) {
+ Collection c = findConfigObjects(baseName, true) ;
+ if (c == null || c.size() == 0)
+ return null ;
+
+ Iterator i = c.iterator() ;
+ ArrayList l = new ArrayList() ;
+ while (i.hasNext()) l.add(((ConfigObject)i.next()).targetObject) ;
+
+ return new ReadOnlySet(l) ;
+ }
+
+ // Returns a read-only Map that maps all names in the specified base
+ // class, including aliases, to their corresponding Java 3D objects.
+ private ReadOnlyMap createMap(String baseName) {
+ Collection c = findConfigObjects(baseName, false) ;
+ if (c == null || c.size() == 0)
+ return null ;
+
+ Iterator i = c.iterator() ;
+ HashMap m = new HashMap() ;
+ while (i.hasNext()) {
+ ConfigObject co = (ConfigObject)i.next() ;
+ if (co.isAlias)
+ m.put(co.instanceName, co.original.targetObject) ;
+ else
+ m.put(co.instanceName, co.targetObject) ;
+ }
+
+ return new ReadOnlyMap(m) ;
+ }
+
+ /**
+ * Returns a read-only Set of all configured PhysicalBody instances in the
+ * order they were defined in the configuration file.
+ *
+ * PhysicalBody instances are created with the following command:
+ * (NewPhysicalBody <instance name>
+ * [Alias <alias name>])
+ *
+ *
+ * The PhysicalBody is configured through the following command:
+ * (PhysicalBodyProperty <instance name>
+ * <property name> <property value>)
+ *
+ *
+ * @return read-only Set of all unique instances, or null
+ */
+ public Set getPhysicalBodies() {
+ if (bodies != null) return bodies ;
+ bodies = createSet("PhysicalBody") ;
+ return bodies ;
+ }
+
+ /**
+ * Returns a read-only Map that maps PhysicalBody names to instances.
+ * Names may be aliases and if so will map to the original instances.
+ *
+ * @return read-only Map from names to PhysicalBody instances, or null if
+ * no instances
+ */
+ public Map getNamedPhysicalBodies() {
+ if (bodyMap != null) return bodyMap ;
+ bodyMap = createMap("PhysicalBody") ;
+ return bodyMap ;
+ }
+
+ /**
+ * Returns a read-only Set of all configured PhysicalEnvironment instances
+ * in the order they were defined in the configuration file.
+ * (NewPhysicalEnvironment <instance name>
+ * [Alias <alias name>])
+ *
+ *
+ * The PhysicalEnvironment is configured through the following command:
+ * (PhysicalEnvironmentProperty <instance name>
+ * <property name> <property value>)
+ *
+ *
+ * @return read-only Set of all unique instances, or null
+ */
+ public Set getPhysicalEnvironments() {
+ if (environments != null) return environments ;
+ environments = createSet("PhysicalEnvironment") ;
+ return environments ;
+ }
+
+ /**
+ * Returns a read-only Map that maps PhysicalEnvironment names to
+ * instances. Names may be aliases and if so will map to the original
+ * instances.
+ *
+ * @return read-only Map from names to PhysicalEnvironment instances, or
+ * null if no instances
+ */
+ public Map getNamedPhysicalEnvironments() {
+ if (environmentMap != null) return environmentMap ;
+ environmentMap = createMap("PhysicalEnvironment") ;
+ return environmentMap ;
+ }
+
+ /**
+ * Returns a read-only Set of all configured Viewer instances in the order
+ * they were defined in the configuration file. The Viewers will have
+ * incorporated any PhysicalEnvironment and PhysicalBody objects specfied
+ * for them in the configuration file, and will be attached to any
+ * ViewingPlatforms specified for them.
+ * (NewView <instance name> [Alias <alias name>])
+ *
+ *
+ * The Viewer is configured through the following command:
+ * (ViewProperty <instance name>
+ * <property name> <property value>)
+ *
+ *
+ * @return read-only Set of all unique instances, or null
+ */
+ public Set getViewers() {
+ if (viewers != null) return viewers ;
+ viewers = createSet("View") ;
+ return viewers ;
+ }
+
+ /**
+ * Returns a read-only Map that maps Viewer names to instances.
+ * Names may be aliases and if so will map to the original instances.
+ * The Viewers will have incorporated any PhysicalEnvironment and
+ * PhysicalBody objects specfied for them in the configuration file, and
+ * will be attached to any ViewingPlatforms specified for them.
+ * (NewDevice <instanceName> <className>
+ * [Alias <alias name>])
+ *
+ *
+ * className must be the fully-qualified name of a class that
+ * implements the InputDevice interface. The implementation
+ * must provide a parameterless constructor.
+ * (DeviceProperty <instanceName> <propertyName>
+ * <arg0> ... <argn>)
+ *
+ *
+ * propertyName must be the name of a input device method that
+ * takes an array of Objects as its only parameter; the array is populated
+ * with the values of arg0 through argn when the method is
+ * invoked to set the property. These additional requirements for
+ * configurable input devices can usually be fulfilled by extending or
+ * wrapping available InputDevice implementations.
+ *
+ * @return read-only Set of all unique instances, or null
+ */
+ public Set getInputDevices() {
+ if (devices != null) return devices ;
+ devices = createSet("Device") ;
+ return devices ;
+ }
+
+ /**
+ * Returns a read-only Map that maps InputDevice names to instances.
+ * Names may be aliases and if so will map to the original instances. All
+ * InputDevice instances in the map are initialized and registered with
+ * any PhysicalEnvironments that reference them.
+ *
+ * @return read-only Map from names to InputDevice instances, or
+ * null if no instances
+ * @see #getInputDevices
+ */
+ public Map getNamedInputDevices() {
+ if (deviceMap != null) return deviceMap ;
+ deviceMap = createMap("Device") ;
+ return deviceMap ;
+ }
+
+ /**
+ * Returns a read-only Set of all configured Sensor instances in the order
+ * they were defined in the configuration file. The associated
+ * InputDevices are all initialized and registered with any
+ * PhysicalEnvironments that reference them.
+ * (NewSensor <instance name> <device name>
+ * <sensor index> [Alias <alias name>])
+ *
+ *
+ * device name is the instance name of a previously defined
+ * InputDevice, and sensor index is the index of the Sensor to be
+ * bound to instance name. The InputDevice implementation is
+ * responsible for creating its own Sensor objects, so this command does
+ * not create any new instances.
+ * (SensorProperty <instance name> <property name>
+ * <property value>)
+ *
+ *
+ * With the sole exception of the Sensor assigned to the head tracker,
+ * none of the Sensors defined in the configuration file are placed into
+ * the Sensor array maintained by a PhysicalEnvironment.
+ *
+ * @return read-only Set of all unique instances, or null
+ */
+ public Set getSensors() {
+ if (sensors != null) return sensors ;
+ sensors = createSet("Sensor") ;
+ return sensors ;
+ }
+
+ /**
+ * Returns a read-only Map that maps Sensor names to instances. Names may
+ * be aliases and if so will map to the original instances. The
+ * associated InputDevices are all initialized and registered with any
+ * PhysicalEnvironments that reference them.
+ * (NewViewPlatform <instance name>
+ * [Alias <alias name>])
+ *
+ *
+ * The ViewingPlatform is configured through the following command:
+ * (ViewPlatformProperty <instance name> <property name>
+ * <property value>)
+ *
+ *
+ * @return read-only Set of all unique instances, or null
+ */
+ public Set getViewingPlatforms() {
+ if (platforms != null) return platforms ;
+ platforms = createSet("ViewPlatform") ;
+ return platforms ;
+ }
+
+ /**
+ * Returns a read-only Map that maps ViewingPlatform names to instances.
+ * Names may be aliases and if so will map to the original instances. The
+ * ConfigContainer class itself does not attach the ViewingPlatform
+ * instances to any scengraph components or universe Locales; they are not
+ * "live" until made so by a separate client such as ConfiguredUniverse.
+ *
+ * @return read-only Map from names to ViewingPlatform instances, or
+ * null if no instances
+ */
+ public Map getNamedViewingPlatforms() {
+ if (platformMap != null) return platformMap ;
+ platformMap = createMap("ViewPlatform") ;
+ return platformMap ;
+ }
+
+ /**
+ * Returns a read-only Set of all configured ViewPlatformBehavior
+ * instances in the order they were defined in the configuration file.setViewPlatformBehavior
and
+ * setViewingPlatform
methods of ViewingPlatform and
+ * ViewPlatformBehavior have been called if appropriate. However, a
+ * behavior's initialize
method is not called until the
+ * ViewingPlatform to which it is attached is made live.
+ * (NewViewPlatformBehavior <instanceName> <className>)
+ *
+ *
+ * className must be the fully qualified name of a concrete class
+ * that extends the abstract ViewPlatformBehavior class. The
+ * implementation must provide a parameterless constructor.
+ * (ViewPlatformBehaviorProperty <instanceName>
+ * <propertyName> <arg0> ... <argn>)
+ *
+ *
+ * ViewPlatformBehavior subclasses inherit a number of pre-defined
+ * properties that can be directly specified with the propertyName
+ * string; see the configuration file documentation for details.setViewPlatformBehavior
and
+ * setViewingPlatform
methods of ViewingPlatform and
+ * ViewPlatformBehavior have been called if appropriate. However, a
+ * behavior's initialize
method is not called until the
+ * ViewingPlatform to which it is attached is made live.
+ * (ViewProperty <view> Screen <screenName>)
+ *
+ * view is the name of a Viewer created with the NewView command.
+ * The screenName and windowName parameters of the above
+ * commands are the keys to use when looking up the associated Canvas3D
+ * instances in the Map returned by this method. Note: the
+ * NewScreen and NewWindow commands do not create Canvas3D
+ * instances themselves; they are created only by the above configuration
+ * commands.
+ *
+ * @param viewName the name of the Viewer
+ * @return read-only Map containing the Viewer's named Canvas3D instances
+ */
+ public Map getNamedCanvases(String viewName) {
+ Map m = (Map)viewCanvasMap.get(viewName) ;
+ if (m != null) return m ;
+
+ m = new HashMap() ;
+ ConfigView cv = (ConfigView)findConfigObject("View", viewName) ;
+ Iterator i = cv.screens.iterator() ;
+ while (i.hasNext()) {
+ ConfigScreen cs = (ConfigScreen)i.next() ;
+ m.put(cs.instanceName, cs.j3dCanvas) ;
+
+ // The aliases list contains all alias strings for the canvas.
+ Iterator j = cs.aliases.iterator() ;
+ while (j.hasNext()) m.put(j.next(), cs.j3dCanvas) ;
+ }
+ m = new ReadOnlyMap(m) ;
+ viewCanvasMap.put(viewName, m) ;
+ return m ;
+ }
+
+ /**
+ * Returns a read-only Set of all generic configuration object
+ * instances in the order they were defined in the configuration file.
+ * (ViewProperty <view> Window <windowName>)
+ *
+ * (NewObject <instanceName> <className>)
+ *
+ *
+ * className must be the fully-qualified name of a class that
+ * provides a parameterless constructor.
+ * (ObjectProperty <instanceName> <propertyName>
+ * <arg0> ... <argn>)
+ *
+ *
+ * propertyName must be the name of a method provided by object
+ * instanceName. It must take an array of Objects as its only
+ * parameter; the array is populated with the values of arg0
+ * through argn when the method is invoked to set the property.
+ * These additional requirements for configurable objects can usually be
+ * fulfilled by extending or wrapping available object classes.
+ *
+ * @return read-only Set of all unique instances, or null
+ */
+ public Set getGenericObjects() {
+ if (genericObjects != null) return genericObjects ;
+ genericObjects = createSet("Object") ;
+ return genericObjects ;
+ }
+
+ /**
+ * Returns a read-only Map that maps generic object names to
+ * instances. Names may be aliases and if so will map to the original
+ * instances.
+ *
+ * @return read-only Map from names to generic object instances, or
+ * null if no instances
+ * @see #getGenericObjects
+ */
+ public Map getNamedGenericObjects() {
+ if (genericObjectMap != null) return genericObjectMap ;
+ genericObjectMap = createMap("Object") ;
+ return genericObjectMap ;
+ }
+
+ /**
+ * Returns the number of TransformGroups with which ViewingPlatforms
+ * should be created. This is useful for clients that wish to provide a
+ * default ViewingPlatform if the configuration file doesn't specify one.
+ *
+ * @return the number of TransformGroups
+ */
+ public int getViewPlatformTransformCount() {
+ return transformCount ;
+ }
+
+ /**
+ * Returns whether Viewers should be created with their AWT components
+ * initially visible or invisible. This is useful for clients that wish
+ * to provide a default Viewer if the configuration file doesn't specify
+ * one.
+ *
+ * @return true if Viewer components should be initially visible; false
+ * otherwise
+ */
+ public boolean getViewerVisibility() {
+ return setVisible ;
+ }
+
+ /**
+ * Release memory references used by this ConfigContainer. All Sets and
+ * Maps obtained from this ConfigContainer are cleared.
+ */
+ public void clear() {
+ // Clear baseNameList.
+ Iterator i = baseNameMap.values().iterator() ;
+ while (i.hasNext()) ((Collection)i.next()).clear() ;
+ baseNameMap.clear() ;
+
+ // Clear viewCanvasMap.
+ i = viewCanvasMap.values().iterator() ;
+ while (i.hasNext()) ((ReadOnlyMap)i.next()).map.clear() ;
+ viewCanvasMap.clear() ;
+
+ // Release reference to file name.
+ currentFileName = null ;
+
+ // Clear and release sets.
+ if (bodies != null) {
+ bodies.collection.clear() ;
+ bodies = null ;
+ }
+ if (environments != null) {
+ environments.collection.clear() ;
+ environments = null ;
+ }
+ if (devices != null) {
+ devices.collection.clear() ;
+ devices = null ;
+ }
+ if (sensors != null) {
+ sensors.collection.clear() ;
+ sensors = null ;
+ }
+ if (behaviors != null) {
+ behaviors.collection.clear() ;
+ behaviors = null ;
+ }
+ if (platforms != null) {
+ platforms.collection.clear() ;
+ platforms = null ;
+ }
+ if (viewers != null) {
+ viewers.collection.clear() ;
+ viewers = null ;
+ }
+ if (genericObjects != null) {
+ genericObjects.collection.clear() ;
+ genericObjects = null ;
+ }
+
+ // Clear and release maps.
+ if (bodyMap != null) {
+ bodyMap.map.clear() ;
+ bodyMap = null ;
+ }
+ if (environmentMap != null) {
+ environmentMap.map.clear() ;
+ environmentMap = null ;
+ }
+ if (deviceMap != null) {
+ deviceMap.map.clear() ;
+ deviceMap = null ;
+ }
+ if (sensorMap != null) {
+ sensorMap.map.clear() ;
+ sensorMap = null ;
+ }
+ if (behaviorMap != null) {
+ behaviorMap.map.clear() ;
+ behaviorMap = null ;
+ }
+ if (platformMap != null) {
+ platformMap.map.clear() ;
+ platformMap = null ;
+ }
+ if (viewerMap != null) {
+ viewerMap.map.clear() ;
+ viewerMap = null ;
+ }
+ if (genericObjectMap != null) {
+ genericObjectMap.map.clear() ;
+ genericObjectMap = null ;
+ }
+
+ }
+
+ /**
+ * Returns the config file URL based on system properties. The current
+ * implementation of this method parses the j3d.configURL property as a
+ * URL string. For example, the following command line would specify that
+ * the config file is taken from the file "j3dconfig" in the current
+ * directory:
+ *
+ *
+ *
+ * @return the URL of the config file; null is returned if no valid
+ * URL is defined by the system properties
+ */
+ public static URL getConfigURL() {
+ return getConfigURL(null) ;
+ }
+
+ /**
+ * Returns the config file URL based on system properties. The current
+ * implementation of this method parses the j3d.configURL property as a
+ * URL string. For example, the following command line would specify that
+ * the config file is taken from the file "j3dconfig" in the current
+ * directory:
+ * java -Dj3d.configURL=file:j3dconfig ...
+ *
+ *
+ *
+ * @param defaultURLString the default string used to construct
+ * the URL if the appropriate system properties are not defined
+ * @return the URL of the config file; null is returned if no
+ * valid URL is defined either by the system properties or the
+ * default URL string
+ */
+ public static URL getConfigURL(String defaultURLString) {
+ URL url = null ;
+ String urlString = null ;
+ final String defProp = defaultURLString ;
+
+ urlString = (String)java.security.AccessController.doPrivileged
+ (new java.security.PrivilegedAction() {
+ @Override
+ public Object run() {
+ return System.getProperty("j3d.configURL", defProp) ;
+ }
+ }) ;
+
+ if (urlString == null) {
+ return null ;
+ }
+ try {
+ url = new URL(urlString) ;
+ }
+ catch(MalformedURLException e) {
+ System.out.println(e) ;
+ return null ;
+ }
+ return url ;
+ }
+
+ // A general purpose read-only Map backed by a HashMap.
+ private static class ReadOnlyMap extends AbstractMap {
+ HashMap map ;
+ private Set entrySet = null ;
+
+ ReadOnlyMap(Map map) {
+ this.map = new HashMap(map) ;
+ }
+
+ // overridden for efficiency
+ @Override
+ public Object get(Object key) {
+ return map.get(key) ;
+ }
+
+ // overridden for efficiency
+ @Override
+ public boolean containsKey(Object key) {
+ return map.containsKey(key) ;
+ }
+
+ // overridden for efficiency
+ @Override
+ public boolean containsValue(Object value) {
+ return map.containsValue(value) ;
+ }
+
+ @Override
+ public Set entrySet() {
+ if (entrySet == null)
+ entrySet = new ReadOnlySet(map.entrySet()) ;
+
+ return entrySet ;
+ }
+ }
+
+ // A general purpose read-only Set backed by a Collection containing
+ // unique objects.
+ private static class ReadOnlySet extends AbstractSet {
+ Collection collection = null ;
+
+ ReadOnlySet(Collection c) {
+ this.collection = c ;
+ }
+
+ @Override
+ public int size() {
+ return collection.size() ;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return new ReadOnlyIterator(collection.iterator()) ;
+ }
+ }
+
+ // A general purpose read-only Iterator backed by another Iterator.
+ private static class ReadOnlyIterator implements Iterator {
+ private Iterator i ;
+
+ ReadOnlyIterator(Iterator i) {
+ this.i = i ;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return i.hasNext() ;
+ }
+
+ @Override
+ public Object next() {
+ return i.next() ;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException() ;
+ }
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfigDevice.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigDevice.java
new file mode 100644
index 0000000..9b24d2d
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigDevice.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe ;
+import org.jogamp.java3d.InputDevice;
+
+/**
+ * Mostly empty now; ConfigObject provides all required methods.
+ */
+class ConfigDevice extends ConfigObject {
+ /**
+ * The corresponding Java 3D core InputDevice instance.
+ */
+ InputDevice j3dInputDevice ;
+
+ /**
+ * Instantiate an InputDevice of the given class name.
+ *
+ * @return the InputDevice, or null if error
+ */
+ InputDevice createInputDevice() {
+ j3dInputDevice = (InputDevice)createTargetObject() ;
+ return j3dInputDevice ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfigObject.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigObject.java
new file mode 100644
index 0000000..4ad66ca
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigObject.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe ;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for all configuration objects. A ConfigObject processes
+ * configuration parameters for a target object, which is instantiated after
+ * the configuration file is parsed. The ConfigObject then applies its
+ * configuration properties to the target object.java -Dj3d.configURL=file:j3dconfig ...
+ *
+ * (ViewPlatformProperty {instanceName} {attrName} {attrValue})
+ *
+ * @param command the command that invoked this method
+ */
+ @Override
+ protected void setProperty(ConfigCommand command) {
+
+ int argc = command.argc ;
+ Object[] argv = command.argv ;
+ String attribute ;
+ Object value ;
+
+ if (argc != 4) {
+ syntaxError("Incorrect number of arguments to " +
+ command.commandName) ;
+ }
+
+ if (!isName(argv[2])) {
+ syntaxError("The second argument to " + command.commandName +
+ " must be a property name");
+ }
+
+ attribute = (String)argv[2] ;
+ value = argv[3] ;
+
+ if (attribute.equals("NominalViewingTransform")) {
+ if (! (value instanceof Boolean)) {
+ syntaxError("NominalViewingTransform must be a boolean") ;
+ }
+ nominalViewingTransform = ((Boolean)value).booleanValue() ;
+ }
+ else if (attribute.equals("InitialViewingTransform")) {
+ if (! (value instanceof Matrix4d)) {
+ syntaxError("InitialViewingTransform must be a Matrix4d") ;
+ }
+ initialViewingTransform = new Transform3D((Matrix4d)value) ;
+ }
+ else if (attribute.equals("ViewAttachPolicy")) {
+ if (! (value instanceof String)) {
+ syntaxError("ViewAttachPolicy must be a string") ;
+ }
+
+ String svalue = (String)value ;
+
+ if (svalue.equals("NOMINAL_HEAD"))
+ viewAttachPolicy = View.NOMINAL_HEAD ;
+ else if (svalue.equals("NOMINAL_SCREEN"))
+ viewAttachPolicy = View.NOMINAL_SCREEN ;
+ else if (svalue.equals("NOMINAL_FEET"))
+ viewAttachPolicy = View.NOMINAL_FEET ;
+ else
+ syntaxError("Illegal value " +
+ svalue + " for ViewAttachPolicy") ;
+ }
+ else if (attribute.equals("ViewPlatformBehavior")) {
+ if (! (value instanceof String)) {
+ syntaxError("ViewPlatformBehavior must be a name") ;
+ }
+ configBehavior =
+ (ConfigViewPlatformBehavior)configContainer.findConfigObject
+ ("ViewPlatformBehavior", (String)value) ;
+ }
+ else if (attribute.equals("AllowPolicyRead")) {
+ if (!(value instanceof Boolean)) {
+ syntaxError("value for AllowPolicyRead " +
+ "must be a boolean") ;
+ }
+ allowPolicyRead = ((Boolean)value).booleanValue() ;
+ }
+ else if (attribute.equals("AllowLocalToVworldRead")) {
+ if (!(value instanceof Boolean)) {
+ syntaxError("value for AllowLocalToVworldRead " +
+ "must be a boolean") ;
+ }
+ allowLocalToVworldRead = ((Boolean)value).booleanValue() ;
+ }
+ else {
+ syntaxError("Unknown " + command.commandName +
+ " \"" + attribute + "\"") ;
+ }
+ }
+
+ /**
+ * Add a ConfigView to this ConfigViewPlatform.
+ */
+ void addConfigView(ConfigView cv) {
+ configViews.add(cv) ;
+ }
+
+ /**
+ * Creates a ViewingPlatform from attributes gathered by this object.
+ *
+ * @param transformCount the number of TransformGroups to attach to the
+ * ViewingPlatform
+ * @return the new ViewingPlatform
+ */
+ ViewingPlatform createViewingPlatform(int transformCount) {
+
+ // Get the Viewers attached to this ViewingPlatform.
+ // All ConfigViews must be processed at this point.
+ if (configViews.size() == 0) {
+ viewers = new Viewer[0] ;
+ }
+ else {
+ viewers = new Viewer[configViews.size()] ;
+ for (int i = 0 ; i < viewers.length ; i++)
+ viewers[i] = ((ConfigView)configViews.get(i)).j3dViewer ;
+ }
+
+ // Create the viewing platform and get its ViewPlatform instance.
+ viewingPlatform = new ViewingPlatform(transformCount) ;
+ ViewPlatform vp = viewingPlatform.getViewPlatform() ;
+
+ // Set defined policies.
+ if (allowPolicyRead)
+ vp.setCapability(ViewPlatform.ALLOW_POLICY_READ) ;
+
+ if (allowLocalToVworldRead)
+ vp.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ) ;
+
+ if (viewAttachPolicy == -1) {
+ // Apply a default based on the eyepoint policy.
+ boolean nominalHead = true ;
+ for (int i = 0 ; i < viewers.length ; i++) {
+ if (viewers[i].getView().getWindowEyepointPolicy() !=
+ View.RELATIVE_TO_FIELD_OF_VIEW) {
+ nominalHead = false ;
+ break ;
+ }
+ }
+ if (nominalHead)
+ vp.setViewAttachPolicy(View.NOMINAL_HEAD) ;
+ else
+ vp.setViewAttachPolicy(View.NOMINAL_SCREEN) ;
+ }
+ else {
+ vp.setViewAttachPolicy(viewAttachPolicy) ;
+ }
+
+ // Assign the viewing platform to all viewers.
+ for (int i = 0 ; i < viewers.length ; i++) {
+ viewers[i].setViewingPlatform(viewingPlatform) ;
+ }
+
+ // Apply initial viewing transforms if defined.
+ if (nominalViewingTransform) {
+ viewingPlatform.setNominalViewingTransform() ;
+ }
+
+ if (initialViewingTransform != null) {
+ TransformGroup tg = viewingPlatform.getViewPlatformTransform() ;
+ tg.setTransform(initialViewingTransform) ;
+ }
+
+ return viewingPlatform ;
+ }
+
+ /**
+ * Attach any ViewPlatformBehavior specified for this platform.
+ */
+ void processBehavior() {
+ if (configBehavior != null) {
+ viewingPlatform.setViewPlatformBehavior
+ (configBehavior.viewPlatformBehavior) ;
+ }
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/ConfigViewPlatformBehavior.java b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigViewPlatformBehavior.java
new file mode 100644
index 0000000..984192f
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/ConfigViewPlatformBehavior.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe ;
+
+import org.jogamp.java3d.Bounds;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.vecmath.Matrix4d;
+
+import org.jogamp.java3d.utils.behaviors.vp.ViewPlatformBehavior;
+
+class ConfigViewPlatformBehavior extends ConfigObject {
+
+ // All known configurable properties.
+ private Transform3D homeTransform = null ;
+ private Bounds schedulingBounds = null ;
+ private int schedulingInterval = -1 ;
+
+ /**
+ * The corresponding ViewPlatformBehavior instance.
+ */
+ ViewPlatformBehavior viewPlatformBehavior ;
+
+ /**
+ * Processes properties for this object. Handles commands of the form:SimpleUniverse()
. Creates a
+ * Locale, a single ViewingPlatform, and a Viewer object.
+ *
+ * @see SimpleUniverse#SimpleUniverse()
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ */
+ public ConfiguredUniverse() {
+ super();
+ }
+
+ /**
+ * Equivalent to SimpleUniverse(int)
.
+ * Creates a Locale, a single ViewingPlatform with the specified number of
+ * transforms, and a Viewer object.
+ *
+ * @param transformCount the number of transforms in the
+ * MultiTransformGroup object to be created
+ *
+ * @see SimpleUniverse#SimpleUniverse(int)
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ */
+ public ConfiguredUniverse(int transformCount) {
+ super(transformCount);
+ }
+
+ /**
+ * Equivalent to SimpleUniverse(Canvas3D)
.
+ * Creates a Locale, a single ViewingPlatform, and a Viewer object using
+ * the given Canvas3D instance.
+ *
+ * @param canvas the canvas to associate with the Viewer object;
+ * passing in null will cause this parameter to be ignored and a canvas
+ * to be created by the utility
+ *
+ * @see SimpleUniverse#SimpleUniverse(Canvas3D)
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ */
+ public ConfiguredUniverse(Canvas3D canvas) {
+ super(canvas);
+ }
+
+ /**
+ * Equivalent to SimpleUniverse(Canvas3D, int)
.
+ * Creates a Locale, a single ViewingPlatform with the specified number of
+ * transforms, and a Viewer object with the given Canvas3D.
+ *
+ * @param canvas the canvas to associate with the Viewer object;
+ * passing in null will cause this parameter to be ignored and a canvas
+ * to be created by the utility
+ * @param transformCount the number of transforms in the
+ * MultiTransformGroup object to be created
+ *
+ * @see SimpleUniverse#SimpleUniverse(Canvas3D, int)
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ */
+ public ConfiguredUniverse(Canvas3D canvas, int transformCount) {
+ super(canvas, transformCount);
+ }
+
+ /**
+ * Equivalent to SimpleUniverse(ViewingPlatform, Viewer)
.
+ * Creates the view side of the scene graph with the given ViewingPlatform
+ * and Viewer.
+ *
+ * @param viewingPlatform the viewingPlatform to use to create
+ * the view side of the scene graph
+ * @param viewer the viewer object to use to create
+ * the view side of the scene graph
+ *
+ * @see SimpleUniverse#SimpleUniverse(ViewingPlatform, Viewer)
+ * @see ViewingPlatform
+ * @see Viewer
+ */
+ public ConfiguredUniverse(ViewingPlatform viewingPlatform, Viewer viewer) {
+ super(viewingPlatform, viewer, null);
+ }
+
+ /**
+ * Equivalent to SimpleUniverse(ViewingPlatform, Viewer,
+ * LocalFactory)
. Creates the view side of the scene graph with
+ * the given ViewingPlatform, Viewer, and Locale created by the specified
+ * LocaleFactory.
+ *
+ * @param viewingPlatform the viewingPlatform to use to create
+ * the view side of the scene graph
+ * @param viewer the viewer object to use to create
+ * the view side of the scene graph
+ * @param localeFactory the factory object used to create the Locale
+ *
+ * @see SimpleUniverse#SimpleUniverse(ViewingPlatform, Viewer,
+ * LocaleFactory)
+ * @see ViewingPlatform
+ * @see Viewer
+ * @see LocaleFactory
+ */
+ public ConfiguredUniverse(ViewingPlatform viewingPlatform, Viewer viewer,
+ LocaleFactory localeFactory ) {
+ super(viewingPlatform, viewer, localeFactory);
+ }
+
+ /**
+ * Creates a Locale, a single ViewingPlatform, and a Viewer object from
+ * the given array of Canvas3D instances.
+ *
+ * @param canvases the canvases to associate with the Viewer object;
+ * passing in null will cause this parameter to be ignored and a canvas
+ * to be created by the utility
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ */
+ public ConfiguredUniverse(Canvas3D[] canvases) {
+ this(1, canvases, null, null, null, true);
+ }
+
+ /**
+ * Creates a Locale, a single ViewingPlatform with the specified number of
+ * transforms, and a Viewer object using the given array of Canvas3D
+ * instances.
+ *
+ * @param canvases the canvases to associate with the Viewer object;
+ * passing in null will cause this parameter to be ignored and a canvas
+ * to be created by the utility
+ * @param transformCount the number of transforms in the
+ * MultiTransformGroup object to be created
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ */
+ public ConfiguredUniverse(Canvas3D[] canvases, int transformCount) {
+ this(transformCount, canvases, null, null, null, true);
+ }
+
+ /**
+ * Creates a Locale, a single ViewingPlatform with the specified number of
+ * transforms, and a Viewer object using the given array of Canvas3D
+ * instances.
+ *
+ * @param canvases the canvases to associate with the Viewer object;
+ * passing in null will cause this parameter to be ignored and a canvas
+ * to be created by the utility
+ * @param transformCount the number of transforms in the
+ * MultiTransformGroup object to be created
+ * @param localeFactory the factory object used to create the Locale
+ *
+ * @since Java 3D 1.5.1
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ */
+ public ConfiguredUniverse(Canvas3D[] canvases, int transformCount, LocaleFactory localeFactory ) {
+ this(transformCount, canvases, null, localeFactory, null, true);
+ }
+
+ /**
+ * Reads the configuration specified by the given URL to create a Locale,
+ * one or more ViewingPlatforms, and at least one Viewer object. The
+ * configuration file may also create InputDevice, Sensor, and
+ * ViewPlatformBehavior instances.
+ *
+ * @param userConfig the URL to the user's configuration file; passing in
+ * null creates a default Viewer and ViewingPlatform
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ */
+ public ConfiguredUniverse(URL userConfig) {
+ this(1, null, userConfig, null, null, true);
+ }
+
+ /**
+ * Reads the configuration specified by the given URL to create a Locale,
+ * one or more ViewingPlatforms with the specified number of transforms,
+ * and at least one Viewer object. The configuration file may also create
+ * InputDevice, Sensor, and ViewPlatformBehavior instances.
+ *
+ * @param userConfig the URL to the user's configuration file; passing in
+ * null creates a default Viewer and ViewingPlatform with the specified
+ * number of transforms
+ * @param transformCount the number of transforms in the
+ * MultiTransformGroup objects to be created
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ */
+ public ConfiguredUniverse(URL userConfig, int transformCount) {
+ this(transformCount, null, userConfig, null, null, true);
+ }
+
+ /**
+ * Reads the configuration specified by the given URL to create a Locale,
+ * one or more ViewingPlatforms with the specified number of transforms,
+ * and at least one Viewer object with optional visibility. AWT
+ * components used by the Viewers will remain invisible unless the
+ * setVisible
flag is true. The configuration file may also
+ * create InputDevice, Sensor, and ViewPlatformBehavior instances.
+ *
+ * @param userConfig the URL to the user's configuration file; passing in
+ * null creates a default Viewer with the specified visibility and a
+ * ViewingPlatform with the specified number of transforms
+ * @param transformCount the number of transforms in the
+ * MultiTransformGroup object to be created
+ * @param setVisible if true, calls setVisible(true)
on all
+ * created window components; otherwise, they remain invisible
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ */
+ public ConfiguredUniverse(URL userConfig,
+ int transformCount, boolean setVisible) {
+ this(transformCount, null, userConfig, null, null, setVisible);
+ }
+
+ /**
+ * Reads the configuration specified by the given URL to create a Locale
+ * using the given LocaleFactory, one or more ViewingPlatforms, and at
+ * least one Viewer object. The configuration file may also create
+ * InputDevice, Sensor, and ViewPlatformBehavior instances.
+ *
+ * @param userConfig the URL to the user's configuration file; passing in
+ * null creates a default Viewer and ViewingPlatform with the specified
+ * number of transforms
+ * @param localeFactory the factory object used to create the Locale
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ */
+ public ConfiguredUniverse(URL userConfig, LocaleFactory localeFactory) {
+ this(1, null, userConfig, localeFactory, null, true);
+ }
+
+ /**
+ * Reads the configuration specified by the given URL to create a Locale
+ * using the given LocaleFactory, one or more ViewingPlatforms, and at
+ * least one Viewer object with optional visibility. The configuration
+ * file may also create InputDevice, Sensor, and ViewPlatformBehavior
+ * instances. Window components used by the Viewers will remain invisible
+ * unless the setVisible
flag is true.
+ *
+ * @param userConfig the URL to the user's configuration file; passing in
+ * null creates a default Viewer with the specified visibility and a
+ * default ViewingPlatform
+ * @param localeFactory the factory object used to create the Locale
+ * @param setVisible if true, calls setVisible(true)
on all
+ * created window components; otherwise, they remain invisible
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ */
+ public ConfiguredUniverse(URL userConfig,
+ LocaleFactory localeFactory,
+ boolean setVisible) {
+ this(1, null, userConfig, localeFactory, null, setVisible);
+ }
+
+ /**
+ * Reads the configuration specified by the given URL to create a Locale
+ * using the specified LocaleFactory with the given origin, one or more
+ * ViewingPlatforms with the specified number of transforms, and at least
+ * one Viewer object with optional visibility. Window components used by
+ * the Viewers will remain invisible unless the setVisible
+ * flag is true. The configuration file may also create InputDevice,
+ * Sensor, and ViewPlatformBehavior instances.
+ *
+ * @param userConfig the URL to the user's configuration file; passing in
+ * null creates a default Viewer with the specified visibility and a
+ * ViewingPlatform with the specified number of transforms
+ * @param localeFactory the factory object used to create the Locale
+ * @param origin the origin used to set the origin of the Locale object;
+ * if this object is null, then 0.0 is used
+ * @param transformCount the number of transforms in the
+ * MultiTransformGroup object to be created
+ * @param setVisible if true, calls setVisible(true)
on all
+ * created window components; otherwise, they remain invisible
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ */
+ public ConfiguredUniverse(URL userConfig, LocaleFactory localeFactory,
+ HiResCoord origin, int transformCount,
+ boolean setVisible) {
+
+ this(transformCount, null, userConfig,
+ localeFactory, origin, setVisible);
+ }
+
+ /**
+ * Retrieves view-side scenegraph components from the given container to
+ * create a universe with one Locale, one or more ViewingPlatforms, and at
+ * least one Viewer object. Equivalent to
+ * ConfiguredUniverse(ConfigContainer, null, null)
.
+ *
+ * @param userConfig container holding viewing configuration components;
+ * must not be null
+ *
+ * @see #ConfiguredUniverse(ConfigContainer, LocaleFactory, HiResCoord)
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @since Java 3D 1.3.1
+ */
+ public ConfiguredUniverse(ConfigContainer userConfig) {
+ this(userConfig, null, null);
+ }
+
+ /**
+ * Retrieves view-side scenegraph components from the given container to
+ * create a universe with one Locale created from the specified
+ * LocaleFactory and origin, one or more ViewingPlatforms, and at least
+ * one Viewer object. The container may also provide InputDevice, Sensor,
+ * and ViewPlatformBehavior instances which will be incorporated into the
+ * universe if they are referenced by any of the Viewer or ViewingPlatform
+ * instances.ConfiguredUniverse(ConfigContainer)
+ * both accept ConfigContainer references directly and are the preferred
+ * interfaces for constructing universes from configuration files. They
+ * differ from the constructors that accept URL objects in the
+ * following ways:
+ *
+ * @param userConfig container holding viewing configuration components;
+ * must not be null
+ * @param localeFactory the factory object used to create the Locale, or
+ * null
+ * @param origin the origin used to set the origin of the Locale object;
+ * if this object is null, then 0.0 is used
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @since Java 3D 1.3.1
+ */
+ public ConfiguredUniverse(ConfigContainer userConfig,
+ LocaleFactory localeFactory,
+ HiResCoord origin) {
+
+ super(origin, localeFactory);
+ configContainer = userConfig;
+
+ Collection c = configContainer.getViewers();
+ if (c == null || c.size() == 0)
+ throw new IllegalArgumentException(
+ "no views defined in configuration file");
+
+ viewer = (Viewer[])c.toArray(new Viewer[1]);
+
+ c = configContainer.getViewingPlatforms();
+ if (c == null || c.size() == 0) {
+ createDefaultViewingPlatform
+ (configContainer.getViewPlatformTransformCount());
+ }
+ else {
+ Iterator i = c.iterator();
+ while (i.hasNext()) {
+ ViewingPlatform vp = (ViewingPlatform)i.next();
+ vp.setUniverse(this);
+ locale.addBranchGraph(vp);
+ }
+ }
+ }
+
+ /**
+ * Package-scope constructor that creates the view side of the
+ * scene graph. The passed in parameters override the default
+ * values where appropriate. Note that the userCanvases parameter
+ * is ignored when the userConfig is non-null.
+ *
+ * @param transformCount the number of transforms in the
+ * MultiTransformGroup object to be created
+ * @param canvases the canvases to associate with the Viewer object;
+ * passing in null will cause this parameter to be ignored and a canvas
+ * to be created by the utility
+ * @param userConfig the URL to the user's configuration file; passing in
+ * null causes the default values to be used.
+ * @param localeFactory the factory object used to create the Locale
+ * @param origin the origin used to set the origin of the Locale object;
+ * if this object is null, then 0.0 is used
+ * @param setVisible if true, calls setViewingPlatform
method is called; it must wait
+ * until its initialize
method is called.setVisible(true)
on all
+ * created window components; otherwise, they remain invisible
+ *
+ * @see Locale
+ * @see Viewer
+ * @see ViewingPlatform
+ * @see MultiTransformGroup
+ */
+ ConfiguredUniverse(int transformCount,
+ Canvas3D[] canvases,
+ URL userConfig,
+ LocaleFactory localeFactory,
+ HiResCoord origin,
+ boolean setVisible) {
+
+ super(origin, localeFactory);
+
+ if (userConfig == null) {
+ viewer = new Viewer[1];
+ viewer[0] = new Viewer(canvases, null, null, setVisible);
+ createDefaultViewingPlatform(transformCount);
+ }
+ else {
+ // Create a ConfigContainer without attaching behaviors. The
+ // package-scope constructor is used for backward compatibility.
+ configContainer = new ConfigContainer
+ (userConfig, setVisible, transformCount, false);
+
+ Collection c = configContainer.getViewers();
+ if (c == null || c.size() == 0)
+ throw new IllegalArgumentException(
+ "no views defined in configuration file");
+
+ viewer = (Viewer[])c.toArray(new Viewer[1]);
+
+ // Get ViewingPlatforms from the ConfigContainer and add them to
+ // the locale. The package-scoped findConfigObjects() accesor is
+ // used so that backward compatibility can be maintained for older
+ // configuration files.
+ c = configContainer.findConfigObjects("ViewPlatform");
+ if (c == null || c.size() == 0) {
+ createDefaultViewingPlatform(transformCount);
+ }
+ else {
+ Iterator i = c.iterator();
+ while (i.hasNext()) {
+ ConfigViewPlatform cvp = (ConfigViewPlatform)i.next();
+ ViewingPlatform vp = cvp.viewingPlatform;
+
+ // For backward compatibility, handle the default
+ // attachment of one Viewer to one ViewingPlatform. If
+ // there are multiple Viewers and ViewingPlatforms then
+ // attachments must be made explicitly in the config file.
+ if (vp.getViewers() == null &&
+ viewer.length == 1 && c.size() == 1) {
+ if (cvp.viewAttachPolicy == -1) {
+ setDerivedAttachPolicy(viewer[0], vp) ;
+ }
+ viewer[0].setViewingPlatform(vp);
+ }
+ vp.setUniverse(this);
+ locale.addBranchGraph(vp);
+
+ // If there's a behavior associated with the platform,
+ // attach it now after the setting the universe reference.
+ cvp.processBehavior();
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates a default ViewingPlatform, attaches the first Viewer, and then
+ * attaches the platform to the Locale.
+ *
+ * @param transformCount number of TransformGroups to create in the
+ * ViewingPlatform
+ */
+ private void createDefaultViewingPlatform(int transformCount) {
+ ViewingPlatform vp = new ViewingPlatform(transformCount);
+ setDerivedAttachPolicy(viewer[0], vp);
+ viewer[0].setViewingPlatform(vp);
+ vp.setUniverse(this);
+ locale.addBranchGraph(vp);
+ }
+
+ /**
+ * Sets a view attach policy appropriate for a window eyepoint policy.
+ *
+ * @param v Viewer to which the ViewingPlatform will be attached
+ * @param vp ViewingPlatform to which the Viewer will be attached
+ */
+ private void setDerivedAttachPolicy(Viewer v, ViewingPlatform vp) {
+ if (v.getView().getWindowEyepointPolicy() !=
+ View.RELATIVE_TO_FIELD_OF_VIEW) {
+ vp.getViewPlatform().setViewAttachPolicy(View.NOMINAL_SCREEN);
+ }
+ }
+
+
+ /**
+ * Returns the Viewer object specified by the given index.
+ *
+ * @param index The index of which Viewer object to return.
+ *
+ * @return The Viewer object specified by the given index.
+ */
+ public Viewer getViewer(int index) {
+ return viewer[index];
+ }
+
+ /**
+ * Returns all of the Viewer objects associated with this scene graph.
+ *
+ * @return The Viewer objects associated with this scene graph.
+ */
+ public Viewer[] getViewers() {
+ Viewer[] ret = new Viewer[viewer.length];
+ for (int i = 0; i < viewer.length; i++) {
+ ret[i] = viewer[i];
+ }
+ return ret;
+ }
+
+ /**
+ * Call setVisible()
on all AWT components created by this
+ * ConfiguredUniverse instance.setVisible()
+ * calls on the window components created by this
+ * ConfiguredUniverse instance
+ */
+ public void setVisible(boolean visible) {
+ for (int i = 0; i < viewer.length; i++)
+ if (viewer[i] != null)
+ viewer[i].setVisible(visible);
+ }
+
+ /**
+ * Returns the config file URL based on system properties. This is
+ * equivalent to calling ConfigContainer.getConfigURL()
. The
+ * current implementation of this method parses the j3d.configURL property
+ * as a URL string. For example, the following command line would specify
+ * that the config file is taken from the file "j3dconfig" in the current
+ * directory:
+ *
+ *
+ *
+ * @return the URL of the config file; null is returned if no valid
+ * URL is defined by the system properties
+ */
+ public static URL getConfigURL() {
+ return ConfigContainer.getConfigURL(null);
+ }
+
+ /**
+ * Returns the config file URL based on system properties. This is the
+ * same as calling java -Dj3d.configURL=file:j3dconfig ...
+ * ConfigContainer.getConfigURL(String)
. The
+ * current implementation of this method parses the j3d.configURL property
+ * as a URL string. For example, the following command line would specify
+ * that the config file is taken from the file "j3dconfig" in the current
+ * directory:
+ *
+ *
+ *
+ * @param defaultURLString the default string used to construct
+ * the URL if the appropriate system properties are not defined
+ * @return the URL of the config file; null is returned if no
+ * valid URL is defined either by the system properties or the
+ * default URL string
+ */
+ public static URL getConfigURL(String defaultURLString) {
+ return ConfigContainer.getConfigURL(defaultURLString);
+ }
+
+ /**
+ * Returns all named Sensors defined by the configuration file used to
+ * create the ConfiguredUniverse, if any. Equivalent to
+ * java -Dj3d.configURL=file:j3dconfig ...
+ * getConfigContainer().getNamedSensors()
.getConfigContainer().getNamedViewPlatformBehaviors()
.GraphicsConfiguration
object
+ * for the system. This object can then be used to create the
+ * Canvas3D objet for this system.
+ *
+ * @return The best GraphicsConfiguration
object for
+ * the system.
+ */
+ public static GraphicsConfiguration getPreferredConfiguration() {
+ GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D();
+
+ // Check if the user has set the Java 3D stereo option.
+ // Getting the system properties causes appletviewer to fail with a
+ // security exception without a try/catch.
+ String stereo = java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedActiongetImagePlateToVworld
+ * and other methods in the core Java 3D classes use a transform from view
+ * platform coordinates to virtual world coordinates that can be out of date
+ * with respect to the state of the view platform as set by the application.
+ * When an application uses the transforms returned by those methods to update
+ * view dependent parts of the scene graph, those updates might not be
+ * synchronized with what the viewer actually sees.ALLOW_LOCAL_TO_VWORLD_READ
capability
+ * set, which potentially inhibits internal scene graph optimization.ALLOW_LOCAL_TO_VWORLD_READ
view platform
+ * capability doesn't need to be set for these applications.
+ *
+ *
getUserHeadToVworld
method always incorporates a virtual world
+ * transform that is out of date with respect to the application scene graph
+ * state. ViewInfo reads data from the head tracking sensor directly, but
+ * since head trackers are continuous input devices, getting the same data
+ * that the renderer is using is unlikely. See the source code for the
+ * private method getHeadInfo
in this class for more information
+ * and possible workarounds.updateScreen
,
+ * updateCanvas
, updateViewPlatform
,
+ * updateView
, and updateHead
methods just set flags
+ * indicating that derived transforms need to be recomputed; they are safe to
+ * call from any thread. updateCanvas
, for example, can safely
+ * be called from an AWT event listener.localToVworld
+ * transform should be automatically checked with each call to a public
+ * method in this class. The View must be attached to a ViewPlatform
+ * which is part of a live scene graph, and the ViewPlatform node must
+ * have its ALLOW_LOCAL_TO_VWORLD_READ
capability set.
+ */
+ public final static int PLATFORM_AUTO_UPDATE = 16 ;
+
+ //
+ // Screen3D and ViewPlatform instances are shared across multiple Views in
+ // the Java 3D view model. Since ViewInfo is per-View and we want to
+ // cache screen and platform derived data, we maintain static references
+ // to the screens and platforms here.
+ //
+ // From a design standpoint our ViewInfo objects should probably be in the
+ // scope of an object that encloses these maps so they can be gc'ed
+ // properly. This is cumbersome with the current design constraints, so
+ // for now we provide an alternative constructor to override these static
+ // maps and a method to explicitly clear them. The alternative
+ // constructor can be used to wrap this class into a multi-view context
+ // that provides the maps.
+ //
+ private static Map staticVpMap = new HashMap() ;
+ private static Map staticSiMap = new HashMap() ;
+
+ private Map screenMap = null ;
+ private Map viewPlatformMap = null ;
+
+ // The target View and some derived data.
+ private View view = null ;
+ private Sensor headTracker = null ;
+ private boolean useTracking = false ;
+ private boolean clipVirtual = false ;
+
+ // The current ViewPlatform and Canvas3D information used by this object.
+ private ViewPlatformInfo vpi = null ;
+ private int canvasCount = 0 ;
+ private Map canvasMap = new HashMap() ;
+ private CanvasInfo[] canvasInfo = new CanvasInfo[1] ;
+
+ // This View's update flags. The other update flags are maintained by
+ // ScreenInfo, CanvasInfo, and ViewPlatformInfo.
+ private boolean updateView = true ;
+ private boolean updateHead = true ;
+ private boolean autoUpdate = false ;
+ private int autoUpdateFlags = 0 ;
+
+ // Cached View policies.
+ private int viewPolicy = View.SCREEN_VIEW ;
+ private int resizePolicy = View.PHYSICAL_WORLD ;
+ private int movementPolicy = View.PHYSICAL_WORLD ;
+ private int eyePolicy = View.RELATIVE_TO_FIELD_OF_VIEW ;
+ private int projectionPolicy = View.PERSPECTIVE_PROJECTION ;
+ private int frontClipPolicy = View.PHYSICAL_EYE ;
+ private int backClipPolicy = View.PHYSICAL_EYE ;
+ private int scalePolicy = View.SCALE_SCREEN_SIZE ;
+ private boolean coeCentering = true ;
+
+ // This View's cached transforms. See ScreenInfo, CanvasInfo, and
+ // ViewPlatformInfo for the rest of the cached transforms.
+ private Transform3D coeToTrackerBase = null ;
+ private Transform3D headToHeadTracker = null ;
+
+ // These are from the head tracker read.
+ private Transform3D headTrackerToTrackerBase = null ;
+ private Transform3D trackerBaseToHeadTracker = null ;
+
+ // These are derived from the head tracker read.
+ private Transform3D headToTrackerBase = null ;
+ private Transform3D coeToHeadTracker = null ;
+
+ // Cached physical body and environment.
+ private PhysicalEnvironment env = null ;
+ private PhysicalBody body = null ;
+ private Point3d leftEyeInHead = new Point3d() ;
+ private Point3d rightEyeInHead = new Point3d() ;
+
+ // Temporary variables. These could just be new'ed as needed, but we'll
+ // assume that ViewInfo instances are used much more than they're created.
+ private Vector3d v3d = new Vector3d() ;
+ private double[] m16d = new double[16] ;
+ private Point3d leftEye = new Point3d() ;
+ private Point3d rightEye = new Point3d() ;
+ private Map newMap = new HashMap() ;
+ private Set newSet = new HashSet() ;
+
+ /**
+ * Creates a new ViewInfo for the specified View.localToVworld
transform. These
+ * notifications are performed with the updateView
,
+ * updateCanvas
, updateScreen
,
+ * updateHead
, and updateViewPlatform
+ * methods.ALLOW_POLICY_READ
+ * capability must be set on the ViewPlatform node.
+ *
+ * @param view the View to use
+ * @see #updateView
+ * @see #updateCanvas updateCanvas(Canvas3D)
+ * @see #updateScreen updateScreen(Screen3D)
+ * @see #updateHead
+ * @see #updateViewPlatform
+ */
+ public ViewInfo(View view) {
+ this(view, 0) ;
+ }
+
+ /**
+ * Creates a new ViewInfo for the specified View. The View must be
+ * attached to a ViewPlatform. If the ViewPlatform is attached to a live
+ * scene graph, then ALLOW_POLICY_READ
capability must be set
+ * on the ViewPlatform node.
+ *
+ * @param view the View to useOR
of any of the
+ * VIEW_AUTO_UPDATE
, CANVAS_AUTO_UPDATE
,
+ * SCREEN_AUTO_UPDATE
, HEAD_AUTO_UPDATE
, or
+ * PLATFORM_AUTO_UPDATE
flags to control whether changes to
+ * the View, its Canvas3D or Screen3D components, the tracked head
+ * position, or the ViewPlatform's localToVworld
transform
+ * are checked automatically with each call to a public method of this
+ * class; if a flag is not set, then the application must inform this
+ * class of updates to the corresponding data
+ */
+ public ViewInfo(View view, int autoUpdateFlags) {
+ this(view, autoUpdateFlags, staticSiMap, staticVpMap) ;
+ }
+
+ /**
+ * Creates a new ViewInfo for the specified View. The View must be
+ * attached to a ViewPlatform. If the ViewPlatform is attached to a live
+ * scene graph, then ALLOW_POLICY_READ
capability must be set
+ * on the ViewPlatform node.ViewInfo.clear
when done with ViewInfo, or by simply
+ * retaining the static references until the JVM exits.OR
of any of the
+ * VIEW_AUTO_UPDATE
, CANVAS_AUTO_UPDATE
,
+ * SCREEN_AUTO_UPDATE
, HEAD_AUTO_UPDATE
, or
+ * PLATFORM_AUTO_UPDATE
flags to control whether changes to
+ * the View, its Canvas3D or Screen3D components, the tracked head
+ * position, or the ViewPlatform's localToVworld
transform
+ * are checked automatically with each call to a public method of this
+ * class; if a flag is not set, then the application must inform this
+ * class of updates to the corresponding dataALLOW_LOCAL_TO_VWORLD_READ
capability set.
+ *
+ * @param c3d the Canvas3D associated with the image plate
+ * @param ip2vwl the Transform3D to receive the left transform
+ * @param ip2vwr the Transform3D to receive the right transform, or null
+ */
+ public void getImagePlateToVworld(Canvas3D c3d,
+ Transform3D ip2vwl, Transform3D ip2vwr) {
+
+ CanvasInfo ci = updateCache(c3d, "getImagePlateToVworld", true) ;
+ getImagePlateToVworld(ci) ;
+ ip2vwl.set(ci.plateToVworld) ;
+ if (ci.useStereo && ip2vwr != null)
+ ip2vwr.set(ci.rightPlateToVworld) ;
+ }
+
+ private void getImagePlateToVworld(CanvasInfo ci) {
+ if (ci.updatePlateToVworld) {
+ if (verbose) System.err.println("updating PlateToVworld") ;
+ if (ci.plateToVworld == null)
+ ci.plateToVworld = new Transform3D() ;
+
+ getImagePlateToViewPlatform(ci) ;
+ ci.plateToVworld.mul
+ (vpi.viewPlatformToVworld, ci.plateToViewPlatform) ;
+
+ if (ci.useStereo) {
+ if (ci.rightPlateToVworld == null)
+ ci.rightPlateToVworld = new Transform3D() ;
+
+ ci.rightPlateToVworld.mul
+ (vpi.viewPlatformToVworld, ci.rightPlateToViewPlatform) ;
+ }
+ ci.updatePlateToVworld = false ;
+ }
+ }
+
+ /**
+ * Gets the current transforms from coexistence coordinates to image plate
+ * coordinates and copies them into the given Transform3Ds. The default
+ * coexistence centering enable and window movement policies are
+ * true
and PHYSICAL_WORLD
respectively, which
+ * will center coexistence coordinates to the middle of the canvas,
+ * aligned with the screen (image plate). A movement policy of
+ * VIRTUAL_WORLD
centers coexistence coordinates to the
+ * middle of the screen.trackerBaseToImagePlate
transform and the
+ * PhysicalEnvironment coexistenceToTrackerBase
transform.
+ * These are calibration constants used for multiple fixed screen displays.
+ * For head mounted displays the transform is determined by the user head
+ * position along with calibration parameters found in Screen3D and
+ * PhysicalBody. (See the source code for the private method
+ * getEyesHMD
for more information).
+ *
+ *
+ *
+ * @param c3d the Canvas3D to use
+ * @param vp2coe the Transform3D to receive the transform
+ */
+ public void getViewPlatformToCoexistence(Canvas3D c3d,
+ Transform3D vp2coe) {
+
+ CanvasInfo ci = updateCache
+ (c3d, "getViewPlatformToCoexistence", false) ;
+
+ getViewPlatformToCoexistence(ci) ;
+ vp2coe.set(ci.viewPlatformToCoe) ;
+ }
+
+ private void getViewPlatformToCoexistence(CanvasInfo ci) {
+ if (!ci.updateViewPlatformToCoe) return ;
+ if (verbose) System.err.println("updating ViewPlatformToCoe") ;
+ if (ci.viewPlatformToCoe == null)
+ ci.viewPlatformToCoe = new Transform3D() ;
+ //
+ // The scale from view platform coordinates to coexistence coordinates
+ // has two components -- the screen scale and the window scale. The
+ // window scale only applies if the resize policy is PHYSICAL_WORLD.
+ //
+ // This scale is not the same as the vworld to view platform scale.
+ // The latter is contained in the view platform's localToVworld
+ // transform as defined by the scene graph. The complete scale factor
+ // from virtual units to physical units is the product of the vworld
+ // to view platform scale and the view platform to coexistence scale.
+ //
+ getScreenScale(ci) ;
+ if (resizePolicy == View.PHYSICAL_WORLD)
+ ci.viewPlatformToCoe.setScale(ci.screenScale * ci.windowScale) ;
+ else
+ ci.viewPlatformToCoe.setScale(ci.screenScale) ;
+
+ if (viewPolicy == View.HMD_VIEW) {
+ // In HMD mode view platform coordinates are the same as
+ // coexistence coordinates, except for scale.
+ ci.updateViewPlatformToCoe = false ;
+ return ;
+ }
+
+ //
+ // Otherwise, get the offset of the origin of view platform
+ // coordinates relative to the origin of coexistence. This is is
+ // specified by two policies: the view platform's view attach policy
+ // and the physical environment's coexistence center in pworld policy.
+ //
+ double eyeOffset ;
+ double eyeHeight = body.getNominalEyeHeightFromGround() ;
+ int viewAttachPolicy = view.getViewPlatform().getViewAttachPolicy() ;
+ int pworldAttachPolicy = env.getCoexistenceCenterInPworldPolicy() ;
+
+ if (eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW)
+ // The view platform origin is the same as the eye position.
+ eyeOffset = ci.getFieldOfViewOffset() ;
+ else
+ // The view platform origin is independent of the eye position.
+ eyeOffset = body.getNominalEyeOffsetFromNominalScreen() ;
+
+ if (pworldAttachPolicy == View.NOMINAL_SCREEN) {
+ // The default. The physical coexistence origin locates the
+ // nominal screen. This is rarely, if ever, set to anything
+ // else, and the intended effects of the other settings are
+ // not well documented.
+ if (viewAttachPolicy == View.NOMINAL_HEAD) {
+ // The default. The view platform origin is at the origin
+ // of the nominal head in coexistence coordinates, offset
+ // from the screen along +Z. If the window eyepoint
+ // policy is RELATIVE_TO_FIELD_OF_VIEW, then the eyepoint
+ // is the same as the view platform origin.
+ v3d.set(0.0, 0.0, eyeOffset) ;
+ }
+ else if (viewAttachPolicy == View.NOMINAL_SCREEN) {
+ // View platform and coexistence are the same except for
+ // scale.
+ v3d.set(0.0, 0.0, 0.0) ;
+ }
+ else {
+ // The view platform origin is at the ground beneath the
+ // head.
+ v3d.set(0.0, -eyeHeight, eyeOffset) ;
+ }
+ }
+ else if (pworldAttachPolicy == View.NOMINAL_HEAD) {
+ // The physical coexistence origin locates the nominal head.
+ if (viewAttachPolicy == View.NOMINAL_HEAD) {
+ // The view platform origin is set to the head;
+ // coexistence and view platform coordinates differ only
+ // in scale.
+ v3d.set(0.0, 0.0, 0.0) ;
+ }
+ else if (viewAttachPolicy == View.NOMINAL_SCREEN) {
+ // The view platform is set in front of the head, at the
+ // nominal screen location.
+ v3d.set(0.0, 0.0, -eyeOffset) ;
+ }
+ else {
+ // The view platform origin is at the ground beneath the
+ // head.
+ v3d.set(0.0, -eyeHeight, 0.0) ;
+ }
+ }
+ else {
+ // The physical coexistence origin locates the nominal feet.
+ if (viewAttachPolicy == View.NOMINAL_HEAD) {
+ v3d.set(0.0, eyeHeight, 0.0) ;
+ }
+ else if (viewAttachPolicy == View.NOMINAL_SCREEN) {
+ v3d.set(0.0, eyeHeight, -eyeOffset) ;
+ }
+ else {
+ v3d.set(0.0, 0.0, 0.0) ;
+ }
+ }
+
+ ci.viewPlatformToCoe.setTranslation(v3d) ;
+ ci.updateViewPlatformToCoe = false ;
+ if (verbose) t3dPrint(ci.viewPlatformToCoe, "vpToCoe") ;
+ }
+
+ /**
+ * Gets the current transform from coexistence coordinates to
+ * view platform coordinates and copies it into the given transform.PHYSICAL_WORLD
, which
+ * alters the scale depending upon the width of the canvas.SCALE_SCREEN_SIZE
,
+ * which alters the scale depending upon the width of the screen
+ * associated with the canvas.RELATIVE_TO_FIELD_OF_VIEW
+ * with a view attach policy of NOMINAL_HEAD
in effect,
+ * which sets the view platform Z offset in coexistence coordinates
+ * based on the width of the canvas. These are the default policies.
+ * The offset also follows the width of the canvas when the
+ * NOMINAL_FEET
view attach policy is used.getViewPlatformToCoexistence
.ALLOW_LOCAL_TO_VWORLD_READ
capability set.getViewPlatformToCoexistence
.trackerBaseToImagePlate
transform. Otherwise the window
+ * eyepoint policy is used to derive the eyepoint relative to the image
+ * plate. When using a head mounted display the eye position is
+ * determined solely by calibration constants in Screen3D and
+ * PhysicalBody; see the source code for the private method
+ * getEyesHMD
for more information.RELATIVE_TO_COEXISTENCE
, then the transforms returned may
+ * be different for each canvas if stereo is not in use and they have
+ * different monoscopic view policies. They may additionally differ in
+ * scale across canvases with the PHYSICAL_WORLD
window
+ * resize policy or the SCALE_SCREEN_SIZE
screen scale
+ * policy, which alter the scale depending upon the width of the canvas or
+ * the width of the screen respectively.RELATIVE_TO_FIELD_OF_VIEW
,
+ * RELATIVE_TO_SCREEN
, or RELATIVE_TO_WINDOW
,
+ * then the transforms returned may differ across canvases due to
+ * the following additional conditions:
+ *
+ *
+ *
+ * @param c3d the Canvas3D to use
+ * @param e2vpl the Transform3D to receive the left transform
+ * @param e2vpr the Transform3D to receive the right transform, or null
+ */
+ public void getEyeToViewPlatform(Canvas3D c3d,
+ Transform3D e2vpl, Transform3D e2vpr) {
+
+ CanvasInfo ci = updateCache(c3d, "getEyeToViewPlatform", false) ;
+ getEyeToViewPlatform(ci) ;
+ e2vpl.set(ci.eyeToViewPlatform) ;
+ if (ci.useStereo && e2vpr != null)
+ e2vpr.set(ci.rightEyeToViewPlatform) ;
+ }
+
+ private void getEyeToViewPlatform(CanvasInfo ci) {
+ if (ci.updateEyeToViewPlatform) {
+ if (verbose) System.err.println("updating EyeToViewPlatform") ;
+ if (ci.eyeToViewPlatform == null)
+ ci.eyeToViewPlatform = new Transform3D() ;
+
+ getEyeToImagePlate(ci) ;
+ getImagePlateToViewPlatform(ci) ;
+ ci.eyeToViewPlatform.mul(ci.plateToViewPlatform, ci.eyeToPlate) ;
+
+ if (ci.useStereo) {
+ if (ci.rightEyeToViewPlatform == null)
+ ci.rightEyeToViewPlatform = new Transform3D() ;
+
+ ci.rightEyeToViewPlatform.mul
+ (ci.rightPlateToViewPlatform, ci.rightEyeToPlate) ;
+ }
+ ci.updateEyeToViewPlatform = false ;
+ if (verbose) t3dPrint(ci.eyeToViewPlatform, "eyeToVp") ;
+ }
+ }
+
+ /**
+ * Gets the current transforms from view platform coordinates to eye
+ * coordinates and copies them into the given Transform3Ds.RELATIVE_TO_WINDOW
or
+ * RELATIVE_TO_SCREEN
, in which case the manual eye
+ * position in image plate can be set differently for each
+ * canvas.RELATIVE_TO_FIELD_OF_VIEW
+ * and the view attach policy is NOMINAL_SCREEN
, which
+ * decouples the view platform's canvas Z offset from the eyepoint's
+ * canvas Z offset.RELATIVE_TO_FIELD_OF_VIEW
+ * or RELATIVE_TO_WINDOW
, and a window movement policy
+ * of VIRTUAL_WORLD
centers the view platform's X and Y
+ * coordinates to the middle of the screen.getEyeToViewPlatform
.
+ *
+ * @param c3d the Canvas3D to use
+ * @param vp2el the Transform3D to receive the left transform
+ * @param vp2er the Transform3D to receive the right transform, or null
+ * @see #getEyeToViewPlatform
+ * getEyeToViewPlatform(Canvas3D, Transform3D, Transform3D)
+ */
+ public void getViewPlatformToEye(Canvas3D c3d,
+ Transform3D vp2el, Transform3D vp2er) {
+
+ CanvasInfo ci = updateCache(c3d, "getViewPlatformToEye", false) ;
+ getViewPlatformToEye(ci) ;
+ vp2el.set(ci.viewPlatformToEye) ;
+ if (ci.useStereo && vp2er != null)
+ vp2er.set(ci.viewPlatformToRightEye) ;
+ }
+
+ private void getViewPlatformToEye(CanvasInfo ci) {
+ if (ci.updateViewPlatformToEye) {
+ if (verbose) System.err.println("updating ViewPlatformToEye") ;
+ if (ci.viewPlatformToEye == null)
+ ci.viewPlatformToEye = new Transform3D() ;
+
+ getEyeToViewPlatform(ci) ;
+ ci.viewPlatformToEye.invert(ci.eyeToViewPlatform) ;
+
+ if (ci.useStereo) {
+ if (ci.viewPlatformToRightEye == null)
+ ci.viewPlatformToRightEye = new Transform3D() ;
+
+ ci.viewPlatformToRightEye.invert(ci.rightEyeToViewPlatform) ;
+ }
+ ci.updateViewPlatformToEye = false ;
+ }
+ }
+
+ /**
+ * Gets the current transforms from eye coordinates to virtual world
+ * coordinates and copies them into the given Transform3Ds.ALLOW_LOCAL_TO_VWORLD_READ
capability set.getEyeToViewPlatform
.
+ *
+ * @param c3d the Canvas3D to use
+ * @param e2vwl the Transform3D to receive the left transform
+ * @param e2vwr the Transform3D to receive the right transform, or null
+ * @see #getEyeToViewPlatform
+ * getEyeToViewPlatform(Canvas3D, Transform3D, Transform3D)
+ */
+ public void getEyeToVworld(Canvas3D c3d,
+ Transform3D e2vwl, Transform3D e2vwr) {
+
+ CanvasInfo ci = updateCache(c3d, "getEyeToVworld", true) ;
+ getEyeToVworld(ci) ;
+ e2vwl.set(ci.eyeToVworld) ;
+ if (ci.useStereo && e2vwr != null)
+ e2vwr.set(ci.rightEyeToVworld) ;
+ }
+
+ private void getEyeToVworld(CanvasInfo ci) {
+ if (ci.updateEyeToVworld) {
+ if (verbose) System.err.println("updating EyeToVworld") ;
+ if (ci.eyeToVworld == null)
+ ci.eyeToVworld = new Transform3D() ;
+
+ getEyeToViewPlatform(ci) ;
+ ci.eyeToVworld.mul
+ (vpi.viewPlatformToVworld, ci.eyeToViewPlatform) ;
+
+ if (ci.useStereo) {
+ if (ci.rightEyeToVworld == null)
+ ci.rightEyeToVworld = new Transform3D() ;
+
+ ci.rightEyeToVworld.mul
+ (vpi.viewPlatformToVworld, ci.rightEyeToViewPlatform) ;
+ }
+ ci.updateEyeToVworld = false ;
+ }
+ }
+
+ /**
+ * Gets the transforms from eye coordinates to clipping coordinates
+ * and copies them into the given Transform3Ds. These transforms take
+ * a viewing volume bounded by the physical canvas edges and the
+ * physical front and back clip planes and project it into a range
+ * bound to [-1.0 .. +1.0] on each of the X, Y, and Z axes. If a
+ * perspective projection has been specified then the physical image
+ * plate eye location defines the apex of a viewing frustum;
+ * otherwise, the orientation of the image plate determines the
+ * direction of a parallel projection.VIRTUAL_EYE
or
+ * VIRTUAL_SCREEN
are used, then the View should be attached
+ * to a ViewPlatform that is part of a live scene graph and that has its
+ * ALLOW_LOCAL_TO_VWORLD_READ
capability set; otherwise, a
+ * scale factor of 1.0 will be used for the scale factor from virtual
+ * world units to view platform units.
+ *
+ * @param c3d the Canvas3D to use
+ * @param e2ccl the Transform3D to receive left transform
+ * @param e2ccr the Transform3D to receive right transform, or null
+ */
+ public void getProjection(Canvas3D c3d,
+ Transform3D e2ccl, Transform3D e2ccr) {
+
+ CanvasInfo ci = updateCache(c3d, "getProjection", true) ;
+ getProjection(ci) ;
+ e2ccl.set(ci.projection) ;
+ if (ci.useStereo && e2ccr != null)
+ e2ccr.set(ci.rightProjection) ;
+ }
+
+ private void getProjection(CanvasInfo ci) {
+ if (ci.updateProjection) {
+ if (verbose) System.err.println("updating Projection") ;
+ if (ci.projection == null)
+ ci.projection = new Transform3D() ;
+
+ getEyeToImagePlate(ci) ;
+ getClipDistances(ci) ;
+
+ // Note: core Java 3D code insists that the back clip plane
+ // relative to the image plate must be the same left back clip
+ // distance for both the left and right eye. Not sure why this
+ // should be, but the same is done here for compatibility.
+ double backClip = getBackClip(ci, ci.eyeInPlate) ;
+ computeProjection(ci, ci.eyeInPlate,
+ getFrontClip(ci, ci.eyeInPlate),
+ backClip, ci.projection) ;
+
+ if (ci.useStereo) {
+ if (ci.rightProjection == null)
+ ci.rightProjection = new Transform3D() ;
+
+ computeProjection(ci, ci.rightEyeInPlate,
+ getFrontClip(ci, ci.rightEyeInPlate),
+ backClip, ci.rightProjection) ;
+ }
+ ci.updateProjection = false ;
+ if (verbose) t3dPrint(ci.projection, "projection") ;
+ }
+ }
+
+ /**
+ * Gets the transforms from clipping coordinates to eye coordinates
+ * and copies them into the given Transform3Ds. These transforms take
+ * the clip space volume bounded by the range [-1.0 .. + 1.0] on each
+ * of the X, Y, and Z and project it into eye coordinates.VIRTUAL_EYE
or
+ * VIRTUAL_SCREEN
are used, then the View should be attached
+ * to a ViewPlatform that is part of a live scene graph and that has its
+ * ALLOW_LOCAL_TO_VWORLD_READ
capability set; otherwise, a
+ * scale factor of 1.0 will be used for the scale factor from virtual
+ * world units to view platform units.
+ *
+ * @param c3d the Canvas3D to use
+ * @param cc2el the Transform3D to receive left transform
+ * @param cc2er the Transform3D to receive right transform, or null
+ */
+ public void getInverseProjection(Canvas3D c3d,
+ Transform3D cc2el, Transform3D cc2er) {
+
+ CanvasInfo ci = updateCache(c3d, "getInverseProjection", true) ;
+ getInverseProjection(ci) ;
+ cc2el.set(ci.inverseProjection) ;
+ if (ci.useStereo && cc2er != null)
+ cc2er.set(ci.inverseRightProjection) ;
+ }
+
+ private void getInverseProjection(CanvasInfo ci) {
+ if (ci.updateInverseProjection) {
+ if (verbose) System.err.println("updating InverseProjection") ;
+ if (ci.inverseProjection == null)
+ ci.inverseProjection = new Transform3D() ;
+
+ getProjection(ci) ;
+ ci.inverseProjection.invert(ci.projection) ;
+
+ if (ci.useStereo) {
+ if (ci.inverseRightProjection == null)
+ ci.inverseRightProjection = new Transform3D() ;
+
+ ci.inverseRightProjection.invert(ci.rightProjection) ;
+ }
+ ci.updateInverseProjection = false ;
+ }
+ }
+
+ /**
+ * Gets the transforms from clipping coordinates to view platform
+ * coordinates and copies them into the given Transform3Ds. These
+ * transforms take the clip space volume bounded by the range
+ * [-1.0 .. +1.0] on each of the X, Y, and Z axes and project into
+ * the view platform coordinate system.VIRTUAL_EYE
or
+ * VIRTUAL_SCREEN
are used, then the View should be attached
+ * to a ViewPlatform that is part of a live scene graph and that has its
+ * ALLOW_LOCAL_TO_VWORLD_READ
capability set; otherwise, a
+ * scale factor of 1.0 will be used for the scale factor from virtual
+ * world units to view platform units.
+ *
+ * @param c3d the Canvas3D to use
+ * @param cc2vpl the Transform3D to receive left transform
+ * @param cc2vpr the Transform3D to receive right transform, or null
+ */
+ public void getInverseViewPlatformProjection(Canvas3D c3d,
+ Transform3D cc2vpl,
+ Transform3D cc2vpr) {
+
+ CanvasInfo ci = updateCache
+ (c3d, "getInverseViewPlatformProjection", true) ;
+
+ getInverseViewPlatformProjection(ci) ;
+ cc2vpl.set(ci.inverseViewPlatformProjection) ;
+ if (ci.useStereo & cc2vpr != null)
+ cc2vpr.set(ci.inverseViewPlatformRightProjection) ;
+ }
+
+ private void getInverseViewPlatformProjection(CanvasInfo ci) {
+ if (ci.updateInverseViewPlatformProjection) {
+ if (verbose) System.err.println("updating InverseVpProjection") ;
+ if (ci.inverseViewPlatformProjection == null)
+ ci.inverseViewPlatformProjection = new Transform3D() ;
+
+ getInverseProjection(ci) ;
+ getEyeToViewPlatform(ci) ;
+ ci.inverseViewPlatformProjection.mul
+ (ci.eyeToViewPlatform, ci.inverseProjection) ;
+
+ if (ci.useStereo) {
+ if (ci.inverseViewPlatformRightProjection == null)
+ ci.inverseViewPlatformRightProjection = new Transform3D() ;
+
+ ci.inverseViewPlatformRightProjection.mul
+ (ci.rightEyeToViewPlatform, ci.inverseRightProjection) ;
+ }
+ ci.updateInverseVworldProjection = false ;
+ }
+ }
+
+ /**
+ * Gets the transforms from clipping coordinates to virtual world
+ * coordinates and copies them into the given Transform3Ds. These
+ * transforms take the clip space volume bounded by the range
+ * [-1.0 .. +1.0] on each of the X, Y, and Z axes and project into
+ * the virtual world.ALLOW_LOCAL_TO_VWORLD_READ
capability set.
+ *
+ * @param c3d the Canvas3D to use
+ * @param cc2vwl the Transform3D to receive left transform
+ * @param cc2vwr the Transform3D to receive right transform, or null
+ */
+ public void getInverseVworldProjection(Canvas3D c3d,
+ Transform3D cc2vwl,
+ Transform3D cc2vwr) {
+
+ CanvasInfo ci = updateCache(c3d, "getInverseVworldProjection", true) ;
+ getInverseVworldProjection(ci) ;
+ cc2vwl.set(ci.inverseVworldProjection) ;
+ if (ci.useStereo & cc2vwr != null)
+ cc2vwr.set(ci.inverseVworldRightProjection) ;
+ }
+
+ private void getInverseVworldProjection(CanvasInfo ci) {
+ if (ci.updateInverseVworldProjection) {
+ if (verbose) System.err.println("updating InverseVwProjection") ;
+ if (ci.inverseVworldProjection == null)
+ ci.inverseVworldProjection = new Transform3D() ;
+
+ getInverseViewPlatformProjection(ci) ;
+ ci.inverseVworldProjection.mul
+ (vpi.viewPlatformToVworld, ci.inverseViewPlatformProjection) ;
+
+ if (ci.useStereo) {
+ if (ci.inverseVworldRightProjection == null)
+ ci.inverseVworldRightProjection = new Transform3D() ;
+
+ ci.inverseVworldRightProjection.mul
+ (vpi.viewPlatformToVworld,
+ ci.inverseViewPlatformRightProjection) ;
+ }
+ ci.updateInverseVworldProjection = false ;
+ }
+ }
+
+ //
+ // Compute a projection matrix from the given eye position in image plate,
+ // the front and back clip Z positions in image plate, and the current
+ // canvas position in image plate.
+ //
+ private void computeProjection(CanvasInfo ci, Point3d eye,
+ double front, double back, Transform3D p) {
+
+ // Convert everything to eye coordinates.
+ double lx = ci.canvasX - eye.x ; // left (low x)
+ double ly = ci.canvasY - eye.y ; // bottom (low y)
+ double hx = (ci.canvasX+ci.canvasWidth) - eye.x ; // right (high x)
+ double hy = (ci.canvasY+ci.canvasHeight) - eye.y ; // top (high y)
+ double nz = front - eye.z ; // front (near z)
+ double fz = back - eye.z ; // back (far z)
+ double iz = -eye.z ; // plate (image z)
+
+ if (projectionPolicy == View.PERSPECTIVE_PROJECTION)
+ computePerspectiveProjection(lx, ly, hx, hy, iz, nz, fz, m16d) ;
+ else
+ computeParallelProjection(lx, ly, hx, hy, nz, fz, m16d) ;
+
+ p.set(m16d) ;
+ }
+
+ //
+ // Compute a perspective projection from the given eye-space bounds.
+ //
+ private void computePerspectiveProjection(double lx, double ly,
+ double hx, double hy,
+ double iz, double nz,
+ double fz, double[] m) {
+ //
+ // We first derive the X and Y projection components without regard
+ // for Z scaling. The Z scaling or perspective depth is handled by
+ // matrix elements expressed solely in terms of the near and far clip
+ // planes.
+ //
+ // Since the eye is at the origin, the projector for any point V in
+ // eye space is just V. Any point along this ray can be expressed in
+ // parametric form as P = tV. To find the projection onto the plane
+ // containing the canvas, find t such that P.z = iz; ie, t = iz/V.z.
+ // The projection P is thus [V.x*iz/V.z, V.y*iz/V.z, iz].
+ //
+ // This projection can expressed as the following matrix equation:
+ //
+ // -iz 0 0 0 V.x
+ // 0 -iz 0 0 X V.y
+ // 0 0 -iz 0 V.z
+ // 0 0 -1 0 1 {matrix 1}
+ //
+ // where the matrix elements have been negated so that w is positive.
+ // This is mostly by convention, although some hardware won't handle
+ // clipping in the -w half-space.
+ //
+ // After the point has been projected to the image plate, the
+ // canvas bounds need to be mapped to the [-1..1] of Java 3D's
+ // clipping space. The scale factor for X is thus 2/(hx - lx); adding
+ // the translation results in (V.x - lx)(2/(hx - lx)) - 1, which after
+ // some algebra can be confirmed to the same as the following
+ // canonical scale/offset form:
+ //
+ // V.x*2/(hx - lx) - (hx + lx)/(hx - lx)
+ //
+ // Similarly for Y:
+ //
+ // V.y*2/(hy - ly) - (hy + ly)/(hy - ly)
+ //
+ // If we set idx = 1/(hx - lx) and idy = 1/(hy - ly), then we get:
+ //
+ // 2*V.x*idx - (hx + lx)idx
+ // 2*V.y*idy - (hy + ly)idy
+ //
+ // These scales and offsets are represented by the following matrix:
+ //
+ // 2*idx 0 0 -(hx + lx)*idx
+ // 0 2*idy 0 -(hy + ly)*idy
+ // 0 0 1 0
+ // 0 0 0 1 {matrix 2}
+ //
+ // The result after concatenating the projection transform
+ // ({matrix 2} X {matrix 1}):
+ //
+ // -2*iz*idx 0 (hx + lx)*idx 0
+ // 0 -2*iz*idy (hy + ly)*idy 0
+ // 0 0 -iz {a} 0 {b}
+ // 0 0 -1 0 {matrix 3}
+ //
+ // The Z scaling is handled by m[10] ("a") and m[11] ("b"), which must
+ // map the range [front..back] to [1..-1] in clipping space. If ze is
+ // the Z coordinate in eye space, and zc is the Z coordinate in
+ // clipping space after division by w, then from {matrix 3}:
+ //
+ // zc = (a*ze + b)/-ze = -(a + b/ze)
+ //
+ // We want this to map to +1 when ze is at the near clip plane, and
+ // to -1 when ze is at the far clip plane:
+ //
+ // -(a + b/nz) = +1
+ // -(a + b/fz) = -1
+ //
+ // Solving results in:
+ //
+ // a = -(nz + fz)/(nz - fz)
+ // b = (2*nz*fz)/(nz - fz).
+ //
+ // NOTE: this produces a perspective transform that has matrix
+ // components with a different scale than the matrix computed by the
+ // Java 3D core. They do in fact effect the equivalent clipping in 4D
+ // homogeneous coordinates and project to the same 3D Euclidean
+ // coordinates. m[14] is always -1 in our derivation above. If the
+ // matrix components produced by Java 3D core are divided by its value
+ // of -m[14], then both matrices are the same.
+ //
+ double idx = 1.0 / (hx - lx) ;
+ double idy = 1.0 / (hy - ly) ;
+ double idz = 1.0 / (nz - fz) ;
+
+ m[0] = -2.0 * iz * idx ;
+ m[5] = -2.0 * iz * idy ;
+ m[2] = (hx + lx) * idx ;
+ m[6] = (hy + ly) * idy ;
+ m[10] = -(nz + fz) * idz ;
+ m[11] = 2.0 * fz * nz * idz ;
+ m[14] = -1.0 ;
+ m[1] = m[3] = m[4] = m[7] = m[8] = m[9] = m[12] = m[13] = m[15] = 0.0 ;
+ }
+
+ //
+ // Compute a parallel projection from the given eye-space bounds.
+ //
+ private void computeParallelProjection(double lx, double ly,
+ double hx, double hy,
+ double nz, double fz, double[] m) {
+ //
+ // A parallel projection in eye space just involves scales and offsets
+ // with no w division. We can use {matrix 2} for the X and Y scales
+ // and offsets and then use a linear mapping of the front and back
+ // clip distances to the [1..-1] Z clip range.
+ //
+ double idx = 1.0 / (hx - lx) ;
+ double idy = 1.0 / (hy - ly) ;
+ double idz = 1.0 / (nz - fz) ;
+
+ m[0] = 2.0 * idx ;
+ m[5] = 2.0 * idy ;
+ m[10] = 2.0 * idz ;
+ m[3] = -(hx + lx) * idx ;
+ m[7] = -(hy + ly) * idy ;
+ m[11] = -(nz + fz) * idz ;
+ m[15] = 1.0 ;
+ m[1] = m[2] = m[4] = m[6] = m[8] = m[9] = m[12] = m[13] = m[14] = 0.0 ;
+ }
+
+ //
+ // Get front clip plane Z coordinate in image plate space.
+ //
+ private double getFrontClip(CanvasInfo ci, Point3d eye) {
+ if (frontClipPolicy == View.PHYSICAL_EYE ||
+ frontClipPolicy == View.VIRTUAL_EYE) {
+ return eye.z - ci.frontClipDistance ;
+ }
+ else {
+ return - ci.frontClipDistance ;
+ }
+ }
+
+ //
+ // Get back clip plane Z coordinate in image plate space.
+ //
+ private double getBackClip(CanvasInfo ci, Point3d eye) {
+ //
+ // Note: Clip node status is unavailable here. If a clip node is
+ // active in the scene graph, it should override the view's back
+ // clip plane.
+ //
+ if (backClipPolicy == View.PHYSICAL_EYE ||
+ backClipPolicy == View.VIRTUAL_EYE) {
+ return eye.z - ci.backClipDistance ;
+ }
+ else {
+ return -ci.backClipDistance ;
+ }
+ }
+
+ //
+ // Compute clip distance scale.
+ //
+ private double getClipScale(CanvasInfo ci, int clipPolicy) {
+ if (clipPolicy == View.VIRTUAL_EYE ||
+ clipPolicy == View.VIRTUAL_SCREEN) {
+ getScreenScale(ci) ;
+ if (resizePolicy == View.PHYSICAL_WORLD)
+ return vpi.vworldToViewPlatformScale * ci.screenScale *
+ ci.windowScale ;
+ else
+ return vpi.vworldToViewPlatformScale * ci.screenScale ;
+ }
+ else {
+ if (resizePolicy == View.PHYSICAL_WORLD)
+ return ci.windowScale ; // see below
+ else
+ return 1.0 ;
+ }
+ }
+
+ /**
+ * Gets the front clip distance scaled to physical meters. This is useful
+ * for ensuring that objects positioned relative to a physical coordinate
+ * system (such as eye, image plate, or coexistence) will be within the
+ * viewable Z depth. This distance will be relative to either the eye or
+ * the image plate depending upon the front clip policy.setFrontClipDistance
, even when the front clip policy
+ * is PHYSICAL_SCREEN
or PHYSICAL_EYE
. If
+ * the window resize policy is PHYSICAL_WORLD
, then physical
+ * clip distances as specified are in fact scaled by the ratio of the
+ * window width to the screen width. The Java 3D view model does this
+ * to prevent the physical clip planes from moving with respect to the
+ * virtual world when the window is resized.VIRTUAL_EYE
or
+ * VIRTUAL_SCREEN
are used, then the View should be attached
+ * to a ViewPlatform that is part of a live scene graph and that has its
+ * ALLOW_LOCAL_TO_VWORLD_READ
capability set; otherwise, a
+ * scale factor of 1.0 will be used for the scale factor from virtual
+ * world units to view platform units.
+ *
+ * @param c3d the Canvas3D to use
+ * @return the physical front clip distance
+ */
+ public double getPhysicalFrontClipDistance(Canvas3D c3d) {
+ CanvasInfo ci = updateCache
+ (c3d, "getPhysicalFrontClipDistance", true) ;
+
+ getClipDistances(ci) ;
+ return ci.frontClipDistance ;
+ }
+
+ /**
+ * Gets the back clip distance scaled to physical meters. This is useful
+ * for ensuring that objects positioned relative to a physical coordinate
+ * system (such as eye, image plate, or coexistence) will be within the
+ * viewable Z depth. This distance will be relative to either the eye or
+ * the image plate depending upon the back clip policy.setBackClipDistance
, even when the back clip policy
+ * is PHYSICAL_SCREEN
or PHYSICAL_EYE
. If
+ * the window resize policy is PHYSICAL_WORLD
, then physical
+ * clip distances as specified are in fact scaled by the ratio of the
+ * window width to the screen width. The Java 3D view model does this
+ * to prevent the physical clip planes from moving with respect to the
+ * virtual world when the window is resized.VIRTUAL_EYE
or
+ * VIRTUAL_SCREEN
are used, then the View should be attached
+ * to a ViewPlatform that is part of a live scene graph and that has its
+ * ALLOW_LOCAL_TO_VWORLD_READ
capability set; otherwise, a
+ * scale factor of 1.0 will be used for the scale factor from virtual
+ * world units to view platform units.
+ *
+ * @param c3d the Canvas3D to use
+ * @return the physical back clip distance
+ */
+ public double getPhysicalBackClipDistance(Canvas3D c3d) {
+ CanvasInfo ci = updateCache(c3d, "getPhysicalBackClipDistance", true) ;
+ getClipDistances(ci) ;
+ return ci.backClipDistance ;
+ }
+
+ private void getClipDistances(CanvasInfo ci) {
+ if (ci.updateClipDistances) {
+ if (verbose) System.err.println("updating clip distances") ;
+
+ ci.frontClipDistance = view.getFrontClipDistance() *
+ getClipScale(ci, frontClipPolicy) ;
+
+ ci.backClipDistance = view.getBackClipDistance() *
+ getClipScale(ci, backClipPolicy) ;
+
+ ci.updateClipDistances = false ;
+ if (verbose) {
+ System.err.println
+ (" front clip distance " + ci.frontClipDistance) ;
+ System.err.println
+ (" back clip distance " + ci.backClipDistance) ;
+ }
+ }
+ }
+
+ private void getScreenScale(CanvasInfo ci) {
+ if (ci.updateScreenScale) {
+ if (verbose) System.err.println("updating screen scale") ;
+
+ if (scalePolicy == View.SCALE_SCREEN_SIZE)
+ ci.screenScale = ci.si.screenWidth / 2.0 ;
+ else
+ ci.screenScale = view.getScreenScale() ;
+
+ ci.updateScreenScale = false ;
+ if (verbose) System.err.println("screen scale " + ci.screenScale) ;
+ }
+ }
+
+ /**
+ * Gets the scale factor from physical meters to view platform units.
+ *
+ *
+ *
+ * @param c3d the Canvas3D to use
+ * @return the physical to view platform scale
+ */
+ public double getPhysicalToViewPlatformScale(Canvas3D c3d) {
+ CanvasInfo ci = updateCache
+ (c3d, "getPhysicalToViewPlatformScale", false) ;
+
+ getPhysicalToViewPlatformScale(ci) ;
+ return ci.physicalToVpScale ;
+ }
+
+ private void getPhysicalToViewPlatformScale(CanvasInfo ci) {
+ if (ci.updatePhysicalToVpScale) {
+ if (verbose) System.err.println("updating PhysicalToVp scale") ;
+
+ getScreenScale(ci) ;
+ if (resizePolicy == View.PHYSICAL_WORLD)
+ ci.physicalToVpScale = 1.0/(ci.screenScale * ci.windowScale) ;
+ else
+ ci.physicalToVpScale = 1.0/ci.screenScale ;
+
+ ci.updatePhysicalToVpScale = false ;
+ if (verbose) System.err.println("PhysicalToVp scale " +
+ ci.physicalToVpScale) ;
+ }
+ }
+
+ /**
+ * Gets the scale factor from physical meters to virtual units.PHYSICAL_WORLD
, which
+ * alters the scale depending upon the width of the canvas.SCALE_SCREEN_SIZE
,
+ * which alters the scale depending upon the width of the screen
+ * associated with the canvas.getPhysicalToViewPlatformScale
.ALLOW_LOCAL_TO_VWORLD_READ
capability set.
+ *
+ * @param c3d the Canvas3D to use
+ * @return the physical to virtual scale
+ * @see #getPhysicalToViewPlatformScale
+ * getPhysicalToViewPlatformScale(Canvas3D)
+ */
+ public double getPhysicalToVirtualScale(Canvas3D c3d) {
+ CanvasInfo ci = updateCache(c3d, "getPhysicalToVirtualScale", true) ;
+ getPhysicalToVirtualScale(ci) ;
+ return ci.physicalToVirtualScale ;
+ }
+
+ private void getPhysicalToVirtualScale(CanvasInfo ci) {
+ if (ci.updatePhysicalToVirtualScale) {
+ if (verbose)
+ System.err.println("updating PhysicalToVirtual scale") ;
+
+ getPhysicalToViewPlatformScale(ci) ;
+ ci.physicalToVirtualScale =
+ ci.physicalToVpScale / vpi.vworldToViewPlatformScale ;
+
+ ci.updatePhysicalToVirtualScale = false ;
+ if (verbose) System.err.println("PhysicalToVirtual scale " +
+ ci.physicalToVirtualScale) ;
+ }
+ }
+
+ /**
+ * Gets the width of the specified canvas scaled to physical meters. This
+ * is derived from the physical screen width as reported by the Screen3D
+ * associated with the canvas. If the screen width is not explicitly set
+ * using the setPhysicalScreenWidth
method of Screen3D, then
+ * Java 3D will derive the screen width based on a screen resolution of 90
+ * pixels/inch.
+ *
+ * @param c3d the Canvas3D to use
+ * @return the width of the canvas scaled to physical meters
+ */
+ public double getPhysicalWidth(Canvas3D c3d) {
+ CanvasInfo ci = updateCache(c3d, "getPhysicalWidth", false) ;
+ return ci.canvasWidth ;
+ }
+
+ /**
+ * Gets the height of the specified canvas scaled to physical meters. This
+ * is derived from the physical screen height as reported by the Screen3D
+ * associated with the canvas. If the screen height is not explicitly set
+ * using the setPhysicalScreenHeight
method of Screen3D, then
+ * Java 3D will derive the screen height based on a screen resolution of 90
+ * pixels/inch.
+ *
+ * @param c3d the Canvas3D to use
+ * @return the height of the canvas scaled to physical meters
+ */
+ public double getPhysicalHeight(Canvas3D c3d) {
+ CanvasInfo ci = updateCache(c3d, "getPhysicalHeight", false) ;
+ return ci.canvasHeight ;
+ }
+
+ /**
+ * Gets the location of the specified canvas relative to the image plate
+ * origin. This is derived from the physical screen parameters as
+ * reported by the Screen3D associated with the canvas. If the screen
+ * width and height are not explicitly set in Screen3D, then Java 3D will
+ * derive those screen parameters based on a screen resolution of 90
+ * pixels/inch.
+ *
+ * @param c3d the Canvas3D to use
+ * @param location the output position, in meters, of the lower-left
+ * corner of the canvas relative to the image plate lower-left corner; Z
+ * is always 0.0
+ */
+ public void getPhysicalLocation(Canvas3D c3d, Point3d location) {
+ CanvasInfo ci = updateCache(c3d, "getPhysicalLocation", false) ;
+ location.set(ci.canvasX, ci.canvasY, 0.0) ;
+ }
+
+ /**
+ * Gets the location of the AWT pixel value and copies it into the
+ * specified Point3d.
+ *
+ * @param c3d the Canvas3D to use
+ * @param x the X coordinate of the pixel relative to the upper-left
+ * corner of the canvas
+ * @param y the Y coordinate of the pixel relative to the upper-left
+ * corner of the canvas
+ * @param location the output position, in meters, relative to the
+ * lower-left corner of the image plate; Z is always 0.0
+ */
+ public void getPixelLocationInImagePlate(Canvas3D c3d, int x, int y,
+ Point3d location) {
+
+ CanvasInfo ci = updateCache
+ (c3d, "getPixelLocationInImagePlate", false) ;
+
+ location.set(ci.canvasX + ((double)x * ci.si.metersPerPixelX),
+ ci.canvasY - ((double)y * ci.si.metersPerPixelY) +
+ ci.canvasHeight, 0.0) ;
+ }
+
+ /**
+ * Gets a read from the specified sensor and transforms it to virtual
+ * world coordinates. The View must be attached to a ViewPlatform which
+ * is part of a live scene graph, and the ViewPlatform node must have its
+ * ALLOW_LOCAL_TO_VWORLD_READ
capability set.getViewPlatformToCoexistence
.
+ *
+ * @param sensor the Sensor instance to read
+ * @param s2vw the output transform
+ * @see #getViewPlatformToCoexistence
+ * getViewPlatformToCoexistence(Canvas3D, Transform3D)
+ */
+ public void getSensorToVworld(Canvas3D c3d,
+ Sensor sensor, Transform3D s2vw) {
+
+ CanvasInfo ci = updateCache(c3d, "getSensorToVworld", true) ;
+ getTrackerBaseToVworld(ci) ;
+ sensor.getRead(s2vw) ;
+ s2vw.mul(ci.trackerBaseToVworld, s2vw) ;
+ }
+
+ /**
+ * Gets the transform from tracker base coordinates to view platform
+ * coordinates and copies it into the specified Transform3D.getViewPlatformToCoexistence
.
+ *
+ * @param c3d the Canvas3D to use
+ * @param tb2vp the output transform
+ * @see #getViewPlatformToCoexistence
+ * getViewPlatformToCoexistence(Canvas3D, Transform3D)
+ */
+ public void getTrackerBaseToViewPlatform(Canvas3D c3d, Transform3D tb2vp) {
+ CanvasInfo ci = updateCache
+ (c3d, "getTrackerBaseToViewPlatform", false) ;
+
+ getTrackerBaseToViewPlatform(ci) ;
+ tb2vp.set(ci.trackerBaseToViewPlatform) ;
+ }
+
+ private void getTrackerBaseToViewPlatform(CanvasInfo ci) {
+ if (ci.updateTrackerBaseToViewPlatform) {
+ if (verbose) System.err.println("updating TrackerBaseToVp") ;
+ if (ci.trackerBaseToViewPlatform == null)
+ ci.trackerBaseToViewPlatform = new Transform3D() ;
+
+ getViewPlatformToCoexistence(ci) ;
+ ci.trackerBaseToViewPlatform.mul(coeToTrackerBase,
+ ci.viewPlatformToCoe) ;
+
+ ci.trackerBaseToViewPlatform.invert() ;
+ ci.updateTrackerBaseToViewPlatform = false ;
+ if (verbose) t3dPrint(ci.trackerBaseToViewPlatform,
+ "TrackerBaseToViewPlatform") ;
+ }
+ }
+
+ /**
+ * Gets the transform from tracker base coordinates to virtual world
+ * coordinates and copies it into the specified Transform3D. The View
+ * must be attached to a ViewPlatform which is part of a live scene graph,
+ * and the ViewPlatform node must have its
+ * ALLOW_LOCAL_TO_VWORLD_READ
capability set.getViewPlatformToCoexistence
.
+ *
+ * @param c3d the Canvas3D to use
+ * @param tb2vw the output transform
+ * @see #getViewPlatformToCoexistence
+ * getViewPlatformToCoexistence(Canvas3D, Transform3D)
+ */
+ public void getTrackerBaseToVworld(Canvas3D c3d, Transform3D tb2vw) {
+ CanvasInfo ci = updateCache(c3d, "getTrackerBaseToVworld", true) ;
+ getTrackerBaseToVworld(ci) ;
+ tb2vw.set(ci.trackerBaseToVworld) ;
+ }
+
+ private void getTrackerBaseToVworld(CanvasInfo ci) {
+ if (ci.updateTrackerBaseToVworld) {
+ if (verbose) System.err.println("updating TrackerBaseToVworld") ;
+ if (ci.trackerBaseToVworld == null)
+ ci.trackerBaseToVworld = new Transform3D() ;
+ //
+ // We compute trackerBaseToViewPlatform and compose with
+ // viewPlatformToVworld instead of computing imagePlateToVworld
+ // and composing with trackerBaseToImagePlate. That way it works
+ // with HMD and avoids the issue of choosing the left image plate
+ // or right image plate transform.
+ //
+ getTrackerBaseToViewPlatform(ci) ;
+ ci.trackerBaseToVworld.mul(vpi.viewPlatformToVworld,
+ ci.trackerBaseToViewPlatform) ;
+
+ ci.updateTrackerBaseToVworld = false ;
+ }
+ }
+
+ /**
+ * Release all static memory references held by ViewInfo, if any. These
+ * are the Screen3D and ViewPlatform maps shared by all existing ViewInfo
+ * instances if they're not provided by a constructor. Releasing the
+ * screen references effectively releases all canvas references in all
+ * ViewInfo instances as well.localToVworld
transform. The screen and canvas components
+ * as well as the ViewPlatform's localToVworld
are cached
+ * separately.attachViewPlatform
method, or if
+ * any of the setCanvas3D
, addCanvas3D
,
+ * insertCanvas3D
, removeCanvas3D
, or
+ * removeAllCanvas3Ds
methods of View are called to change
+ * the View's canvas list.localToVworld
+ * transform of the view platform. If automatic update has not been
+ * enabled for this transform, then this method should be called anytime
+ * the view platform has been repositioned in the virtual world and a
+ * transform involving virtual world coordinates is desired.ALLOW_LOCAL_TO_VWORLD_READ
capability set.
+ */
+ public void updateViewPlatform() {
+ if (verbose) System.err.println("updateViewPlatform") ;
+ vpi.updateViewPlatformToVworld = true ;
+ }
+
+ //
+ // Set cache update bits based on auto update flags.
+ // VIEW_AUTO_UPDATE is handled in updateCache().
+ //
+ private void getAutoUpdate(CanvasInfo ci) {
+ if ((autoUpdateFlags & SCREEN_AUTO_UPDATE) != 0)
+ ci.si.updateScreen = true ;
+
+ if ((autoUpdateFlags & CANVAS_AUTO_UPDATE) != 0)
+ ci.updateCanvas = true ;
+
+ if ((autoUpdateFlags & PLATFORM_AUTO_UPDATE) != 0)
+ vpi.updateViewPlatformToVworld = true ;
+
+ if ((autoUpdateFlags & HEAD_AUTO_UPDATE) != 0)
+ this.updateHead = true ;
+ }
+
+ //
+ // Update any changed cached data. This takes a Canvas3D instance. The
+ // cache mechanism could have used a Canvas3D index into the View instead,
+ // but the direct reference is probably more convenient for applications.
+ //
+ private CanvasInfo updateCache(Canvas3D c3d, String name, boolean vworld) {
+ if (verbose) {
+ System.err.println("updateCache: " + name + " in " + hashCode()) ;
+ System.err.println(" canvas " + c3d.hashCode()) ;
+ }
+
+ // The View may have had Canvas3D instances added or removed, or may
+ // have been attached to a different ViewPlatform, so update the view
+ // before anything else.
+ if (updateView || (autoUpdateFlags & VIEW_AUTO_UPDATE) != 0)
+ getViewInfo() ;
+
+ // Now get the CanvasInfo to update.
+ CanvasInfo ci = (CanvasInfo)canvasMap.get(c3d) ;
+ if (ci == null)
+ throw new IllegalArgumentException(
+ "Specified Canvas3D is not a component of the View") ;
+
+ // Check rest of autoUpdateFlags.
+ if (autoUpdate) getAutoUpdate(ci) ;
+
+ // Update the screen, canvas, view platform, and head caches.
+ if (ci.si.updateScreen)
+ ci.si.getScreenInfo() ;
+
+ if (ci.updateCanvas)
+ ci.getCanvasInfo() ;
+
+ if (vworld && vpi.updateViewPlatformToVworld)
+ vpi.getViewPlatformToVworld() ;
+
+ if (useTracking && updateHead)
+ getHeadInfo() ;
+
+ // Return the CanvasInfo instance.
+ return ci ;
+ }
+
+ //
+ // Get physical view parameters and derived data. This is a fairly
+ // heavyweight method -- everything gets marked for update since we don't
+ // currently track changes in individual view attributes. Fortunately
+ // there shouldn't be a need to call it very often.
+ //
+ private void getViewInfo() {
+ if (verbose) System.err.println(" getViewInfo") ;
+
+ // Check if an update of the Canvas3D collection is needed.
+ if (this.canvasCount != view.numCanvas3Ds()) {
+ this.canvasCount = view.numCanvas3Ds() ;
+ getCanvases() ;
+ }
+ else {
+ for (int i = 0 ; i < canvasCount ; i++) {
+ if (canvasMap.get(view.getCanvas3D(i)) != canvasInfo[i]) {
+ getCanvases() ;
+ break ;
+ }
+ }
+ }
+
+ // Update the ViewPlatform.
+ getViewPlatform() ;
+
+ // Update the PhysicalBody and PhysicalEnvironment.
+ this.body = view.getPhysicalBody() ;
+ this.env = view.getPhysicalEnvironment() ;
+
+ // Use the result of the possibly overridden method useHeadTracking()
+ // to determine if head tracking is to be used within ViewInfo.
+ this.useTracking = useHeadTracking() ;
+
+ // Get the head tracker only if really available.
+ if (view.getTrackingEnable() && env.getTrackingAvailable()) {
+ int headIndex = env.getHeadIndex() ;
+ this.headTracker = env.getSensor(headIndex) ;
+ }
+
+ // Get the new policies and update data derived from them.
+ this.viewPolicy = view.getViewPolicy() ;
+ this.projectionPolicy = view.getProjectionPolicy() ;
+ this.resizePolicy = view.getWindowResizePolicy() ;
+ this.movementPolicy = view.getWindowMovementPolicy() ;
+ this.eyePolicy = view.getWindowEyepointPolicy() ;
+ this.scalePolicy = view.getScreenScalePolicy() ;
+ this.backClipPolicy = view.getBackClipPolicy() ;
+ this.frontClipPolicy = view.getFrontClipPolicy() ;
+
+ if (useTracking || viewPolicy == View.HMD_VIEW) {
+ if (this.headToHeadTracker == null)
+ this.headToHeadTracker = new Transform3D() ;
+ if (this.headTrackerToTrackerBase == null)
+ this.headTrackerToTrackerBase = new Transform3D() ;
+
+ if (viewPolicy == View.HMD_VIEW) {
+ if (this.trackerBaseToHeadTracker == null)
+ this.trackerBaseToHeadTracker = new Transform3D() ;
+ if (this.coeToHeadTracker == null)
+ this.coeToHeadTracker = new Transform3D() ;
+ }
+ else {
+ if (this.headToTrackerBase == null)
+ this.headToTrackerBase = new Transform3D() ;
+ }
+
+ body.getLeftEyePosition(this.leftEyeInHead) ;
+ body.getRightEyePosition(this.rightEyeInHead) ;
+ body.getHeadToHeadTracker(this.headToHeadTracker) ;
+
+ if (verbose) {
+ System.err.println(" leftEyeInHead " + leftEyeInHead) ;
+ System.err.println(" rightEyeInHead " + rightEyeInHead) ;
+ t3dPrint(headToHeadTracker, " headToHeadTracker") ;
+ }
+ }
+
+ if (eyePolicy == View.RELATIVE_TO_WINDOW ||
+ eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) {
+ body.getLeftEyePosition(this.leftEyeInHead) ;
+ body.getRightEyePosition(this.rightEyeInHead) ;
+ if (verbose) {
+ System.err.println(" leftEyeInHead " + leftEyeInHead) ;
+ System.err.println(" rightEyeInHead " + rightEyeInHead) ;
+ }
+ }
+
+ if ((env.getCoexistenceCenterInPworldPolicy() !=
+ View.NOMINAL_SCREEN) || (viewPolicy == View.HMD_VIEW))
+ this.coeCentering = false ;
+ else
+ this.coeCentering = view.getCoexistenceCenteringEnable() ;
+
+ if (!coeCentering || useTracking) {
+ if (this.coeToTrackerBase == null)
+ this.coeToTrackerBase = new Transform3D() ;
+
+ env.getCoexistenceToTrackerBase(this.coeToTrackerBase) ;
+ if (verbose) t3dPrint(coeToTrackerBase, " coeToTrackerBase") ;
+ }
+
+ if (backClipPolicy == View.VIRTUAL_EYE ||
+ backClipPolicy == View.VIRTUAL_SCREEN ||
+ frontClipPolicy == View.VIRTUAL_EYE ||
+ frontClipPolicy == View.VIRTUAL_SCREEN) {
+ this.clipVirtual = true ;
+ }
+ else {
+ this.clipVirtual = false ;
+ }
+
+ // Propagate view updates to each canvas.
+ for (int i = 0 ; i < canvasCount ; i++)
+ this.canvasInfo[i].updateViewDependencies() ;
+
+ this.updateView = false ;
+ if (verbose) {
+ System.err.println(" tracking " + useTracking) ;
+ System.err.println(" coeCentering " + coeCentering) ;
+ System.err.println(" clipVirtual " + clipVirtual) ;
+ }
+ }
+
+ //
+ // Each view can have multiple canvases, each with an associated screen.
+ // Each canvas is associated with only one view. Each screen can have
+ // multiple canvases that are used across multiple views. We rebuild the
+ // canvas info instead of trying to figure out what canvases have been
+ // added or removed from the view.
+ //
+ private void getCanvases() {
+ if (this.canvasInfo.length < canvasCount) {
+ this.canvasInfo = new CanvasInfo[canvasCount] ;
+ }
+
+ for (int i = 0 ; i < canvasCount ; i++) {
+ Canvas3D c3d = view.getCanvas3D(i) ;
+ Screen3D s3d = c3d.getScreen3D() ;
+
+ // Check if we have a new screen.
+ ScreenInfo si = (ScreenInfo)screenMap.get(s3d) ;
+ if (si == null) {
+ si = new ScreenInfo(s3d, c3d.getGraphicsConfiguration()) ;
+ screenMap.put(s3d, si) ;
+ }
+
+ // Check to see if we've encountered the screen so far in this
+ // loop over the view's canvases. If not, clear the screen's list
+ // of canvases for this ViewInfo.
+ if (newSet.add(si)) si.clear(this) ;
+
+ // Check if this is a new canvas.
+ CanvasInfo ci = (CanvasInfo)canvasMap.get(c3d) ;
+ if (ci == null) ci = new CanvasInfo(c3d, si) ;
+
+ // Add this canvas to the screen's list for this ViewInfo.
+ si.addCanvasInfo(this, ci) ;
+
+ // Add this canvas to the new canvas map and canvas array.
+ this.newMap.put(c3d, ci) ;
+ this.canvasInfo[i] = ci ;
+ }
+
+ // Null out old references if canvas count shrinks.
+ for (int i = canvasCount ; i < canvasInfo.length ; i++)
+ this.canvasInfo[i] = null ;
+
+ // Update the CanvasInfo map.
+ Map tmp = canvasMap ;
+ this.canvasMap = newMap ;
+ this.newMap = tmp ;
+
+ // Clear the temporary collections.
+ this.newMap.clear() ;
+ this.newSet.clear() ;
+ }
+
+ //
+ // Force the creation of new CanvasInfo instances. This is called when a
+ // screen is removed from the screen map.
+ //
+ private void clearCanvases() {
+ this.canvasCount = 0 ;
+ this.canvasMap.clear() ;
+ this.updateView = true ;
+ }
+
+ //
+ // Update the view platform. Each view can be attached to only one, but
+ // each view platform can have many views attached.
+ //
+ private void getViewPlatform() {
+ ViewPlatform vp = view.getViewPlatform() ;
+ if (vp == null)
+ throw new IllegalStateException
+ ("The View must be attached to a ViewPlatform") ;
+
+ ViewPlatformInfo tmpVpi =
+ (ViewPlatformInfo)viewPlatformMap.get(vp) ;
+
+ if (tmpVpi == null) {
+ // We haven't encountered this ViewPlatform before.
+ tmpVpi = new ViewPlatformInfo(vp) ;
+ viewPlatformMap.put(vp, tmpVpi) ;
+ }
+
+ if (this.vpi != tmpVpi) {
+ // ViewPlatform has changed. Could set an update flag here if it
+ // would be used, but updating the view updates everything anyway.
+ if (this.vpi != null) {
+ // Remove this ViewInfo from the list of Views attached to the
+ // old ViewPlatform.
+ this.vpi.removeViewInfo(this) ;
+ }
+ this.vpi = tmpVpi ;
+ this.vpi.addViewInfo(this) ;
+
+ // updateViewPlatformToVworld is initially set false since the
+ // capability to read the vworld transform may not be
+ // available. If it is, set it here.
+ if (vp.getCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ)) {
+ this.vpi.updateViewPlatformToVworld = true ;
+ if (verbose) System.err.println(" vworld read allowed") ;
+ } else
+ if (verbose) System.err.println(" vworld read disallowed") ;
+ }
+ }
+
+ //
+ // Force the creation of a new ViewPlatformInfo when a view platform is
+ // removed from the view platform map.
+ //
+ private void clearViewPlatform() {
+ this.updateView = true ;
+ }
+
+ //
+ // Update vworld dependencies for this ViewInfo -- called by
+ // ViewPlatformInfo.getViewPlatformToVworld().
+ //
+ private void updateVworldDependencies() {
+ for (int i = 0 ; i < canvasCount ; i++)
+ this.canvasInfo[i].updateVworldDependencies() ;
+ }
+
+ /**
+ * Returns a reference to a Transform3D containing the current transform
+ * from head tracker coordinates to tracker base coordinates. It is only
+ * called if useHeadTracking
returns true and a head position
+ * update is specified with updateHead
or the
+ * HEAD_AUTO_UPDATE
constructor flag.getRead
method directly. The result is a sensor reading
+ * that may have been taken at a slightly different time from the one used
+ * by the renderer. This method can be overridden to synchronize the two
+ * readings through an external mechanism.
+ *
+ * @return current head tracker to tracker base transform
+ * @see #useHeadTracking
+ * @see #updateHead
+ * @see #HEAD_AUTO_UPDATE
+ */
+ protected Transform3D getHeadTrackerToTrackerBase() {
+ headTracker.getRead(this.headTrackerToTrackerBase) ;
+ return this.headTrackerToTrackerBase ;
+ }
+
+ /**
+ * Returns true
if head tracking should be used.true
if the View's
+ * getTrackingEnable
method and the PhysicalEnvironment's
+ * getTrackingAvailable
method both return true
.
+ * These are the same conditions under which the Java 3D renderer uses
+ * head tracking. This method can be overridden if there is any need to
+ * decouple the head tracking status of ViewInfo from the renderer.
+ *
+ * @return true
if ViewInfo should use head tracking
+ */
+ protected boolean useHeadTracking() {
+ return view.getTrackingEnable() && env.getTrackingAvailable() ;
+ }
+
+ //
+ // Cache the current tracked head position and derived data.
+ //
+ private void getHeadInfo() {
+ if (verbose) System.err.println(" getHeadInfo") ;
+
+ this.headTrackerToTrackerBase = getHeadTrackerToTrackerBase() ;
+ if (viewPolicy == View.HMD_VIEW) {
+ this.trackerBaseToHeadTracker.invert(headTrackerToTrackerBase) ;
+ this.coeToHeadTracker.mul(trackerBaseToHeadTracker,
+ coeToTrackerBase) ;
+ }
+ else {
+ this.headToTrackerBase.mul(headTrackerToTrackerBase,
+ headToHeadTracker) ;
+ }
+ for (int i = 0 ; i < canvasCount ; i++)
+ this.canvasInfo[i].updateHeadDependencies() ;
+
+ this.updateHead = false ;
+ //
+ // The head position used by the Java 3D renderer isn't accessible
+ // in the public API. A head tracker generates continuous data, so
+ // getting the same sensor read as the renderer is unlikely.
+ //
+ // Possible workaround: for fixed screens, get the Java 3D
+ // renderer's version of plateToVworld and headToVworld by calling
+ // Canvas3D.getImagePlateToVworld() and View.getUserHeadToVworld().
+ // Although the vworld components will have frame latency, they can
+ // be cancelled out by inverting the former transform and
+ // multiplying by the latter, resulting in userHeadToImagePlate,
+ // which can then be transformed to tracker base coordinates.
+ //
+ // For head mounted displays, the head to image plate transforms are
+ // just calibration constants, so they're of no use. There are more
+ // involved workarounds possible, but one that may work for both fixed
+ // screens and HMD is to define a SensorInterposer class that extends
+ // Sensor. Take the View's head tracking sensor, use it to construct
+ // a SensorInterposer, and then replace the head tracking sensor with
+ // the SensorInterposer. SensorInterposer can then override the
+ // getRead() methods and thus control what the Java 3D renderer gets.
+ // getHeadTrackerToTrackerBase() is a protected method in ViewInfo
+ // which can be overridden to call a variant of getRead() so that
+ // calls from ViewInfo and from the renderer can be distinguished.
+ //
+ // Even if getting the same head position as used by the renderer is
+ // achieved, tracked eye space interactions with objects in the
+ // virtual world still can't be synchronized with rendering. This
+ // means that objects in the virtual world cannot be made to appear in
+ // a fixed position relative to the tracked head position without a
+ // frame lag between them.
+ //
+ // The reason for this is that the tracked head position used by the
+ // Java 3D renderer is updated asynchronously from scene graph
+ // updates. This is done to reduce latency between the user's
+ // position and the rendered image, which is directly related to the
+ // quality of the immersive virtual reality experience. So while an
+ // update to the scene graph may have a frame latency before it gets
+ // rendered, a change to the user's tracked position is always
+ // reflected in the current frame.
+ //
+ // This problem can't be fixed without eliminating the frame latency
+ // in the Java 3D internal state, although there are possible
+ // workarounds at the expense of increased user position latency.
+ // These involve disabling tracking, reading the head sensor directly,
+ // performing whatever eye space interactions are necessary with the
+ // virtual world (using the view platform's current localToVworld),
+ // and then propagating the head position change to the renderer
+ // manually through a behavior post mechanism that delays it by a
+ // frame.
+ //
+ // For example, with head tracking in a fixed screen environment (such
+ // as a CAVE), disable Java 3D head tracking and set the View's window
+ // eyepoint policy to RELATIVE_TO_COEXISTENCE. Read the sensor to get
+ // the head position relative to the tracker base, transform it to
+ // coexistence coordinates using the inverse of the value of the
+ // coexistenceToTrackerBase transform, and then set the eye positions
+ // manually with the View's set{Left,Right}ManualEyeInCoexistence
+ // methods. If these method calls are delayed through a behavior post
+ // mechanism, then they will be synchronized with the rendering of the
+ // scene graph updates.
+ //
+ // With a head mounted display the sensor can be read directly to get
+ // the head position relative to the tracker base. If Java 3D's head
+ // tracking is disabled, it uses identity for the current
+ // headTrackerToTrackerBase transform. It concatenates its inverse,
+ // trackerBaseToHeadTracker, with coexistenceToTrackerBase to get the
+ // image plate positions in coexistence; the former transform is
+ // inaccessible, but the latter can be set through the
+ // PhysicalEnvironment. So the workaround is to maintain a local copy
+ // with the real value of coexistenceToTrackerBase, but set the
+ // PhysicalEnvironment copy to the product of the real value and the
+ // trackerBaseToHeadTracker inverted from the sensor read. Like the
+ // CAVE example, this update to the View would have to be delayed in
+ // order to synchronize with scene graph updates.
+ //
+ // Another possibility is to put the Java 3D view model in
+ // compatibility mode, where it accepts vpcToEye and eyeToCc
+ // (projection) directly. The various view attributes can still be
+ // set and accessed, but will be ignored by the Java 3D view model.
+ // The ViewInfo methods can be used to compute the view and projection
+ // matrices, which can then be delayed to synchronize with the scene
+ // graph.
+ //
+ // Note that these workarounds could be used to make view-dependent
+ // scene graph updates consistent, but they still can't do anything
+ // about synchronizing the actual physical position of the user with
+ // the rendered images. That requires zero latency between position
+ // update and scene graph state.
+ //
+ // Still another possibility: extrapolate the position of the user
+ // into the next few frames from a sample of recently recorded
+ // positions. Unfortunately, that is also a very hard problem. The
+ // Java 3D Sensor API is designed to support prediction but it was
+ // never realized successfully in the sample implementation.
+ }
+
+ //
+ // A per-screen cache, shared between ViewInfo instances. In the Java 3D
+ // view model a single screen can be associated with multiple canvas
+ // and view instances.
+ //
+ private static class ScreenInfo {
+ private Screen3D s3d = null ;
+ private GraphicsConfiguration graphicsConfiguration = null ;
+ private boolean updateScreen = true ;
+
+ private Map viewInfoMap = new HashMap() ;
+ private List viewInfoList = new LinkedList() ;
+ private Transform3D t3d = new Transform3D() ;
+
+ private double screenWidth = 0.0 ;
+ private double screenHeight = 0.0 ;
+ private boolean updateScreenSize = true ;
+
+ private Rectangle screenBounds = null ;
+ private double metersPerPixelX = 0.0 ;
+ private double metersPerPixelY = 0.0 ;
+ private boolean updatePixelSize = true ;
+
+ // These transforms are pre-allocated here since they are required by
+ // some view policies and we don't know what views this screen will be
+ // attached to. Their default identity values are used if not
+ // explicitly set. TODO: allocate if needed in getCanvasInfo(), where
+ // view information will be available.
+ private Transform3D trackerBaseToPlate = new Transform3D() ;
+ private Transform3D headTrackerToLeftPlate = new Transform3D() ;
+ private Transform3D headTrackerToRightPlate = new Transform3D() ;
+ private boolean updateTrackerBaseToPlate = false ;
+ private boolean updateHeadTrackerToPlate = false ;
+
+ private ScreenInfo(Screen3D s3d, GraphicsConfiguration gc) {
+ this.s3d = s3d ;
+ this.graphicsConfiguration = gc ;
+ if (verbose)
+ System.err.println(" ScreenInfo: init " + s3d.hashCode()) ;
+ }
+
+ private List getCanvasList(ViewInfo vi) {
+ List canvasList = (List)viewInfoMap.get(vi) ;
+ if (canvasList == null) {
+ canvasList = new LinkedList() ;
+ viewInfoMap.put(vi, canvasList) ;
+ viewInfoList.add(canvasList) ;
+ }
+ return canvasList ;
+ }
+
+ private synchronized void clear(ViewInfo vi) {
+ getCanvasList(vi).clear() ;
+ }
+
+ private synchronized void clear() {
+ Iterator i = viewInfoMap.keySet().iterator() ;
+ while (i.hasNext()) ((ViewInfo)i.next()).clearCanvases() ;
+ viewInfoMap.clear() ;
+
+ i = viewInfoList.iterator() ;
+ while (i.hasNext()) ((List)i.next()).clear() ;
+ viewInfoList.clear() ;
+ }
+
+ private synchronized void addCanvasInfo(ViewInfo vi, CanvasInfo ci) {
+ getCanvasList(vi).add(ci) ;
+ }
+
+ //
+ // Get all relevant screen information, find out what changed, and
+ // flag derived data. With normal use it's unlikely that any of the
+ // Screen3D attributes will change after the first time this method is
+ // called. It's possible that the screen resolution changed or some
+ // sort of interactive screen calibration is in process.
+ //
+ private synchronized void getScreenInfo() {
+ if (verbose)
+ System.err.println(" getScreenInfo " + s3d.hashCode());
+
+ // This is used for positioning screens in relation to each other
+ // and must be accurate for good results with multi-screen
+ // displays. By default the coexistence to tracker base transform
+ // is identity so in that case this transform will also set the
+ // image plate in coexistence coordinates.
+ s3d.getTrackerBaseToImagePlate(t3d) ;
+ if (! t3d.equals(trackerBaseToPlate)) {
+ this.trackerBaseToPlate.set(t3d) ;
+ this.updateTrackerBaseToPlate = true ;
+ if (verbose) t3dPrint(trackerBaseToPlate,
+ " trackerBaseToPlate") ;
+ }
+
+ // This transform and the following are used for head mounted
+ // displays. They should be based on the *apparent* position of
+ // the screens as viewed through the HMD optics.
+ s3d.getHeadTrackerToLeftImagePlate(t3d) ;
+ if (! t3d.equals(headTrackerToLeftPlate)) {
+ this.headTrackerToLeftPlate.set(t3d) ;
+ this.updateHeadTrackerToPlate = true ;
+ if (verbose) t3dPrint(headTrackerToLeftPlate,
+ " headTrackerToLeftPlate") ;
+ }
+
+ s3d.getHeadTrackerToRightImagePlate(t3d) ;
+ if (! t3d.equals(headTrackerToRightPlate)) {
+ this.headTrackerToRightPlate.set(t3d) ;
+ this.updateHeadTrackerToPlate = true ;
+ if (verbose) t3dPrint(headTrackerToRightPlate,
+ " headTrackerToRightPlate") ;
+ }
+
+ // If the screen width and height in meters are not explicitly set
+ // through the Screen3D, then the Screen3D will assume a pixel
+ // resolution of 90 pixels/inch and compute the dimensions from
+ // the screen resolution. These dimensions should be measured
+ // accurately for multi-screen displays. For HMD, these
+ // dimensions should be the *apparent* width and height as viewed
+ // through the HMD optics.
+ double w = s3d.getPhysicalScreenWidth() ;
+ double h = s3d.getPhysicalScreenHeight();
+ if (w != screenWidth || h != screenHeight) {
+ this.screenWidth = w ;
+ this.screenHeight = h ;
+ this.updateScreenSize = true ;
+ if (verbose) {
+ System.err.println(" screen width " + screenWidth) ;
+ System.err.println(" screen height " + screenHeight) ;
+ }
+ }
+
+ GraphicsConfiguration gc1 = graphicsConfiguration;
+ // Workaround for Issue 316 - use the default config for screen 0
+ // if the graphics config is null
+ if (gc1 == null) {
+ gc1 = GraphicsEnvironment.getLocalGraphicsEnvironment().
+ getDefaultScreenDevice().getDefaultConfiguration();
+ }
+ this.screenBounds = gc1.getBounds() ;
+ double mpx = screenWidth / (double)screenBounds.width ;
+ double mpy = screenHeight / (double)screenBounds.height ;
+ if ((mpx != metersPerPixelX) || (mpy != metersPerPixelY)) {
+ this.metersPerPixelX = mpx ;
+ this.metersPerPixelY = mpy ;
+ this.updatePixelSize = true ;
+ if (verbose) {
+ System.err.println(" screen bounds " + screenBounds) ;
+ System.err.println(" pixel size X " + metersPerPixelX) ;
+ System.err.println(" pixel size Y " + metersPerPixelY) ;
+ }
+ }
+
+ // Propagate screen updates to each canvas in each ViewInfo.
+ Iterator vi = viewInfoList.iterator() ;
+ while (vi.hasNext()) {
+ Iterator ci = ((List)vi.next()).iterator() ;
+ while (ci.hasNext())
+ ((CanvasInfo)ci.next()).updateScreenDependencies() ;
+ }
+
+ this.updateTrackerBaseToPlate = false ;
+ this.updateHeadTrackerToPlate = false ;
+ this.updateScreenSize = false ;
+ this.updatePixelSize = false ;
+ this.updateScreen = false ;
+ }
+ }
+
+ //
+ // A per-ViewPlatform cache, shared between ViewInfo instances. In the
+ // Java 3D view model, a view platform may have several views attached to
+ // it. The only view platform data cached here is its localToVworld, the
+ // inverse of its localToVworld, and the scale from vworld to view
+ // platform coordinates. The view platform to coexistence transform is
+ // cached by the CanvasInfo instances associated with the ViewInfo.
+ //
+ private static class ViewPlatformInfo {
+ private ViewPlatform vp = null ;
+ private List viewInfo = new LinkedList() ;
+ private double[] m = new double[16] ;
+
+ // These transforms are pre-allocated since we don't know what views
+ // will be attached. Their default identity values are used if a
+ // vworld dependent computation is requested and no initial update of
+ // the view platform was performed; this occurs if the local to vworld
+ // read capability isn't set. TODO: rationalize this and allocate
+ // only if necessary.
+ private Transform3D viewPlatformToVworld = new Transform3D() ;
+ private Transform3D vworldToViewPlatform = new Transform3D() ;
+ private double vworldToViewPlatformScale = 1.0 ;
+
+ // Set these update flags initially false since we might not have the
+ // capability to read the vworld transform.
+ private boolean updateViewPlatformToVworld = false ;
+ private boolean updateVworldScale = false ;
+
+ private ViewPlatformInfo(ViewPlatform vp) {
+ this.vp = vp ;
+ if (verbose) System.err.println
+ (" ViewPlatformInfo: init " + vp.hashCode()) ;
+ }
+
+ private synchronized void addViewInfo(ViewInfo vi) {
+ this.viewInfo.add(vi) ;
+ }
+
+ private synchronized void removeViewInfo(ViewInfo vi) {
+ this.viewInfo.remove(vi) ;
+ }
+
+ private synchronized void clear() {
+ Iterator i = viewInfo.iterator() ;
+ while (i.hasNext()) ((ViewInfo)i.next()).clearViewPlatform() ;
+ viewInfo.clear() ;
+ }
+
+ //
+ // Get the view platform's current localToVworld
and
+ // force the update of derived data.
+ //
+ private synchronized void getViewPlatformToVworld() {
+ if (verbose) System.err.println
+ (" getViewPlatformToVworld " + vp.hashCode()) ;
+
+ vp.getLocalToVworld(this.viewPlatformToVworld) ;
+ this.vworldToViewPlatform.invert(viewPlatformToVworld) ;
+
+ // Get the scale factor from the virtual world to view platform
+ // transform. Note that this is always a congruent transform.
+ vworldToViewPlatform.get(m) ;
+ double newScale = Math.sqrt(m[0]*m[0] + m[1]*m[1] + m[2]*m[2]) ;
+
+ // May need to update clip plane distances if scale changed. We'll
+ // check with an epsilon commensurate with single precision float.
+ // It would be more efficient to check the square of the distance
+ // and then compute the square root only if different, but that
+ // makes choosing an epsilon difficult.
+ if ((newScale > vworldToViewPlatformScale + 0.0000001) ||
+ (newScale < vworldToViewPlatformScale - 0.0000001)) {
+ this.vworldToViewPlatformScale = newScale ;
+ this.updateVworldScale = true ;
+ if (verbose) System.err.println(" vworld scale " +
+ vworldToViewPlatformScale) ;
+ }
+
+ // All virtual world transforms must be updated.
+ Iterator i = viewInfo.iterator() ;
+ while (i.hasNext())
+ ((ViewInfo)i.next()).updateVworldDependencies() ;
+
+ this.updateVworldScale = false ;
+ this.updateViewPlatformToVworld = false ;
+ }
+ }
+
+ //
+ // A per-canvas cache.
+ //
+ private class CanvasInfo {
+ private Canvas3D c3d = null ;
+ private ScreenInfo si = null ;
+ private boolean updateCanvas = true ;
+
+ private double canvasX = 0.0 ;
+ private double canvasY = 0.0 ;
+ private boolean updatePosition = true ;
+
+ private double canvasWidth = 0.0 ;
+ private double canvasHeight = 0.0 ;
+ private double windowScale = 0.0 ;
+ private boolean updateWindowScale = true ;
+
+ private double screenScale = 0.0 ;
+ private boolean updateScreenScale = true ;
+
+ private boolean useStereo = false ;
+ private boolean updateStereo = true ;
+
+ //
+ // coeToPlate is the same for each Canvas3D in a Screen3D unless
+ // coexistence centering is enabled and the window movement policy is
+ // PHYSICAL_WORLD.
+ //
+ private Transform3D coeToPlate = null ;
+ private Transform3D coeToRightPlate = null ;
+ private boolean updateCoeToPlate = true ;
+
+ //
+ // viewPlatformToCoe is the same for each Canvas3D in a View unless
+ // the window resize policy is PHYSICAL_WORLD, in which case the scale
+ // factor includes the window scale; or if the screen scale policy is
+ // SCALE_SCREEN_SIZE, in which case the scale factor depends upon the
+ // width of the screen associated with the canvas; or if the window
+ // eyepoint policy is RELATIVE_TO_FIELD_OF_VIEW and the view attach
+ // policy is not NOMINAL_SCREEN, which will set the view platform
+ // origin in coexistence based on the width of the canvas.
+ //
+ private Transform3D viewPlatformToCoe = null ;
+ private Transform3D coeToViewPlatform = null ;
+ private boolean updateViewPlatformToCoe = true ;
+ private boolean updateCoeToViewPlatform = true ;
+
+ //
+ // plateToViewPlatform is composed from viewPlatformToCoe and
+ // coeToPlate.
+ //
+ private Transform3D plateToViewPlatform = null ;
+ private Transform3D rightPlateToViewPlatform = null ;
+ private boolean updatePlateToViewPlatform = true ;
+
+ //
+ // trackerBaseToViewPlatform is computed from viewPlatformToCoe and
+ // coeToTrackerBase.
+ //
+ private Transform3D trackerBaseToViewPlatform = null ;
+ private boolean updateTrackerBaseToViewPlatform = true ;
+
+ //
+ // Eye position in image plate is always different for each Canvas3D
+ // in a View, unless two or more Canvas3D instances are the same
+ // position and size, or two or more Canvas3D instances are using a
+ // window eyepoint policy of RELATIVE_TO_SCREEN and have the same
+ // settings for the manual eye positions.
+ //
+ private Point3d eyeInPlate = new Point3d() ;
+ private Point3d rightEyeInPlate = new Point3d() ;
+ private Transform3D eyeToPlate = null ;
+ private Transform3D rightEyeToPlate = null ;
+ private boolean updateEyeInPlate = true ;
+
+ private Point3d leftManualEyeInPlate = new Point3d() ;
+ private Point3d rightManualEyeInPlate = new Point3d() ;
+ private boolean updateManualEye = true ;
+
+ private int monoscopicPolicy = -1 ;
+ private boolean updateMonoPolicy = true ;
+
+ //
+ // eyeToViewPlatform is computed from eyeToPlate and
+ // plateToViewPlatform.
+ //
+ private Transform3D eyeToViewPlatform = null ;
+ private Transform3D rightEyeToViewPlatform = null ;
+ private boolean updateEyeToViewPlatform = true ;
+
+ private Transform3D viewPlatformToEye = null ;
+ private Transform3D viewPlatformToRightEye = null ;
+ private boolean updateViewPlatformToEye = true ;
+
+ //
+ // The projection transform depends upon eye position in image plate.
+ //
+ private Transform3D projection = null ;
+ private Transform3D rightProjection = null ;
+ private boolean updateProjection = true ;
+
+ private Transform3D inverseProjection = null ;
+ private Transform3D inverseRightProjection = null ;
+ private boolean updateInverseProjection = true ;
+
+ private Transform3D inverseViewPlatformProjection = null ;
+ private Transform3D inverseViewPlatformRightProjection = null ;
+ private boolean updateInverseViewPlatformProjection = true ;
+
+ //
+ // The physical clip distances can be affected by the canvas width
+ // with the PHYSICAL_WORLD resize policy.
+ //
+ private double frontClipDistance = 0.0 ;
+ private double backClipDistance = 0.0 ;
+ private boolean updateClipDistances = true ;
+
+ //
+ // The physical to view platform scale can be affected by the canvas
+ // width with the PHYSICAL_WORLD resize policy.
+ //
+ private double physicalToVpScale = 0.0 ;
+ private double physicalToVirtualScale = 0.0 ;
+ private boolean updatePhysicalToVpScale = true ;
+ private boolean updatePhysicalToVirtualScale = true ;
+
+ //
+ // The vworld transforms require reading the ViewPlaform's
+ // localToVworld tranform.
+ //
+ private Transform3D plateToVworld = null ;
+ private Transform3D rightPlateToVworld = null ;
+ private boolean updatePlateToVworld = true ;
+
+ private Transform3D coeToVworld = null ;
+ private boolean updateCoeToVworld = true ;
+
+ private Transform3D eyeToVworld = null ;
+ private Transform3D rightEyeToVworld = null ;
+ private boolean updateEyeToVworld = true ;
+
+ private Transform3D trackerBaseToVworld = null ;
+ private boolean updateTrackerBaseToVworld = true ;
+
+ private Transform3D inverseVworldProjection = null ;
+ private Transform3D inverseVworldRightProjection = null ;
+ private boolean updateInverseVworldProjection = true ;
+
+ private CanvasInfo(Canvas3D c3d, ScreenInfo si) {
+ this.si = si ;
+ this.c3d = c3d ;
+ if (verbose) System.err.println(" CanvasInfo: init " +
+ c3d.hashCode()) ;
+ }
+
+ private void getCanvasInfo() {
+ if (verbose) System.err.println(" getCanvasInfo " +
+ c3d.hashCode()) ;
+ boolean newStereo =
+ c3d.getStereoEnable() && c3d.getStereoAvailable() ;
+
+ if (useStereo != newStereo) {
+ this.useStereo = newStereo ;
+ this.updateStereo = true ;
+ if (verbose) System.err.println(" stereo " + useStereo) ;
+ }
+
+ this.canvasWidth = c3d.getWidth() * si.metersPerPixelX ;
+ this.canvasHeight = c3d.getHeight() * si.metersPerPixelY ;
+ double newScale = canvasWidth / si.screenWidth ;
+
+ if (windowScale != newScale) {
+ this.windowScale = newScale ;
+ this.updateWindowScale = true ;
+ if (verbose) {
+ System.err.println(" width " + canvasWidth) ;
+ System.err.println(" height " + canvasHeight) ;
+ System.err.println(" scale " + windowScale) ;
+ }
+ }
+
+ // For multiple physical screens, AWT returns the canvas location
+ // relative to the origin of the aggregated virtual screen. We
+ // need the location relative to the physical screen origin.
+ Point awtLocation = c3d.getLocationOnScreen() ;
+ int x = awtLocation.x - si.screenBounds.x ;
+ int y = awtLocation.y - si.screenBounds.y ;
+
+ double newCanvasX = si.metersPerPixelX * x ;
+ double newCanvasY = si.metersPerPixelY *
+ (si.screenBounds.height - (y + c3d.getHeight())) ;
+
+ if (canvasX != newCanvasX || canvasY != newCanvasY) {
+ this.canvasX = newCanvasX ;
+ this.canvasY = newCanvasY ;
+ this.updatePosition = true ;
+ if (verbose) {
+ System.err.println(" lower left X " + canvasX) ;
+ System.err.println(" lower left Y " + canvasY) ;
+ }
+ }
+
+ int newMonoPolicy = c3d.getMonoscopicViewPolicy() ;
+ if (monoscopicPolicy != newMonoPolicy) {
+ this.monoscopicPolicy = newMonoPolicy ;
+ this.updateMonoPolicy = true ;
+
+ if (verbose && !useStereo) {
+ if (monoscopicPolicy == View.LEFT_EYE_VIEW)
+ System.err.println(" left eye view") ;
+ else if (monoscopicPolicy == View.RIGHT_EYE_VIEW)
+ System.err.println(" right eye view") ;
+ else
+ System.err.println(" cyclopean view") ;
+ }
+ }
+
+ c3d.getLeftManualEyeInImagePlate(leftEye) ;
+ c3d.getRightManualEyeInImagePlate(rightEye) ;
+
+ if (!leftEye.equals(leftManualEyeInPlate) ||
+ !rightEye.equals(rightManualEyeInPlate)) {
+
+ this.leftManualEyeInPlate.set(leftEye) ;
+ this.rightManualEyeInPlate.set(rightEye) ;
+ this.updateManualEye = true ;
+
+ if (verbose && (eyePolicy == View.RELATIVE_TO_WINDOW ||
+ eyePolicy == View.RELATIVE_TO_SCREEN)) {
+ System.err.println(" left manual eye in plate " +
+ leftManualEyeInPlate) ;
+ System.err.println(" right manual eye in plate " +
+ rightManualEyeInPlate) ;
+ }
+ }
+
+ updateCanvasDependencies() ;
+ this.updateStereo = false ;
+ this.updateWindowScale = false ;
+ this.updatePosition = false ;
+ this.updateMonoPolicy = false ;
+ this.updateManualEye = false ;
+ this.updateCanvas = false ;
+ }
+
+ private double getFieldOfViewOffset() {
+ return 0.5 * canvasWidth / Math.tan(0.5 * view.getFieldOfView()) ;
+ }
+
+ private void updateScreenDependencies() {
+ if (si.updatePixelSize || si.updateScreenSize) {
+ if (eyePolicy == View.RELATIVE_TO_WINDOW ||
+ eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) {
+ // Physical location of the canvas might change without
+ // changing the pixel location.
+ updateEyeInPlate = true ;
+ }
+ if (resizePolicy == View.PHYSICAL_WORLD ||
+ eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) {
+ // Could change the window scale or view platform Z offset.
+ updateViewPlatformToCoe = true ;
+ }
+ if (resizePolicy == View.PHYSICAL_WORLD) {
+ // Window scale affects the clip distance and the physical
+ // to viewplatform scale.
+ updateClipDistances = true ;
+ updatePhysicalToVpScale = true ;
+ updatePhysicalToVirtualScale = true ;
+ }
+ // Upper right corner of canvas may have moved from eye.
+ updateProjection = true ;
+ }
+ if (si.updateScreenSize && scalePolicy == View.SCALE_SCREEN_SIZE) {
+ // Screen scale affects the clip distances and physical to
+ // view platform scale. The screen scale is also a component
+ // of viewPlatformToCoe.
+ updateScreenScale = true ;
+ updateClipDistances = true ;
+ updatePhysicalToVpScale = true ;
+ updatePhysicalToVirtualScale = true ;
+ updateViewPlatformToCoe = true ;
+ }
+
+ if (viewPolicy == View.HMD_VIEW) {
+ if (si.updateHeadTrackerToPlate) {
+ // Plate moves with respect to the eye and coexistence.
+ updateEyeInPlate = true ;
+ updateCoeToPlate = true ;
+ }
+ }
+ else if (coeCentering) {
+ if (movementPolicy == View.PHYSICAL_WORLD) {
+ // Coexistence is centered on the canvas.
+ if (si.updatePixelSize || si.updateScreenSize)
+ // Physical location of the canvas might change
+ // without changing the pixel location.
+ updateCoeToPlate = true ;
+ }
+ else if (si.updateScreenSize)
+ // Coexistence is centered on the screen.
+ updateCoeToPlate = true ;
+ }
+ else if (si.updateTrackerBaseToPlate) {
+ // Image plate has possibly changed location. Could be
+ // offset by an update to coeToTrackerBase in the
+ // PhysicalEnvironment though.
+ updateCoeToPlate = true ;
+ }
+
+ if (updateCoeToPlate &&
+ eyePolicy == View.RELATIVE_TO_COEXISTENCE) {
+ // Coexistence has moved with respect to plate.
+ updateEyeInPlate = true ;
+ }
+ if (updateViewPlatformToCoe) {
+ // Derived transforms. trackerBaseToViewPlatform is composed
+ // from viewPlatformToCoe and coexistenceToTrackerBase.
+ updateCoeToViewPlatform = true ;
+ updateCoeToVworld = true ;
+ updateTrackerBaseToViewPlatform = true ;
+ updateTrackerBaseToVworld = true ;
+ }
+ if (updateCoeToPlate || updateViewPlatformToCoe) {
+ // The image plate to view platform transform is composed from
+ // the coexistence to image plate and view platform to
+ // coexistence transforms, so these need updates as well.
+ updatePlateToViewPlatform = true ;
+ updatePlateToVworld = true ;
+ }
+ updateEyeDependencies() ;
+ }
+
+ private void updateEyeDependencies() {
+ if (updateEyeInPlate) {
+ updateEyeToVworld = true ;
+ updateProjection = true ;
+ }
+ if (updateProjection) {
+ updateInverseProjection = true ;
+ updateInverseViewPlatformProjection = true ;
+ updateInverseVworldProjection = true ;
+ }
+ if (updateEyeInPlate || updatePlateToViewPlatform) {
+ updateViewPlatformToEye = true ;
+ updateEyeToViewPlatform = true ;
+ }
+ }
+
+ private void updateCanvasDependencies() {
+ if (updateStereo || updateMonoPolicy ||
+ (updateManualEye && (eyePolicy == View.RELATIVE_TO_WINDOW ||
+ eyePolicy == View.RELATIVE_TO_SCREEN))) {
+ updateEyeInPlate = true ;
+ }
+ if (updateWindowScale || updatePosition) {
+ if (coeCentering && movementPolicy == View.PHYSICAL_WORLD) {
+ // Coexistence is centered on the canvas.
+ updateCoeToPlate = true ;
+ if (eyePolicy == View.RELATIVE_TO_COEXISTENCE)
+ updateEyeInPlate = true ;
+ }
+ if (eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW ||
+ eyePolicy == View.RELATIVE_TO_WINDOW)
+ // Eye depends on canvas position and size.
+ updateEyeInPlate = true ;
+ }
+ if (updateWindowScale) {
+ if (resizePolicy == View.PHYSICAL_WORLD ||
+ eyePolicy == View.RELATIVE_TO_FIELD_OF_VIEW) {
+ // View platform scale and its origin Z offset changed.
+ // trackerBaseToViewPlatform needs viewPlatformToCoe.
+ updateViewPlatformToCoe = true ;
+ updateCoeToViewPlatform = true ;
+ updateCoeToVworld = true ;
+ updateTrackerBaseToViewPlatform = true ;
+ updateTrackerBaseToVworld = true ;
+ }
+ if (resizePolicy == View.PHYSICAL_WORLD) {
+ // Clip distance and physical to view platform scale are
+ // affected by the window size.
+ updateClipDistances = true ;
+ updateProjection = true ;
+ updatePhysicalToVpScale = true ;
+ updatePhysicalToVirtualScale = true ;
+ }
+ }
+ if (updateViewPlatformToCoe || updateCoeToPlate) {
+ // The image plate to view platform transform is composed from
+ // the coexistence to image plate and the view platform to
+ // coexistence transforms, so these need updates.
+ updatePlateToViewPlatform = true ;
+ updatePlateToVworld = true ;
+ }
+ if (coeCentering && !updateManualEye && !updateWindowScale &&
+ (movementPolicy == View.PHYSICAL_WORLD) &&
+ (eyePolicy != View.RELATIVE_TO_SCREEN)) {
+ // The canvas may have moved, but the eye, coexistence, and
+ // view platform moved with it. updateEyeDependencies()
+ // isn't called since it would unnecessarily update the
+ // projection and eyeToViewPlatform transforms. The tested
+ // policies are all true by default.
+ return ;
+ }
+ updateEyeDependencies() ;
+ }
+
+ //
+ // TODO: A brave soul could refine cache updates here. There are a
+ // lot of attributes to monitor, so we just update everything for now.
+ //
+ private void updateViewDependencies() {
+ // View policy, physical body eye positions, head to head
+ // tracker, window eyepoint policy, field of view, coexistence
+ // centering, or coexistence to image plate may have changed.
+ updateEyeInPlate = true ;
+
+ // If the eye position in image plate has changed, then the
+ // projection transform may need to be updated. The projection
+ // policy and clip plane distances and policies may have changed.
+ // The window resize policy and screen scale may have changed,
+ // which affects clip plane distance scaling.
+ updateProjection = true ;
+ updateClipDistances = true ;
+ updatePhysicalToVpScale = true ;
+ updatePhysicalToVirtualScale = true ;
+
+ // View policy, coexistence to tracker base, coexistence centering
+ // enable, or window movement policy may have changed.
+ updateCoeToPlate = true ;
+
+ // Screen scale, resize policy, view policy, view platform,
+ // physical body, physical environment, eyepoint policy, or field
+ // of view may have changed.
+ updateViewPlatformToCoe = true ;
+ updateCoeToViewPlatform = true ;
+ updateCoeToVworld = true ;
+
+ // The image plate to view platform transform is composed from the
+ // coexistence to image plate and view platform to coexistence
+ // transforms, so these need updates.
+ updatePlateToViewPlatform = true ;
+ updatePlateToVworld = true ;
+
+ // View platform to coexistence or coexistence to tracker base may
+ // have changed.
+ updateTrackerBaseToViewPlatform = true ;
+ updateTrackerBaseToVworld = true ;
+
+ // Screen scale policy or explicit screen scale may have changed.
+ updateScreenScale = true ;
+
+ // Update transforms derived from eye info.
+ updateEyeDependencies() ;
+ }
+
+ private void updateHeadDependencies() {
+ if (viewPolicy == View.HMD_VIEW) {
+ // Image plates are fixed relative to the head, so their
+ // positions have changed with respect to coexistence, the
+ // view platform, and the virtual world. The eyes are fixed
+ // with respect to the image plates, so the projection doesn't
+ // change with respect to them.
+ updateCoeToPlate = true ;
+ updatePlateToViewPlatform = true ;
+ updatePlateToVworld = true ;
+ updateViewPlatformToEye = true ;
+ updateEyeToViewPlatform = true ;
+ updateEyeToVworld = true ;
+ updateInverseViewPlatformProjection = true ;
+ updateInverseVworldProjection = true ;
+ }
+ else {
+ // Eye positions have changed with respect to the fixed
+ // screens, so the projections must be updated as well as the
+ // positions.
+ updateEyeInPlate = true ;
+ updateEyeDependencies() ;
+ }
+ }
+
+ private void updateVworldDependencies() {
+ updatePlateToVworld = true ;
+ updateCoeToVworld = true ;
+ updateEyeToVworld = true ;
+ updateTrackerBaseToVworld = true ;
+ updateInverseVworldProjection = true ;
+
+ if (vpi.updateVworldScale)
+ updatePhysicalToVirtualScale = true ;
+
+ if (vpi.updateVworldScale && clipVirtual) {
+ // vworldToViewPlatformScale changed and clip plane distances
+ // are in virtual units.
+ updateProjection = true ;
+ updateClipDistances = true ;
+ updateInverseProjection = true ;
+ updateInverseViewPlatformProjection = true ;
+ }
+ }
+ }
+
+ /**
+ * Prints out the specified transform in a readable format.
+ *
+ * @param t3d transform to be printed
+ * @param name the name of the transform
+ */
+ private static void t3dPrint(Transform3D t3d, String name) {
+ double[] m = new double[16] ;
+ t3d.get(m) ;
+ String[] sa = formatMatrixRows(4, 4, m) ;
+ System.err.println(name) ;
+ for (int i = 0 ; i < 4 ; i++) System.err.println(sa[i]) ;
+ }
+
+ /**
+ * Formats a matrix with fixed fractional digits and integer padding to
+ * align the decimal points in columns. Non-negative numbers print up to
+ * 7 integer digits, while negative numbers print up to 6 integer digits
+ * to account for the negative sign. 6 fractional digits are printed.
+ *
+ * @param rowCount number of rows in the matrix
+ * @param colCount number of columns in the matrix
+ * @param m matrix to be formatted
+ * @return matrix rows formatted into strings
+ */
+ private static String[] formatMatrixRows
+ (int rowCount, int colCount, double[] m) {
+
+ DecimalFormat df = new DecimalFormat("0.000000") ;
+ FieldPosition fp = new FieldPosition(DecimalFormat.INTEGER_FIELD) ;
+ StringBuffer sb0 = new StringBuffer() ;
+ StringBuffer sb1 = new StringBuffer() ;
+ String[] rows = new String[rowCount] ;
+
+ for (int i = 0 ; i < rowCount ; i++) {
+ sb0.setLength(0) ;
+ for (int j = 0 ; j < colCount ; j++) {
+ sb1.setLength(0) ;
+ df.format(m[i*colCount+j], sb1, fp) ;
+ int pad = 8 - fp.getEndIndex() ;
+ for (int k = 0 ; k < pad ; k++) {
+ sb1.insert(0, " ") ;
+ }
+ sb0.append(sb1) ;
+ }
+ rows[i] = sb0.toString() ;
+ }
+ return rows ;
+ }
+}
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/Viewer.java b/src/classes/share/org/jogamp/java3d/utils/universe/Viewer.java
new file mode 100644
index 0000000..52c7a74
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/Viewer.java
@@ -0,0 +1,888 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any
+ * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
+ * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
+ * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
+ * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
+ * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
+ * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+ * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
+ * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or
+ * intended for use in the design, construction, operation or
+ * maintenance of any nuclear facility.
+ *
+ */
+
+package org.jogamp.java3d.utils.universe;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Frame;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Panel;
+import java.awt.Rectangle;
+import java.awt.Window;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+
+import org.jogamp.java3d.AudioDevice;
+import org.jogamp.java3d.Canvas3D;
+import org.jogamp.java3d.GraphicsConfigTemplate3D;
+import org.jogamp.java3d.PhysicalBody;
+import org.jogamp.java3d.PhysicalEnvironment;
+import org.jogamp.java3d.Screen3D;
+import org.jogamp.java3d.Transform3D;
+import org.jogamp.java3d.View;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import org.jogamp.java3d.audioengines.AudioEngine3DL2;
+
+/**
+ * The Viewer class holds all the information that describes the physical
+ * and virtual "presence" in the Java 3D universe. The Viewer object
+ * consists of:
+ *
+ *
+ * If the Viewer object is created without any Canvas3D's, or indirectly
+ * through a configuration file, it will create the Canvas3D's as needed.
+ * The default Viewer creates one Canvas3D. If the Viewer object creates
+ * the Canvas3D's, it will also create a JPanel and JFrame for each Canvas3D.
+ *
+ * Dynamic video resize is a new feature in Java 3D 1.3.1.
+ * This feature provides a means for doing swap synchronous resizing
+ * of the area that is to be magnified (or passed through) to the
+ * output video resolution. This functionality allows an application
+ * to draw into a smaller viewport in the framebuffer in order to reduce
+ * the time spent doing pixel fill. The reduced size viewport is then
+ * magnified up to the video output resolution using the SUN_video_resize
+ * extension. This extension is only implemented in XVR-4000 and later
+ * hardware with back end video out resizing capability.
+ *
+ * If video size compensation is enable, the line widths, point sizes and pixel
+ * operations will be scaled internally with the resize factor to approximately
+ * compensate for video resizing. The location of the pixel ( x, y ) in the
+ * resized framebuffer = ( floor( x * factor + 0.5 ), floor( y * factor + 0.5 ) )
+ *
+ *
+ *
+ *
+ *
+ *
+Example Configuration Files
+
+
j3d1x1 A single fullscreen
+desktop configuration.
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/config-syntax.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/config-syntax.html
new file mode 100644
index 0000000..e725146
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/config-syntax.html
@@ -0,0 +1,1973 @@
+
+
+
+
+
+
+
+
+
+
+The Java 3D Configuration File
+
+
+Syntax Description
+Command Overview
+
+ Overview of Relevant View Model Parameters
+Top-Level Command Details
+Built-In Command Details
+Command Index
+Property Index
+
+
+
+
+
+
+
+
+
+Syntax Description
+
+
+
+
+Points
+
+A command that consists entirely of two, three, or four numbers is a 2D point,
+a 3D point, or a 4D point respectively. Any other command that starts with a
+number is a syntax error.
+
+Matrices
+
+A 3D matrix is a command that consists entirely of three 3D points. A 4D
+matrix consists entirely of either three or four 4D points; if there are only
+three 4D points then the fourth is implicitly considered to be (0.0 0.0 0.0
+1.0). The points define the row elements of each type of matrix. Any other
+command that starts with a point is a syntax error.
+
+
+Top-level and built-in commands
+
+All other commands start with an alphanumeric string, the command name
+which identifies it. The remaining elements of the command are its arguments.
+
+Java property substitution syntax
+
+All strings are additionally scanned for text enclosed by a starting ${ and a
+matching }. Such text is looked up as a Java system property name and the
+result is substituted back into the string after eliding the starting and
+ending delimiters. For example, the command:
+
+
+
+
+
+
+
+
+Command Overview
+
+
+
+
+
+
+
+
+Overview of Relevant View Model Parameters
+
+
+
+
+
+The Camera View Model
+
+
+
+
+
+The Java 3D View Model
+
+
+
+When a configuration file is being used the defaults are oriented towards
+making the setup of multiple screen environments as easy as possible. If the
+coexistence centering enable has not been explicitly set, and either the
+CoexistenceToTrackerBase transform for the view has been set or
+TrackerBaseToImagePlate has been set for any screen, then the following
+defaults are used instead:RELATIVE_TO_FIELD_OF_VIEW
.PHYSICAL_WORLD
.PHYSICAL_WORLD
.NOMINAL_HEAD
.
+
+
+The avove defaults are also used if coexistence centering enable has been
+explictly set false.
+RELATIVE_TO_COEXISTENCE
.VIRTUAL_WORLD
.VIRTUAL_WORLD
.NOMINAL_SCREEN
.
+
+
+
+
+
+
+
+Top-Level Command Details
+
+
+
+NewDevice
+Syntax:
+
(NewDevice <instance name> <class name>
+[Alias <alias name>])
+
+
+
+DeviceProperty
+Syntax:
+
(DeviceProperty <instance name> <method name> <arg0>
+... <argn>)
+
+
+
+NewSensor
+Syntax:
+
(NewSensor <instance name> <device name>
+<sensor index> [Alias <alias name>])
+
+
+
+SensorProperty
+Syntax:
+
(SensorProperty <instance name> <property name>
+<property value>)
+
+
+
+Hotspot
+A 3D point in the sensor's local coordinate system. The hotspot specifies the
+"active" point which should interact with the virtual world, such as a point
+used for picking or grabbing an object. Its actual interpretation is up to the
+sensor behavior which uses it. Its value is ignored for head tracking sensors.
+
+
+
+NewScreen
+Syntax:
+
+NewWindow
(NewScreen <instance name> <device index>
+[Alias <alias name>])
+
(NewWindow <instance name> <device index>
+[Alias <alias name>])
+
+
+
+ScreenProperty
+Syntax:
+
+WindowProperty
(ScreenProperty <instance name> <property name>
+<property value>)
+
(WindowProperty <instance name> <property name>
+<property value>)
+
+
+PhysicalScreenWidth
+A number specifying the screen's image area width in meters. When using a
+configuration file the default is 0.365. For head mounted displays this should
+be the apparent width of the display at the focal plane.
+
+
+PhysicalScreenHeight
+A number specifying the screen's image area height in meters. When using a
+configuration file the default is 0.292. For head mounted displays this should
+be the apparent height of the display at the focal plane.
+
+
+WindowSize
+This property's value can be a 2D point to create a window with the specified
+X width and Y height in pixels, or it can be either of the strings FullScreen
+or NoBorderFullScreen to specify a full screen canvas with visible frame
+borders or one with no frame borders. A NoBorderFullScreen canvas uses the
+entire physical display surface for its image. The default value is 512 x 512
+pixels. For multiple screen virtual reality installations or head mounted
+displays NoBorderFullScreen should be used.
+
+
+WindowPosition
+This property's value is a 2D point used to create a window with the specified
+X and Y position. These are offsets of the window's upper left corner from the
+screen's upper left corner.
+
+
+TrackerBaseToImagePlate
+A 4D matrix which transforms points from tracker base coordinates to the image
+plate coordinates for the specified screen. This is only used when a
+ViewPolicy of SCREEN_VIEW
is in effect. The matrix value is
+identity by default.
+
+HeadTrackerToLeftImagePlate
+4D matrices which transform points in the head tracking sensor's local
+coordinate system to a head mounted display's left and right image plates
+respectively. The default value for each is the identity matrix.
+HeadTrackerToRightImagePlateHMD_VIEW
is in effect.
+As with physical screen dimensions, these matrices should indicate the
+apparent location and orientation of the screen images as viewed through
+the head mounted display's optics.
+MonoscopicViewPolicy
+This property may have the following string values: CYCLOPEAN_EYE_VIEW,
+LEFT_EYE_VIEW
, or RIGHT_EYE_VIEW
. The default value is
+CYCLOPEAN_EYE_VIEW
. This default works for non-stereo displays
+and field-sequential stereo displays where the two stereo images are generated
+on the same canvas.HMD_VIEW
with the default
+CYCLOPEAN_EYE_VIEW
policy in effect.LEFT_EYE_VIEW
and RIGHT_EYE_VIEW
monoscopic view
+policies are used for generating stereo pairs on separate monoscopic canvases,
+including the left and right canvases needed by HMD devices that are driven by
+two video channels. When using these policies, stereo should not be
+enabled.
+
+
+NewPhysicalEnvironment
+Syntax:
+
(NewPhysicalEnvironment <instance name>
+[Alias <alias name>])
+
+
+
+PhysicalEnvironmentProperty
+Syntax:
+
(PhysicalEnvironmentProperty <instance name>
+<property name> <property value>)
+
+
+
+InputDevice
+Register an InputDevice implementation instantiated by
+NewDevice. The InputDevice instance name is specified
+by the property value string. If an InputDevice is not registered then
+it will not be scheduled to run.
+
+
+HeadTracker
+Register the Sensor which will be used for head tracking. It must provide 6
+degree of freedom position and orientation reads relative to the tracker base.
+The Sensor instance name is specified by the property value string.
+Its corresponding input device must be registered with the InputDevice
+property.
+
+CoexistenceToTrackerBase
+A 4D matrix which transforms points in coexistence coordinates to tracker base
+coordinates. This defines the position and orientation of coexistence
+coordinates relative to the tracker base. Its default value is the identity
+matrix, so if it is not set then coexistence coordinates will be the same as
+tracker base coordinates. See
+TrackerBaseToImagePlate.
+NOMINAL_SCREEN
. Coexistence coordinates and view platform
+coordinates are then equivalent except for scale. For HMD configurations
+placing the coexistence coordinate system aligned with some nominal
+front-facing user position works well.
+
+
+NewPhysicalBody
+Syntax:
+
(NewPhysicalBody <instance name>
+[Alias <alias name>])
+
+
+
+PhysicalBodyProperty
+Syntax:
+
(PhysicalBodyProperty <instance name> <property name>
+<property value>)
+
+
+
+StereoEyeSeparation
+A number indicating the interpupilary distance in meters. This will set the
+left and right eye positions to offsets of half this distance from the head
+origin along its X axis. The default is 0.066 meters.
+
+LeftEarPosition
+A 3D point which sets the left ear position relative to head coordinates.
+The default is (-0.08, -0.03, 0.09).
+
+
+RightEarPosition
+A 3D point which sets the right ear position relative to head coordinates.
+The default is (0.08, -0.03, 0.09).
+
+
+HeadToHeadTracker
+A 4D matrix which transforms points from head coordinates to the local
+coordinate system of the head tracking sensor. This allows the positions
+of the eyes and ears to be determined from the position and orientation
+of the head tracker. The default is the identity matrix.
+
+
+
+NominalEyeOffsetFromNominalScreen
+A distance in meters used as a calibration parameter for
+ViewAttachPolicy. It does not actually set
+the position of the eyes. The property is ignored if ViewAttachPolicy is
+NOMINAL_SCREEN. The default value is 0.4572 meters.
+
+
+NominalEyeHeightFromGround
+A distance in meters used as a calibration parameter for
+ViewAttachPolicy.
+It does not actually set the position of the eyes. This property is
+ignored if ViewAttachPolicy is not NOMINAL_FEET. The default value is 1.68
+meters.
+
+
+
+NewView
+Syntax:
+
(NewView <instance name>
+[Alias <alias name>])
+
+
+
+ViewProperty
+Syntax:
+(NewView <instance name> <property name>
+<property value>)
+
+
+Screen
+These two properties are equivalent. They include a screen created by
+NewScreen or a window created by
+NewWindow into
+this view. The screen or window name is specified by the property value
+string. Multiple-screen or multiple-window views are created by calling this
+command with each window or screen to be used. If no windows or screens are
+defined for this view then an IllegalArgumentException will be thrown after the
+configuration file has been processed.
+
+
+Window
+PhysicalEnvironment
+Sets the PhysicalEnvironment to be used for this view. The property
+value string specifies the name of a PhysicalEnvironment instance created
+by the NewPhysicalEnvironment command.
+If no PhysicalEnvironment is specified for this view then one with default
+values will be created.
+
+
+PhysicalBody
+Sets the PhysicalBody to be used for this view. The property
+value string specifies the name of a PhysicalBody instance created
+by the NewPhysicalBody command. If
+no PhysicalBody is specified for this view then one with default values
+will be created.
+
+
+ViewPlatform
+The property value string is the name of a view platform defined by a
+previous NewViewPlatform command. This
+specifies that the view should be attached to the given view platform.
+ConfiguredUniverse requires that a view platform be specified for every defined
+view unless only a single view without a view platform is provided; in that
+case a view platform is created by default and the view is attached to that.
+If one or more view platforms are defined then the view attachments must be
+made explicitly.
+
+
+ViewPolicy
+The property value string may be either SCREEN_VIEW
or
+HMD_VIEW
to indicate whether fixed room-mounted screens are being
+used or a head mounted display. The default value is SCREEN_VIEW
.
+
+
+CoexistenceCenteringEnable
+The property value is a boolean string. If true, then the origin of the
+coexistence coordinate system is set to either the middle of the canvas or the
+middle of the screen depending upon whether the WindowMovementPolicy is
+PHYSICAL_WORLD
or VIRTUAL_WORLD
respectively. The X,
+Y, and Z directions of coexistence coordinates will point in the same
+directions as those of the screen's image plate.
+HMD_VIEW
.
+WindowEyepointPolicy
+The string value for this property may be either RELATIVE_TO_SCREEN,
+RELATIVE_TO_COEXISTENCE, RELATIVE_TO_WINDOW
, or
+RELATIVE_TO_FIELD_OF_VIEW
. The normal Java 3D default is
+RELATIVE_TO_FIELD_OF_VIEW
. When using a configuration file the
+default is RELATIVE_TO_COEXISTENCE
if
+CoexistenceCenteringEnable is false,
+otherwise the normal default applies. See the
+setWindowEyepointPolicy View method.
+RELATIVE_TO_SCREEN
and RELATIVE_TO_WINDOW
+policies, the eyepoint is set by using the setLeftManualEyeInImagePlate() and
+setRightManualEyeInImagePlate() methods of Canvas3D. The configuration file
+currently does not provide any mechanism for altering these properties from
+their default values. These default values are (0.142, 0.135, 0.4572) for the
+left eye and (0.208, 0.135, 0.4572) for the right eye.
+WindowMovementPolicy
+
+The string values for these properties may be either
+WindowResizePolicyVIRTUAL_WORLD
+or PHYSICAL_WORLD
. The normal Java 3D default value for both is
+PHYSICAL_WORLD
. When using a configuration file the default
+values are VIRTUAL_WORLD
if
+CoexistenceCenteringEnable is false,
+otherwise the normal defaults apply. See the
+setWindowMovementPolicy and
+setWindowResizePolicy View methods.
+CenterEyeInCoexistence
+A 3D point which specifies the location of the center eye relative to
+coexistence coordinates. See
+CoexistenceToTrackerBase. If stereo
+viewing is enabled, then the left and right eye positions are set to offsets
+from this position using the values specified by the PhysicalBody. This
+property is ignored if head tracking is enabled or if WindowEyepointPolicy is
+not RELATIVE_TO_COEXISTENCE
. The default value is (0.0, 0.0,
+0.4572).
+
+ScreenScalePolicy
+The property value string may be either SCALE_SCREEN_SIZE
+or SCALE_EXPLICIT
and determines the source of the screen
+scale, a factor in the scaling of view platform coordinates to physical
+world coordinates.
+SCALE_SCREEN_SIZE
, then the screen scale is half
+the physical screen width in meters. If WindowResizePolicy is
+PHYSICAL_WORLD
, then this scale is further multiplied by the ratio
+of the window width to the width of the screen (the window scale) to
+produce the scale from view platform coordinates to physical coordinates. This
+allows a virtual world which spans a normalized width of [-1.0 .. 1.0] in view
+platform coordinates to map directly to the physical width of the window or
+screen, depending upon the resize policy.SCALE_EXPLICIT
uses the value of the ScreenScale property as the
+screen scale. It is also further multiplied by the window scale when using the
+PHYSICAL_WORLD
window resize policy to produce the scale from view
+platform coordinates to physical coordinates. Viewing configurations
+incorporating multiple screens should generally set the policy to
+SCALE_EXPLICIT
and choose a screen scale based on the aggregate
+display size, but the default value of SCALE_SCREEN_SIZE
will
+usually work if all the screens are the same size and arranged in a linear
+array.PHYSICAL_WORLD
, the window scale. In the usual
+case the view platform scale is 1.0.
+ScreenScale
+The property value is a number specifying the explicit screen scale
+factor. It is only used if ScreenScalePolicy is SCALE_EXPLICIT
;
+otherwise, the screen scale is half the physical width of the screen in meters.
+The default value for this property is 1.0.
+
+
+BackClipPolicy
+The string values of these properties may be either
+FrontClipPolicyPHYSICAL_EYE,
+PHYSICAL_SCREEN, VIRTUAL_EYE
, or VIRTUAL_SCREEN
. The
+default policies are PHYSICAL_EYE
. See the
+setFrontClipPolicy and
+setBackClipPolicy View methods.
+
+
+FrontClipDistance
+These property values are numbers. The defaults are 0.1 and 10.0
+respectively. See the
+setFrontClipDistance and
+setBackClipDistance View methods.
+BackClipDistancePHYSICAL_EYE
the clip distances
+are measured relative to the eye in physical units, so the clip distances
+specified must be scaled to virtual world units in order to determine the
+distances in the virtual world where they would effectively be applied. As
+described in the discussion of
+ScreenScalePolicy above, the scale from
+virtual units to physical units is the product of the view platform scale
+(usually 1.0), the screen scale, and the window scale (if the window resize
+policy is PHYSICAL_WORLD
), so normally the scale from physical
+units to virtual units would be the inverse of that product.PHYSICAL_EYE
or PHYSICAL_SCREEN
clip policies are
+used with the PHYSICAL_WORLD
window resize policy. The locations
+of the clip planes in physical units are not actually set to the physical
+distances as specified, but are in fact scaled by the window scale.
+This means that when determining where the specified physical clip distances
+are in virtual units the scaling to be used is the inverse of the product of
+the screen scale and view platform scale only.PHYSICAL_WORLD
resize policy. It was implemented in this
+manner to prevent objects in the virtual world from getting clipped
+unexpectedly when the virtual world scaling changed as the result of a window
+resize. The quirk can be avoided by using the VIRTUAL_EYE
or
+VIRTUAL_SCREEN
clip policies or by using the
+VIRTUAL_WORLD
resize policy, but in most cases the effect is
+benign and doesn't lead to unexpected results.
+FieldOfView
+This number is the view's horizontal field of view in radians. The default
+value is PI/4. This value is ignored if WindowEyepointPolicy is not
+RELATIVE_TO_FIELD_OF_VIEW
or if head tracking is enabled. The
+eyepoint for each canvas associated with the view is set such that it is
+centered in X and Y, with the Z value at the appropriate distance to match the
+specified field of view across the width of the canvas.
+
+
+StereoEnable
+Enable or disable stereo viewing for this view according to the boolean value
+specified by the property value string. The default value is false.
+
+TrackingEnable
+Enable or disable head tracking for this view according to the boolean value
+specified by the property value string. The default value is false.
+RELATIVE_TO_COEXISTENCE
with the eyepoint in
+coexistence coordinates computed from reading the head tracking sensor.
+Tracking must be made available by registering an input device and a head
+tracking sensor in PhysicalEnvironment.
+AntialiasingEnable
+Enable or disable scene antialiasing for this view according to the boolean
+value specified by the property value string. The default value is
+false.
+
+
+
+NewViewPlatform
+Syntax:
+
(NewViewPlatform <instance name>
+[Alias <alias name>])
+
+
+
+ViewPlatformProperty
+Syntax:
+
(ViewPlatformProperty <instance name> <property name>
+<property value>)
+
+
+
+NominalViewingTransform
+The property value is a boolean string indicating whether or not
+the view platform should be backed up in Z to allow objects at the origin to be
+viewed. This only has effect if the ViewAttachPolicy is
+NOMINAL_HEAD
. The default value is false. See the
+setNominalViewingTransform
+method of ViewingPlatform.
+
+
+InitialViewingTransform
+Sets the initial transform of the view platform to the 4D matrix
+specified by property value. The default value is identity.
+
+
+AllowPolicyRead
+The property value is a boolean string indicating whether or not reading
+the ViewAttachPolicy is allowed. The default value is false.
+
+
+AllowLocalToVworldRead
+The property value is a boolean string indicating whether or not reading
+the view platform's localToVworld transform is allowed. The default value is
+false.
+
+
+ViewPlatformBehavior
+Attaches a ViewPlatformBehavior instantiated by
+NewViewPlatformBehavior.
+The property value string is the name bound to that instance.
+
+
+ViewAttachPolicy
+The property value string can be one of NOMINAL_SCREEN,
+NOMINAL_HEAD,
or NOMINAL_FEET
. This establishes the point
+in coexistence coordinates where the origin of view platform coordinates is
+attached. The basis vectors of view platform coordinates are always aligned
+with those of coexistence coordinates.
+NOMINAL_SCREEN
, the ViewPlatform origin
+is set directly to the origin of coexistence, so that ViewPlatform coordinates
+and coexistence coordinates are identical except for scale.NOMINAL_HEAD
, the ViewPlatform origin is
+set to the origin of the nominal head, the center eye halfway between the left
+and right eyes. The nominal head origin is on the Z axis of coexistence
+coordinates at some offset from the coexistence origin. If the
+WindowEyepointPolicy is RELATIVE_TO_FIELD_OF_VIEW
, then this is
+the positive Z offset producing the required field of view relative to the
+width of the canvas at the coexistence origin, tracking the Z offset of the
+eyepoint defined by that policy; otherwise, the Z offset is the
+NominalEyeOffsetFromNominalScreen property of PhysicalBody and is decoupled
+from the actual eyepoint offset.NOMINAL_FEET
, the ViewPlatform origin is
+at the ground plane, which is NominalEyeHeightFromGround meters along -Y from
+the origin of the nominal head. NominalEyeHeightFromGround is a property of
+PhysicalBody.NOMINAL_HEAD
. When
+using a configuration file, the default is NOMINAL_HEAD
only if
+every view attached to the view platform has a WindowEyepointPolicy of
+RELATIVE_TO_FIELD_OF_VIEW
; otherwise, the default is
+NOMINAL_SCREEN
. If the view policy is HMD_VIEW
, then
+the ViewAttachPolicy is ignored and is always effectively
+NOMINAL_SCREEN
.
+
+
+NewViewPlatformBehavior
+Syntax:
+
(NewViewPlatformBehavior <instance name> <class name>
+[Alias <alias name>])
+
+
+
+ViewPlatformBehaviorProperty
+Syntax:
+
(ViewPlatformBehaviorProperty <instance name>
+<property name> <property value>)
+
+
+
+SchedulingBounds
+The scheduling bounds for this behavior. Use the
+BoundingSphere built-in command to set this
+property. The default is whatever the application or the concrete subclass
+sets.
+
+
+SchedulingInterval
+A number indicating the scheduling interval for this behavior. See the
+setSchedulingInterval
+method of Behavior.
+
+
+HomeTransform
+See the ViewPlatformBehavior method
+setHomeTransform.
+The property value must be a 4D matrix.
+
+
+
+NewObject
+Syntax:
+
(NewObject <instance name> <class name>
+[Alias <alias name>])
+
+
+
+ObjectProperty
+Syntax:
+
(ObjectProperty <instance name> <method name> <arg0>
+... <argn>)
+
+
+
+JavaProperty
+Syntax:
+
(JavaProperty <propertyName> [Default]
+<propertyValue>)
+
+
+
+Include
+Syntax:
+
(Include <URL string>)
+
+
+
+Alias
+Syntax:
+
(<baseName>Alias <aliasName>
+<originalName>)
+
+
+
+
+
+
+
+
+Built-In Command Details
+
+Subtract (translate) the target origin first if it can be conveniently measured
+or computed relative to the source origin along the source X, Y, and Z basis
+vectors. Then rotate with Euler angles that move the target basis vectors to
+their corresponding source basis vectors.
+
+
+
+
+Translate
+Syntax:
+
(Translate <x offset> <y offset> <z offset>)
+
+
+
+Rotate
+Syntax:
+
(Rotate <x degrees> <y degrees> <z degrees>)
+
+
+
+Concatenate
+Syntax:
+
(Concatenate <m1> <m2>)
+
+
+
+RotateTranslate
+Syntax:
+
(RotateTranslate <m1> <m2>)
+
+
+
+TranslateRotate
+Syntax:
+
(TranslateRotate <m1> <m2>)
+
+
+
+BoundingSphere
+Syntax:
+
(BoundingSphere <center> <radius>)
+
+
+
+Canvas3D
+Syntax:
+
(Canvas3D <screen or window name>)
+
+(ViewProperty <view> Screen <screenName>)
+
+view is the name of a view created with the NewView command. The
+argument to the Canvas3D built-in must be a screenName or
+windowName parameter from one of the above commands.
+(ViewProperty <view> Window <windowName>)
+
+
+
+Sensor
+Syntax:
+
(Sensor <sensor name>)
+
+
+
+Device
+Syntax:
+
(Device <device name>)
+
+
+
+PhysicalBody
+Syntax:
+
(PhysicalBody <body name>)
+
+
+
+PhysicalEnvironment
+Syntax:
+
(PhysicalEnvironment <environment name>)
+
+
+
+View
+Syntax:
+
(View <view name>)
+
+
+
+ViewPlatform
+Syntax:
+
(ViewPlatform <view platform name>)
+
+
+
+ViewPlatformBehavior
+Syntax:
+
(ViewPlatformBehavior <behavior name>)
+
+
+
+Object
+Syntax:
+
(Object <generic object name>)
+
+(NewObject <instance name> <class name>
+[Alias <alias name>])
+
+
+
+
+ConfigContainer
+Syntax:
+
(ConfigContainer)
+
+
+
+
+
+
+
+
+Command Index
+
+
+
+
+
+
+Command
+Type
+
+
+Alias
+top-level
+
+
+BoundingSphere
+built-in
+
+
+Canvas3D
+built-in
+
+
+Concatenate
+built-in
+
+
+ConfigContainer
+built-in
+
+
+Device
+built-in
+
+
+DeviceProperty
+top-level
+
+
+Include
+top-level
+
+
+JavaProperty
+top-level
+
+
+NewDevice
+top-level
+
+
+NewObject
+top-level
+
+
+NewPhysicalBody
+top-level
+
+
+NewPhysicalEnvironment
+top-level
+
+
+NewScreen
+top-level
+
+
+NewSensor
+top-level
+
+
+NewView
+top-level
+
+
+NewViewPlatform
+top-level
+
+
+NewViewPlatformBehavior
+top-level
+
+
+NewWindow
+top-level
+
+
+Object
+built-in
+
+
+ObjectProperty
+top-level
+
+
+PhysicalBody
+built-in
+
+
+PhysicalBodyProperty
+top-level
+
+
+PhysicalEnvironment
+built-in
+
+
+PhysicalEnvironmentProperty
+top-level
+
+
+Rotate
+built-in
+
+
+RotateTranslate
+built-in
+
+
+ScreenProperty
+top-level
+
+
+Sensor
+built-in
+
+
+SensorProperty
+top-level
+
+
+Translate
+built-in
+
+
+TranslateRotate
+built-in
+
+
+View
+built-in
+
+
+ViewPlatform
+built-in
+
+
+ViewPlatformBehavior
+built-in
+
+
+ViewProperty
+top-level
+
+
+ViewPlatformProperty
+top-level
+
+
+ViewPlatformBehaviorProperty
+top-level
+
+
+WindowProperty
+top-level
+
+
+
+
+
+
+
+
+Property Index
+
+
+
+/*
+ ************************************************************************
+ *
+ * Java 3D configuration file for single fullscreen desktop configuration.
+ * A view platform behavior is created and configured here as well.
+ *
+ ************************************************************************
+ */
+
+(NewScreen center 0)
+(ScreenProperty center WindowSize NoBorderFullScreen)
+
+(NewView view0)
+(ViewProperty view0 Screen center)
+
+// Create a view platform behavior. Here we use OrbitBehavior, although any
+// concrete subclass of the abstract ViewPlatformBehavior with a parameterless
+// constructor could be used. The logical name to assign to this behavior is
+// specified by the 2nd argument to the NewViewPlatformBehavior command, while
+// the 3rd argument is the name of the ViewPlatformBehavior subclass. It is
+// instantiated through introspection.
+//
+(NewViewPlatformBehavior vpb org.jogamp.java3d.utils.behaviors.vp.OrbitBehavior)
+
+// Set the scheduling bounds to be a BoundingSphere with its center at
+// (0.0 0.0 0.0) and an infinite radius.
+//
+(ViewPlatformBehaviorProperty vpb SchedulingBounds
+ (BoundingSphere (0.0 0.0 0.0) infinite))
+
+// Set properties specific to OrbitBehavior. All arguments following the
+// method name are wrapped and passed to the specified method as an array of
+// Objects. Strings "true" and "false" get turned into Boolean, and number
+// strings get turned into Double. Constructs such as (0.0 1.0 2.0) and
+// ((0.0 1.0 2.0 0.5) (3.0 4.0 5.0 1.0) (6.0 7.0 8.0 0.0)) get converted to
+// Point3d and Matrix4d respectively. Note that last row of a Matrix4d doesn't
+// need to be specified; it is implicitly (0.0 0.0 0.0 1.0).
+//
+// The REVERSE_ALL flags are usually passed to the OrbitBehavior constructor.
+// Since it is being instantiated with its parameterless constructor the
+// reverse flags are set here explicitly.
+//
+(ViewPlatformBehaviorProperty vpb ReverseTranslate true)
+(ViewPlatformBehaviorProperty vpb ReverseRotate true)
+(ViewPlatformBehaviorProperty vpb ReverseZoom true)
+
+// Create a new view platform and set the view platform behavior.
+//
+(NewViewPlatform vp)
+(ViewPlatformProperty vp ViewPlatformBehavior vpb)
+
+// Attach the view to the view platform.
+(ViewProperty view0 ViewPlatform vp)
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1-stereo.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1-stereo.html
new file mode 100644
index 0000000..0a91eed
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1-stereo.html
@@ -0,0 +1,90 @@
+
+
+
+
+
+/*
+ ************************************************************************
+ *
+ * Java 3D configuration file for single fullscreen stereo desktop
+ * configuration with no head tracking.
+ *
+ ************************************************************************
+ */
+
+(NewScreen center 0)
+(ScreenProperty center WindowSize NoBorderFullScreen)
+
+// Define the physical body.
+//
+// The head origin is halfway between the eyes, with X extending to the right,
+// Y up, and positive Z extending into the skull.
+//
+(NewPhysicalBody SiteUser)
+
+// Set the interpupilary distance. This sets the LeftEyePosition and
+// RightEyePosition to offsets of half this distance along both directions of
+// the X axis.
+//
+(PhysicalBodyProperty SiteUser StereoEyeSeparation 0.066)
+
+// Create a view using the defined screen and physical body.
+//
+(NewView view0)
+(ViewProperty view0 Screen center)
+(ViewProperty view0 PhysicalBody SiteUser)
+
+// Enable stereo viewing.
+//
+(ViewProperty view0 StereoEnable true)
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1-vr.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1-vr.html
new file mode 100644
index 0000000..a2e07ac
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1-vr.html
@@ -0,0 +1,173 @@
+
+
+
+
+
+/*
+ ************************************************************************
+ *
+ * Java 3D configuration file for a single screen stereo desktop display
+ * using a head tracker and 6DOF mouse.
+ *
+ ************************************************************************
+ */
+
+// Create a screen object and give it a logical name.
+(NewScreen center 0)
+
+// Set the actual available image area.
+(ScreenProperty center PhysicalScreenWidth 0.398)
+(ScreenProperty center PhysicalScreenHeight 0.282)
+(ScreenProperty center WindowSize NoBorderFullScreen)
+
+// Set the TrackerBaseToImagePlate transform for this screen.
+(ScreenProperty center TrackerBaseToImagePlate
+ (RotateTranslate (Rotate 50.000 0.000 0.000)
+ (Translate 0.199 0.376 0.000)))
+
+// Configure the head tracker.
+(NewDevice tracker1 org.jogamp.java3d.input.LogitechTracker)
+(DeviceProperty tracker1 SerialPort "/dev/ttya")
+(DeviceProperty tracker1 ReceiverBaseline 0.1450)
+(DeviceProperty tracker1 ReceiverLeftLeg 0.0875)
+(DeviceProperty tracker1 ReceiverHeight 0.0470)
+(DeviceProperty tracker1 ReceiverTopOffset 0.0000)
+(DeviceProperty tracker1 RealtimeSerialBuffer true)
+
+// Configure the 6DOF wand.
+(NewDevice tracker2 org.jogamp.java3d.input.LogitechTracker)
+(DeviceProperty tracker2 SerialPort "/dev/ttyb")
+(DeviceProperty tracker2 ReceiverBaseline 0.0700)
+(DeviceProperty tracker2 ReceiverLeftLeg 0.0625)
+(DeviceProperty tracker2 ReceiverHeight 0.0510)
+(DeviceProperty tracker2 ReceiverTopOffset 0.0000)
+(DeviceProperty tracker2 RealtimeSerialBuffer true)
+
+// Make the tracker2 device a slave of the tracker1 device.
+(DeviceProperty tracker1 Slave (Device tracker2))
+
+// Create a 2D mouse valuator.
+(NewDevice mouse org.jogamp.java3d.input.Mouse2DValuator)
+(DeviceProperty mouse Components (Canvas3D center))
+
+// Create logical names for the available sensors.
+(NewSensor head tracker1 0)
+(NewSensor mouse6d tracker2 0)
+(NewSensor mouse2d mouse 0)
+
+// Set the 6DOF mouse sensor hotspot in the local sensor coordinate system.
+(SensorProperty mouse6d Hotspot (0.00 0.00 -0.10))
+
+// Create a physical environment.
+(NewPhysicalEnvironment SampleSite)
+
+// Register the input devices and head tracker sensor.
+(PhysicalEnvironmentProperty SampleSite InputDevice tracker1)
+(PhysicalEnvironmentProperty SampleSite InputDevice tracker2)
+(PhysicalEnvironmentProperty SampleSite InputDevice mouse)
+(PhysicalEnvironmentProperty SampleSite HeadTracker head)
+
+// Define coexistence coordinates.
+(PhysicalEnvironmentProperty SampleSite CoexistenceToTrackerBase
+ (TranslateRotate (Translate 0.0 -0.235 0.0)
+ (Rotate -50.0 0.0 0.0)))
+
+// Define the physical body.
+(NewPhysicalBody SiteUser)
+
+// Set the interpupilary distance.
+(PhysicalBodyProperty SiteUser StereoEyeSeparation 0.066)
+
+// Define the head location relative to the tracker mounted on the head.
+(PhysicalBodyProperty SiteUser HeadToHeadTracker ((1.0 0.0 0.0 0.000)
+ (0.0 1.0 0.0 0.020)
+ (0.0 0.0 1.0 0.018)))
+
+// Create a view platform behavior.
+//
+(NewViewPlatformBehavior vpb org.jogamp.java3d.utils.behaviors.vp.WandViewBehavior)
+
+(ViewPlatformBehaviorProperty vpb Sensor6D (Sensor mouse6d))
+(ViewPlatformBehaviorProperty vpb Sensor2D (Sensor mouse2d))
+
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 1 GrabView)
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 2 TranslateForward)
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 0 TranslateBackward)
+
+(ViewPlatformBehaviorProperty vpb RotationCoords ViewPlatform)
+(ViewPlatformBehaviorProperty vpb ButtonAction2D 1 Translation)
+(ViewPlatformBehaviorProperty vpb ButtonAction2D 2 Scale)
+
+(ViewPlatformBehaviorProperty vpb EchoType Beam)
+(ViewPlatformBehaviorProperty vpb EchoSize 0.004)
+
+(ViewPlatformBehaviorProperty vpb EchoColor 1.0 0.7 0.0)
+(ViewPlatformBehaviorProperty vpb EchoTransparency 0.4)
+
+// Create a new view platform and set the view platform behavior.
+//
+(NewViewPlatform vp)
+(ViewPlatformProperty vp ViewPlatformBehavior vpb)
+
+// Create a view.
+//
+(NewView view0)
+(ViewProperty view0 Screen center)
+(ViewProperty view0 PhysicalEnvironment SampleSite)
+(ViewProperty view0 PhysicalBody SiteUser)
+(ViewProperty view0 ViewPlatform vp)
+
+// Enable stereo viewing and head tracking.
+(ViewProperty view0 StereoEnable true)
+(ViewProperty view0 TrackingEnable True)
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1-window.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1-window.html
new file mode 100644
index 0000000..3ff401f
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1-window.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+/*
+ ************************************************************************
+ *
+ * Java 3D configuration file for a conventional single screen, windowed
+ * desktop configuration.
+ *
+ ************************************************************************
+ */
+
+(NewWindow window1 0)
+(WindowProperty window1 WindowSize (700.0 700.0))
+
+(NewView view1)
+(ViewProperty view1 Window window1)
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1.html
new file mode 100644
index 0000000..1f7f17b
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x1.html
@@ -0,0 +1,69 @@
+
+
+
+
+
+/*
+ ************************************************************************
+ *
+ * Java 3D configuration file for a single fullscreen desktop configuration.
+ *
+ ************************************************************************
+ */
+
+(NewWindow big 0)
+(WindowProperty big WindowSize NoBorderFullScreen)
+
+(NewView view0)
+(ViewProperty view0 Window big)
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x2-flat.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x2-flat.html
new file mode 100644
index 0000000..9391af2
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x2-flat.html
@@ -0,0 +1,152 @@
+
+
+
+
+
+/*
+ ************************************************************************
+ *
+ * Java 3D configuration file for dual-screen (flat) desktop configuration
+ * with no head tracking.
+ *
+ ************************************************************************
+ */
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+//
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+//
+(NewScreen left 0)
+(NewScreen right 1)
+
+// Set the screen dimensions.
+//
+(ScreenProperty left PhysicalScreenWidth 0.360)
+(ScreenProperty left PhysicalScreenHeight 0.288)
+
+(ScreenProperty right PhysicalScreenWidth 0.360)
+(ScreenProperty right PhysicalScreenHeight 0.288)
+
+// Specify full screen windows.
+//
+(ScreenProperty left WindowSize NoBorderFullScreen)
+(ScreenProperty right WindowSize NoBorderFullScreen)
+
+// Set the TrackerBaseToImagePlate transforms for these screens. This
+// transforms points in tracker base coordinates to each screen's image plate
+// coordinates, where the origin of the image plate is defined to be the lower
+// left corner of the screen with X increasing to the right, Y increasing to
+// the top, and Z increasing away from the screen.
+//
+// Without head or sensor tracking the tracker base is still needed as a fixed
+// frame of reference for describing the orientation and position of each
+// screen to the others. The coexistence to tracker base transform is set to
+// identity by default, so the tracker base origin and orientation will also
+// set the origin and orientation of coexistence coordinates in the physical
+// world.
+//
+// The tracker base and center of coexistence is set here to the middle of the
+// edge shared by the two screens.
+//
+(ScreenProperty left TrackerBaseToImagePlate
+ (Translate 0.360 0.144 0.0))
+(ScreenProperty right TrackerBaseToImagePlate
+ (Translate 0.000 0.144 0.0))
+
+// Sometimes it is desirable to include the bevels in between the monitors in
+// the TrackerBaseToImagePlate transforms, so that the abutting bevels obscure
+// the view of the virtual world instead of stretching it out between the
+// monitors. For a bevel width of 4.5 cm on each monitor, the above commands
+// would become the following:
+//
+// (ScreenProperty left TrackerBaseToImagePlate
+// (Translate 0.405 0.144 0.0))
+// (ScreenProperty right TrackerBaseToImagePlate
+// (Translate -0.045 0.144 0.0))
+//
+// Conversely, a similar technique may be used to include overlap between the
+// screens. This is useful for projection systems which use edge blending
+// to provide seamless integration between screens.
+
+
+// Create a view using the defined screens.
+//
+(NewView view0)
+(ViewProperty view0 Screen left)
+(ViewProperty view0 Screen right)
+
+// Set the eyepoint relative to coexistence coordinates. Here it is set 45cm
+// toward the user along Z, extending out from the midpoint of the edge shared
+// by the two screens. This will create the appropriate skewed projection
+// frustums for each image plate.
+//
+// If a planar display surface is all that is required, the same effect could
+// be achieved in a virtual screen enviroment such as Xinerama by simply
+// creating a canvas that spans both screens. In some display environments the
+// use of a canvas that spans multiple physical screens may cause significant
+// performance degradation, however.
+//
+// See j3d1x2-rot30 for an example of a non-planar configuration that cannot be
+// achieved through a single canvas spanning both screens.
+//
+(ViewProperty view0 CenterEyeInCoexistence (0.0 0.0 0.45))
+
+(NewViewPlatform vp)
+(ViewPlatformProperty vp AllowPolicyRead true)
+(ViewPlatformProperty vp AllowLocalToVworldRead true)
+
+(ViewProperty view0 ViewPlatform vp)
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x2-rot30.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x2-rot30.html
new file mode 100644
index 0000000..ca5fdd6
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x2-rot30.html
@@ -0,0 +1,111 @@
+
+
+
+
+
+/*
+ ************************************************************************
+ *
+ * Java 3D configuration file for a dual-screen desktop configuration
+ * with each screen rotated toward the other by 30 degrees about Y from
+ * planar. The inside angle between them is 120 degrees.
+ *
+ ************************************************************************
+ */
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+//
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+//
+(NewScreen left 0)
+(NewScreen right 1)
+
+// Set the available image areas for full screens.
+//
+(ScreenProperty left PhysicalScreenWidth 0.360)
+(ScreenProperty left PhysicalScreenHeight 0.288)
+
+(ScreenProperty right PhysicalScreenWidth 0.360)
+(ScreenProperty right PhysicalScreenHeight 0.288)
+
+// Specify full screen windows.
+//
+(ScreenProperty left WindowSize NoBorderFullScreen)
+(ScreenProperty right WindowSize NoBorderFullScreen)
+
+// Set the TrackerBaseToImagePlate transforms for these screens.
+//
+// The tracker base is set here to the middle of the edge shared by the two
+// screens. Each screen is rotated 30 degrees toward the other about the
+// tracker base +Y axis, so that the tracker base +Z is centered between the
+// two screens.
+//
+(ScreenProperty left TrackerBaseToImagePlate
+ (RotateTranslate (Rotate 0.000 -30.000 0.0)
+ (Translate 0.360 0.144 0.0)))
+
+(ScreenProperty right TrackerBaseToImagePlate
+ (RotateTranslate (Rotate 0.000 30.000 0.0)
+ (Translate 0.000 0.144 0.0)))
+
+
+// Create a view using the defined screens.
+//
+(NewView view0)
+(ViewProperty view0 Screen left)
+(ViewProperty view0 Screen right)
+(ViewProperty view0 CenterEyeInCoexistence (0.0 0.0 0.45))
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x3-cave-vr.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x3-cave-vr.html
new file mode 100644
index 0000000..7ad30c4
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x3-cave-vr.html
@@ -0,0 +1,243 @@
+
+
+
+
+
+/*
+ ************************************************************************
+ *
+ * Java 3D configuration file for a cave environment with head tracking and
+ * stereo viewing. This cave consists of 3 projectors with 3 screens to the
+ * left, front, and right of the user, all at 90 degrees to each other.
+ *
+ * The projectors in Sun's VirtualPortal sample site are actually turned
+ * on their sides to get more height. Screen 0 is rotated 90 degrees
+ * counter-clockwise, while screens 1 and 2 are rotated 90 degrees
+ * clockwise.
+ *
+ ************************************************************************
+ */
+
+// Configure the head tracker.
+//
+(NewDevice tracker1 org.jogamp.java3d.input.LogitechTracker)
+(DeviceProperty tracker1 SerialPort "/dev/ttya") // Unix paths need quoting.
+(DeviceProperty tracker1 TransmitterBaseline 0.4600)
+(DeviceProperty tracker1 TransmitterLeftLeg 0.4400)
+(DeviceProperty tracker1 TransmitterCalibrationDistance 0.4120)
+
+// Configure an InputDevice to use for a 6 degree of freedom wand.
+//
+(NewDevice tracker2 org.jogamp.java3d.input.LogitechTracker)
+(DeviceProperty tracker2 SerialPort "/dev/ttyb")
+(DeviceProperty tracker2 ReceiverBaseline 0.0700)
+(DeviceProperty tracker2 ReceiverLeftLeg 0.0625)
+(DeviceProperty tracker2 ReceiverHeight 0.0510)
+(DeviceProperty tracker2 ReceiverTopOffset 0.0000)
+
+// Make the tracker2 device a slave of the tracker1 device.
+(DeviceProperty tracker1 Slave (Device tracker2))
+
+// Create logical names for the head tracker and wand sensors. The last
+// argument is the sensor's index in the input device.
+//
+(NewSensor head tracker1 0)
+(NewSensor sensor6d tracker2 0)
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+//
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+//
+(NewScreen left 0)
+(NewScreen center 1)
+(NewScreen right 2)
+
+
+// Set the available image areas as well as their positition and orientation
+// relative to the tracker base. From the orientation of a user standing
+// within this VirtualPortal site and facing the center screen, the tracker
+// base is along the vertical midline of the screen, 0.248 meters down from
+// the top edge, and 1.340 meters in front of it. The tracker base is
+// oriented so that its +X axis points to the left, its +Y axis points toward
+// the screen, and its +Z axis points toward the floor.
+//
+(ScreenProperty left PhysicalScreenWidth 2.480)
+(ScreenProperty left PhysicalScreenHeight 1.705)
+(ScreenProperty left WindowSize NoBorderFullScreen)
+(ScreenProperty left TrackerBaseToImagePlate
+ (( 0.0 0.0 -1.0 2.230)
+ ( 0.0 -1.0 0.0 1.340)
+ (-1.0 0.0 0.0 0.885)))
+
+(ScreenProperty center PhysicalScreenWidth 2.485)
+(ScreenProperty center PhysicalScreenHeight 1.745)
+(ScreenProperty center WindowSize NoBorderFullScreen)
+(ScreenProperty center TrackerBaseToImagePlate
+ (( 0.0 0.0 1.0 0.248)
+ (-1.0 0.0 0.0 0.885)
+ ( 0.0 -1.0 0.0 1.340)))
+
+(ScreenProperty right PhysicalScreenWidth 2.480)
+(ScreenProperty right PhysicalScreenHeight 1.775)
+(ScreenProperty right WindowSize NoBorderFullScreen)
+(ScreenProperty right TrackerBaseToImagePlate
+ (( 0.0 0.0 1.0 0.2488)
+ ( 0.0 -1.0 0.0 1.340)
+ ( 1.0 0.0 0.0 0.860)))
+
+// Create a physical environment. This contains the available input devices,
+// audio devices, and sensors, and defines the coexistence coordinate system
+// for mapping between the virtual and physical worlds.
+//
+(NewPhysicalEnvironment VirtualPortal)
+
+// Register the input device defined in this file and the sensor which will
+// drive head tracking.
+//
+(PhysicalEnvironmentProperty VirtualPortal InputDevice tracker1)
+(PhysicalEnvironmentProperty VirtualPortal InputDevice tracker2)
+(PhysicalEnvironmentProperty VirtualPortal HeadTracker head)
+
+// Set the location of the center of coexistence relative to the tracker base.
+// Here it set to the center of the center screen. The default view attach
+// policy of NOMINAL_SCREEN used by ConfiguredUniverse will place the origin of
+// the view platform in coexistence coordinates at the center of coexistence.
+//
+(PhysicalEnvironmentProperty VirtualPortal
+ CoexistenceToTrackerBase
+ ((-1.0 0.0 0.0 0.000)
+ ( 0.0 0.0 -1.0 1.340)
+ ( 0.0 -1.0 0.0 0.994)))
+
+// Define the physical body. The head origin is halfway between the eyes, with
+// X extending to the right, Y up, and positive Z extending into the skull.
+//
+(NewPhysicalBody LabRat)
+(PhysicalBodyProperty LabRat StereoEyeSeparation .07)
+
+// Define the position and orientation of the head relative to the tracker
+// mounted on the head.
+//
+(PhysicalBodyProperty LabRat HeadToHeadTracker
+ ((-1.0 0.0 0.0 0.00)
+ ( 0.0 0.0 -1.0 0.05)
+ ( 0.0 -1.0 0.0 0.11)))
+
+// Create a view platform behavior for the 6DOF sensor.
+//
+(NewViewPlatformBehavior vpb org.jogamp.java3d.utils.behaviors.vp.WandViewBehavior)
+
+(ViewPlatformBehaviorProperty vpb Sensor6D sensor6d)
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 2 GrabView)
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 1 TranslateForward)
+(ViewPlatformBehaviorProperty vpb ButtonAction6D 0 TranslateBackward)
+
+// Default normal translation speed is 0.1 physical meters per second.
+(ViewPlatformBehaviorProperty vpb TranslationSpeed
+ 1.0 PhysicalMeters PerSecond)
+
+// Default rotation coordinates are Sensor.
+(ViewPlatformBehaviorProperty vpb RotationCoords Head)
+
+// Nominal sensor transform for modified joystick RedBarron
+(SensorProperty sensor6d Hotspot (0.00 0.6 0.00))
+(ViewPlatformBehaviorProperty vpb NominalSensorRotation
+ ((-1.0 0.0 0.0)
+ ( 0.0 0.0 -1.0)
+ ( 0.0 -1.0 0.0)))
+
+// Default 6DOF sensor echo is Gnomon
+(ViewPlatformBehaviorProperty vpb EchoSize 0.015)
+(ViewPlatformBehaviorProperty vpb EchoType Beam)
+
+// Default 6DOF sensor echo color is white
+(ViewPlatformBehaviorProperty vpb EchoColor 1.0 0.7 0.0)
+
+// Default 6DOF sensor transparency is 0.0 (opaque)
+(ViewPlatformBehaviorProperty vpb EchoTransparency 0.4)
+
+// Create a new view platform and set the view platform behavior.
+//
+(NewViewPlatform vp)
+(ViewPlatformProperty vp ViewPlatformBehavior vpb)
+
+// Now define the view.
+//
+(NewView view0)
+(ViewProperty view0 Screen left)
+(ViewProperty view0 Screen center)
+(ViewProperty view0 Screen right)
+(ViewProperty view0 PhysicalBody LabRat)
+(ViewProperty view0 PhysicalEnvironment VirtualPortal)
+(ViewProperty view0 ViewPlatform vp)
+
+// Set the screen scale. This is scale factor from virtual to physical
+// coordinates.
+//
+(ViewProperty view0 ScreenScalePolicy SCALE_SCREEN_SIZE)
+
+// Alternative for explict scaling.
+//
+//(ViewProperty view0 ScreenScalePolicy SCALE_EXPLICIT)
+//(ViewProperty view0 ScreenScale 5.00)
+
+// Enable stereo viewing. Enable head tracking to get the position of the eyes
+// with respect to coexistence. Boolean values may be specified as either
+// true, True, false, or False.
+//
+(ViewProperty view0 StereoEnable true)
+(ViewProperty view0 TrackingEnable True)
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x3-cave.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x3-cave.html
new file mode 100644
index 0000000..9b0298b
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x3-cave.html
@@ -0,0 +1,156 @@
+
+
+
+
+
+/*
+ ************************************************************************
+ *
+ * Java 3D configuration file for a cave environment. This cave
+ * consists of 3 projectors with 3 screens to the left, front, and right
+ * of the user, all at 90 degrees to each other.
+ *
+ * The projectors in the VirtualPortal sample site are actually turned
+ * on their sides to get more height. Screen 0 is rotated 90 degrees
+ * counter-clockwise, while screens 1 and 2 are rotated 90 degrees
+ * clockwise.
+ *
+ ************************************************************************
+ */
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+//
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+//
+(NewScreen left 0)
+(NewScreen center 1)
+(NewScreen right 2)
+
+
+// Set the available image areas as well as their positition and orientation
+// relative to the tracker base. Although this config file doesn't enable
+// head tracking, the tracker base is still needed as a point of reference to
+// describe the position and orientation of the screens relative to the
+// environment.
+//
+// From the orientation of a user standing within this VirtualPortal site and
+// facing the center screen, the tracker base is along the vertical midline of
+// the screen, 0.248 meters down from the top edge, and 1.340 meters in front
+// of it. The tracker base is oriented so that its +X axis points to the left,
+// its +Y axis points toward the screen, and its +Z axis points toward the
+// floor.
+//
+(ScreenProperty left PhysicalScreenWidth 2.480)
+(ScreenProperty left PhysicalScreenHeight 1.705)
+(ScreenProperty left WindowSize NoBorderFullScreen)
+(ScreenProperty left TrackerBaseToImagePlate
+ (( 0.0 0.0 -1.0 2.230)
+ ( 0.0 -1.0 0.0 1.340)
+ (-1.0 0.0 0.0 0.885)))
+
+(ScreenProperty center PhysicalScreenWidth 2.485)
+(ScreenProperty center PhysicalScreenHeight 1.745)
+(ScreenProperty center WindowSize NoBorderFullScreen)
+(ScreenProperty center TrackerBaseToImagePlate
+ (( 0.0 0.0 1.0 0.248)
+ (-1.0 0.0 0.0 0.885)
+ ( 0.0 -1.0 0.0 1.340)))
+
+(ScreenProperty right PhysicalScreenWidth 2.480)
+(ScreenProperty right PhysicalScreenHeight 1.775)
+(ScreenProperty right WindowSize NoBorderFullScreen)
+(ScreenProperty right TrackerBaseToImagePlate
+ (( 0.0 0.0 1.0 0.2488)
+ ( 0.0 -1.0 0.0 1.340)
+ ( 1.0 0.0 0.0 0.860)))
+
+// Set the location of the center of coexistence relative to the tracker base.
+// Here it set to the center of the center screen. This config file will set
+// the location of the user's eyes relative to this point. The default view
+// attach policy of NOMINAL_SCREEN used by ConfiguredUniverse will place the
+// origin of the view platform in coexistence coordinates at the center of
+// coexistence.
+//
+(NewPhysicalEnvironment VirtualPortal)
+(PhysicalEnvironmentProperty VirtualPortal
+ CoexistenceToTrackerBase
+ ((-1.0 0.0 0.0 0.000)
+ ( 0.0 0.0 -1.0 1.340)
+ ( 0.0 -1.0 0.0 0.994)))
+
+// Now define the view.
+//
+(NewView view0)
+(ViewProperty view0 Screen left)
+(ViewProperty view0 Screen center)
+(ViewProperty view0 Screen right)
+(ViewProperty view0 PhysicalEnvironment VirtualPortal)
+
+// Set the user eye position in the display environment. It is set here to
+// 1.340 meters back from the center screen (directly under the tracker), and
+// 1.737 meters from the floor (about 5 ft 8.4 inches).
+//
+(ViewProperty view0 CenterEyeInCoexistence (0.0 0.494 1.340))
+
+// Explict scaling.
+//
+(ViewProperty view0 ScreenScalePolicy SCALE_EXPLICIT)
+(ViewProperty view0 ScreenScale 0.30)
+
+// No stereo viewing for this configuration.
+//
+(ViewProperty view0 StereoEnable False)
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x3-rot45.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x3-rot45.html
new file mode 100644
index 0000000..927dbd8
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d1x3-rot45.html
@@ -0,0 +1,122 @@
+
+
+
+
+
+/*
+ ************************************************************************
+ *
+ * Java 3D configuration file for 3 screens. Left and right screens are
+ * rotated 45 degrees from the center screen.
+ *
+ ************************************************************************
+ */
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+//
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+//
+(NewScreen left 0)
+(NewScreen center 1)
+(NewScreen right 2)
+
+// Set the available image areas for full screens.
+//
+(ScreenProperty left PhysicalScreenWidth 0.360)
+(ScreenProperty left PhysicalScreenHeight 0.288)
+
+(ScreenProperty center PhysicalScreenWidth 0.360)
+(ScreenProperty center PhysicalScreenHeight 0.288)
+
+(ScreenProperty right PhysicalScreenWidth 0.360)
+(ScreenProperty right PhysicalScreenHeight 0.288)
+
+// Specify full screen windows.
+//
+(ScreenProperty left WindowSize NoBorderFullScreen)
+(ScreenProperty center WindowSize NoBorderFullScreen)
+(ScreenProperty right WindowSize NoBorderFullScreen)
+
+// Set the TrackerBaseToImagePlate transforms for these screens.
+//
+// The tracker base and center of coexistence are set here to the middle of the
+// center screen. The basis vectors are aligned with the center screen image
+// plate. The left and right screens are rotated 45 degrees toward each other
+// about their shared edges with the center screen.
+//
+(ScreenProperty center TrackerBaseToImagePlate
+ (Translate 0.180000 0.144000 0.000000))
+
+// cos(45) * 0.360 * 0.5 = 0.127279; 0.360 + 0.127279 = 0.487279
+(ScreenProperty left TrackerBaseToImagePlate
+ (RotateTranslate
+ (Rotate 0.000000 -45.000000 0.000000)
+ (Translate 0.487279 0.144000 0.127279)))
+
+// cos(45) * 0.360 * 0.5 = 0.127279
+(ScreenProperty right TrackerBaseToImagePlate
+ (RotateTranslate
+ (Rotate 0.000000 45.000000 0.000000)
+ (Translate -0.127279 0.144000 0.127279)))
+
+// Create a view using the defined screens.
+//
+(NewView view0)
+(ViewProperty view0 Screen left)
+(ViewProperty view0 Screen center)
+(ViewProperty view0 Screen right)
+(ViewProperty view0 CenterEyeInCoexistence (0.0 0.0 0.5))
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d2x2-flat.html b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d2x2-flat.html
new file mode 100644
index 0000000..af6f62f
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/doc-files/j3d2x2-flat.html
@@ -0,0 +1,147 @@
+
+
+
+
+
+/*
+ ************************************************************************
+ *
+ * Java 3D configuration file for 4 screen projection configuration
+ * arranged in a 2x2 power wall.
+ *
+ ************************************************************************
+ */
+
+// Create new screen objects and associate them with logical names and numbers.
+// These numbers are used as indices to retrieve the AWT GraphicsDevice from
+// the array that GraphicsEnvironment.getScreenDevices() returns.
+//
+// NOTE: The GraphicsDevice order in the array is specific to the local
+// site and display system.
+//
+(NewScreen topleft 0)
+(NewScreen topright 1)
+(NewScreen bottomleft 3)
+(NewScreen bottomright 2)
+
+// Set the available image areas for full screens. This is important when
+// precise scaling between objects in the virtual world and their projections
+// into the physical world is desired through use of explicit ScreenScale view
+// attributes. The defaults are 0.365 meters for width and 0.292 meters for
+// height.
+//
+(ScreenProperty topleft PhysicalScreenWidth 0.912)
+(ScreenProperty topleft PhysicalScreenHeight 0.680)
+
+(ScreenProperty topright PhysicalScreenWidth 0.912)
+(ScreenProperty topright PhysicalScreenHeight 0.680)
+
+(ScreenProperty bottomleft PhysicalScreenWidth 0.912)
+(ScreenProperty bottomleft PhysicalScreenHeight 0.685)
+
+(ScreenProperty bottomright PhysicalScreenWidth 0.912)
+(ScreenProperty bottomright PhysicalScreenHeight 0.685)
+
+
+// Specify full screen windows.
+//
+(ScreenProperty topleft WindowSize NoBorderFullScreen)
+(ScreenProperty topright WindowSize NoBorderFullScreen)
+(ScreenProperty bottomleft WindowSize NoBorderFullScreen)
+(ScreenProperty bottomright WindowSize NoBorderFullScreen)
+
+// Set the TrackerBaseToImagePlate transforms for these screens. This
+// transforms points in tracker base coordinates to each screen's image plate
+// coordinates, where the origin of the image plate is defined to be the lower
+// left corner of the screen with X increasing to the right, Y increasing to
+// the top, and Z increasing away from the screen.
+//
+// Without head or sensor tracking the tracker base is still needed as a point
+// of reference for describing the orientation and position of each screen to
+// the others. The coexistence to tracker base transform is set to identity by
+// default, so the tracker base origin and orientation will also set the origin
+// and orientation of coexistence coordinates in the physical world.
+//
+// The tracker base and center of coexistence are set here to the center of the
+// 2x2 array with its basis vectors aligned to image plate coordinates.
+//
+(ScreenProperty topleft TrackerBaseToImagePlate
+ (Translate 0.912 0.000 0.0))
+(ScreenProperty topright TrackerBaseToImagePlate
+ (Translate 0.000 0.000 0.0))
+(ScreenProperty bottomleft TrackerBaseToImagePlate
+ (Translate 0.912 0.685 0.0))
+(ScreenProperty bottomright TrackerBaseToImagePlate
+ (Translate 0.000 0.685 0.0))
+
+// Create a view using the defined screens.
+//
+(NewView view0)
+(ViewProperty view0 Screen topleft)
+(ViewProperty view0 Screen topright)
+(ViewProperty view0 Screen bottomleft)
+(ViewProperty view0 Screen bottomright)
+
+// Set the screen scale. This is scale factor from virtual to physical
+// coordinates. The default policy of SCALE_SCREEN_SIZE doesn't work well here
+// since in the 2x2 arrangement the individual screens are too small. The
+// explicit scale factor below assumes a normalized range of object coordinates
+// of [-1.0 .. +1.0].
+//
+(ViewProperty view0 ScreenScalePolicy SCALE_EXPLICIT)
+(ViewProperty view0 ScreenScale 0.912)
+
+// Set the user eye position in the display environment.
+//
+(ViewProperty view0 CenterEyeInCoexistence (0.0 0.0 1.0))
+
+
+
diff --git a/src/classes/share/org/jogamp/java3d/utils/universe/package.html b/src/classes/share/org/jogamp/java3d/utils/universe/package.html
new file mode 100644
index 0000000..06c31db
--- /dev/null
+++ b/src/classes/share/org/jogamp/java3d/utils/universe/package.html
@@ -0,0 +1,12 @@
+
+
+
+
+