/**
  * Get the value of a particular vector value in the event out array.
  *
  * @param index The position to get the vectory value from.
  * @param vec The array to place the value in where. vec[0] = X<br>
  *     vec[1] = Y<br>
  *     vec[2] = Z
  * @exception ArrayIndexOutOfBoundsException The provided array was too small or the index was
  *     outside the current data array bounds.
  */
 public void get1Value(int index, float[] vec) {
   if (storedOutput) System.arraycopy(storedOutputValue, index * 3, vec, 0, 3);
   else {
     checkReadAccess();
     VRMLFieldData data = theNode.getFieldValue(fieldIndex);
     // floatArrayValue may be null if numElements == 0
     if (index < 0 || index >= data.numElements) throw new ArrayIndexOutOfBoundsException();
     else System.arraycopy(data.floatArrayValue, index * 3, vec, 0, 3);
   }
 }
 /**
  * Get the values of the event out flattened into a single 1D array. The array must be at least 3
  * times the size of the array.
  *
  * @param vec The array to be filled in where the vec[i + 0] = X<br>
  *     vec[i + 1] = Y<br>
  *     vec[i + 2] = Z<br>
  * @exception ArrayIndexOutOfBoundsException The provided array was too small
  */
 public void getValue(float[] vec) {
   if (storedOutput) {
     System.arraycopy(storedOutputValue, 0, vec, 0, storedOutputValue.length);
   } else {
     checkReadAccess();
     VRMLFieldData data = theNode.getFieldValue(fieldIndex);
     if (data.numElements != 0)
       System.arraycopy(data.floatArrayValue, 0, vec, 0, data.numElements * 3);
   }
 }
 /**
  * Magical method to make room for a new image to replace a current one. The newly reallocated
  * image is not validly formatted. Replaces storedInputValue with a new array.
  */
 void rewriteImageToSize(int imageIndex, int newWidth, int newHeight) {
   int startOfImage = findStartOfImage(imageIndex, storedInputValue);
   int newSize = newWidth * newHeight + 3;
   int oldSize = storedInputValue[startOfImage] * storedInputValue[startOfImage + 1] + 3;
   int newArray[] = new int[storedInputValue.length - oldSize + newSize];
   System.arraycopy(storedInputValue, 0, newArray, 0, startOfImage);
   System.arraycopy(
       storedInputValue,
       startOfImage + oldSize,
       newArray,
       startOfImage + newSize,
       storedInputValue.length - startOfImage - oldSize);
   storedInputValue = newArray;
   // throw new RuntimeException("Not yet implemented");
 }
 /** @see org.web3d.x3d.sai.MFVec3f#insertValue(int, float[]) */
 public void insertValue(int index, float[] value) throws ArrayIndexOutOfBoundsException {
   checkReadAccess();
   checkWriteAccess();
   synchronized (theEventQueue.eventLock) {
     MFVec3fWrapper queuedElement = (MFVec3fWrapper) theEventQueue.getLast(this);
     boolean newEvent = false;
     if (queuedElement == null || !queuedElement.isSetOneValue) {
       // Input and output buffers do not mix
       if (!storedInput && !storedOutput) {
         queuedElement = this;
         loadInputValue();
         isSetOneValue = true;
       } else {
         queuedElement =
             new MFVec3fWrapper(theNode, fieldIndex, theEventQueue, theEventAdapterFactory, true);
         queuedElement.isSetOneValue = true;
       }
       newEvent = true;
     }
     queuedElement.ensureArraySize(queuedElement.storedInputLength + 3);
     System.arraycopy(
         queuedElement.storedInputValue,
         index * 3,
         queuedElement.storedInputValue,
         index * 3 + 3,
         queuedElement.storedInputLength - index * 3);
     queuedElement.storedInputValue[index * 3] = value[0];
     queuedElement.storedInputValue[index * 3 + 1] = value[1];
     queuedElement.storedInputValue[index * 3 + 2] = value[2];
     queuedElement.storedInputLength += 3;
     if (newEvent) theEventQueue.processEvent(queuedElement);
   }
 }
 /**
  * Ensures that there is atleast a certain number of elements in the storedInputValue array.
  *
  * @param newSize The size to ensure.
  */
 protected void ensureArraySize(int newSize) {
   if (storedInputValue != null && newSize < storedInputValue.length) return;
   float newArray[] = new float[newSize];
   if (storedInputValue != null)
     System.arraycopy(storedInputValue, 0, newArray, 0, storedInputLength);
   storedInputValue = newArray;
 }
 /** Load the current field value from the underlying node and store it as the output value. */
 public void loadOutputValue() {
   if (!isWritable()) return;
   VRMLFieldData value = theNode.getFieldValue(fieldIndex);
   if (storedOutputValue == null || storedOutputValue.length != value.numElements)
     storedOutputValue = new float[value.numElements * 3];
   if (value.numElements != 0)
     System.arraycopy(value.floatArrayValue, 0, storedOutputValue, 0, value.numElements * 3);
   storedOutput = true;
 }
 /** Load the current field value from the underlying node and store it as the input value. */
 private void loadInputValue() {
   if (!isReadable()) return;
   VRMLFieldData value = theNode.getFieldValue(fieldIndex);
   if (storedInputValue == null || storedInputValue.length != value.numElements * 3)
     storedInputValue = new float[value.numElements * 3];
   if (value.numElements != 0)
     System.arraycopy(value.floatArrayValue, 0, storedInputValue, 0, value.numElements * 3);
   storedInput = true;
   storedInputLength = storedInputValue.length;
 }
 /** Load the current field value from the underlying node and store it as the output value. */
 public void loadOutputValue() {
   if (!isWritable()) return;
   // throw new RuntimeException("Not yet implemented");
   VRMLFieldData value = theNode.getFieldValue(fieldIndex);
   int requiredSize = value.numElements;
   // calculateRequiredStorage(value.numElements,value.intArrayValue);
   if (storedOutputValue == null || storedOutputValue.length < requiredSize)
     storedOutputValue = new int[requiredSize];
   System.arraycopy(value.intArrayValue, 0, storedOutputValue, 0, requiredSize);
   storedOutput = true;
 }
 /** Load the current field value from the underlying node and store it as the input value. */
 private void loadInputValue() {
   if (!isReadable()) return;
   VRMLFieldData value = theNode.getFieldValue(fieldIndex);
   int requiredSize = value.numElements;
   // calculateRequiredStorage(value.numElements,value.intArrayValue);
   if (storedInputValue == null || storedInputValue.length < requiredSize)
     storedInputValue = new int[requiredSize];
   System.arraycopy(value.intArrayValue, 0, storedInputValue, 0, requiredSize);
   storedInput = true;
   storedInputLength = storedInputValue.length;
 }
 /**
  * Set the image value in the given writable field.
  * <P>
  * Image values are specified using a width, height and the number of
  * components. The number of items in the pixels array must be at least
  * <CODE>width * height<CODE>. If there are less items than this an
  * ArrayIndexOutOfBoundsException will be generated. The integer values
  * are represented according to the number of components. If the integer
  * contains values in bytes that are not used by the number of components
  * for that image, the values are ignored.
  * <P>
  * <B>1 Component Images</B><BR>
  * The integer has the intensity value stored in the lowest byte and can be
  * obtained:
  * <PRE>
  *    intensity = (pixel[i]     ) & 0xFF;
  * </PRE>
  * <P>
  * <B>2 Component Images</B><BR>
  * The integer has the transparency value stored in the lowest byte and the
  * intensity in the next byte:
  * <PRE>
  *    intensity = (pixel[i] >> 8) & 0xFF;
  *    alpha     = (pixel[i]     ) & 0xFF;
  * </PRE>
  * <P>
  * <B>3 Component Images</B><BR>
  * The three color components are stored in the integer array as follows:
  * <PRE>
  *    red   = (pixel[i] >> 16) & 0xFF;
  *    green = (pixel[i] >>  8) & 0xFF;
  *    blue  = (pixel[i]      ) & 0xFF;
  * </PRE>
  * <P>
  * <B>4 Component Images</B><BR>
  * The integer has the value stored in the array as follows:
  * <PRE>
  *    red   = (pixel[i] >> 24) & 0xFF;
  *    green = (pixel[i] >> 16) & 0xFF;
  *    blue  = (pixel[i] >>  8) & 0xFF;
  *    alpha = (pixel[i]      ) & 0xFF;
  * </PRE>
  * <P>
  * The width and height values must be greater than or equal to zero. The
  * number of components is between 1 and 4. Any value outside of these
  * bounds will generate an IllegalArgumentException.
  *
  * @param imgIndex The index of the image in the array
  * @param width The width of the image in pixels
  * @param height The height of the image in pixels
  * @param components The number of colour components [1-4]
  * @param pixels The array of pixel values as specified above.
  *
  * @exception IllegalArgumentException The number of components or width/
  *    height are illegal values.
  * @exception ArrayIndexOutOfBoundsException The number of pixels provided by the
  *    caller is not enough for the width * height.
  */
 public void set1Value(int imgIndex, int width, int height, int components, int[] pixels) {
   if (imgIndex < 0) throw new ArrayIndexOutOfBoundsException();
   if (width < 0 || height < 0 || components < 0 || components > 4)
     throw new IllegalArgumentException();
   checkWriteAccess();
   synchronized (theEventQueue.eventLock) {
     MFImageWrapper queuedElement = (MFImageWrapper) theEventQueue.getLast(this);
     if (queuedElement == null || !queuedElement.isSetOneValue) {
       // Input and output buffers do not mix
       if (!storedInput && !storedOutput) {
         // Avoid clogging this buffer if
         // index out of bounds
         if (imgIndex >= storedInputValue.length) throw new ArrayIndexOutOfBoundsException();
         queuedElement = this;
         loadInputValue();
         isSetOneValue = true;
       } else {
         // If this generates an ArrayIndexOutOfBounds its okay,
         // the element will be garbage.
         queuedElement =
             new MFImageWrapper(theNode, fieldIndex, theEventQueue, theEventAdapterFactory, true);
         queuedElement.isSetOneValue = true;
       }
       queuedElement.rewriteImageToSize(imgIndex, width, height);
       int startingIndex = queuedElement.findStartOfInputImage(imgIndex);
       queuedElement.storedInputValue[startingIndex + 2] = components;
       if (pixels.length != 0)
         System.arraycopy(
             pixels, 0, queuedElement.storedInputValue, startingIndex + 3, pixels.length);
       theEventQueue.processEvent(queuedElement);
     } else {
       checkDataSanity();
       queuedElement.rewriteImageToSize(imgIndex, width, height);
       int startingIndex = queuedElement.findStartOfInputImage(imgIndex);
       queuedElement.storedInputValue[startingIndex + 2] = components;
       if (pixels.length != 0)
         System.arraycopy(
             pixels, 0, queuedElement.storedInputValue, startingIndex + 3, pixels.length);
     }
   }
 }
 /**
  * Set the value of the array of 3D vectors. Input is an array of doubles If value[i] does not
  * contain at least three values it will generate an ArrayIndexOutOfBoundsException. If value[i]
  * contains more than three items only the first three values will be used and the rest ignored.
  *
  * <p>If one or more of the values for value[i] are null then the resulting event that is sent to
  * the VRML scenegraph is implementation dependent but no error indicator will be set here.
  *
  * @param numVec The number of items to copy from the array
  * @param value The array of vec2f values where<br>
  *     value[i] = X<br>
  *     value[i+1] = Y<br>
  *     value[i+2] = Z
  * @exception ArrayIndexOutOfBoundsException A value did not contain at least three values for the
  *     vector definition.
  */
 public void setValue(int numVec, float[] value) {
   checkWriteAccess();
   MFVec3fWrapper queuedElement = this;
   // Input and output buffers do not mix, and further don't overwrite
   // set1Value calls.
   if (isSetOneValue || storedInput || storedOutput) {
     queuedElement =
         new MFVec3fWrapper(theNode, fieldIndex, theEventQueue, theEventAdapterFactory);
   }
   queuedElement.storedInput = true;
   if (queuedElement.storedInputValue == null
       || queuedElement.storedInputValue.length != numVec * 3)
     queuedElement.storedInputValue = new float[numVec * 3];
   System.arraycopy(value, 0, queuedElement.storedInputValue, 0, numVec * 3);
   queuedElement.storedInputLength = numVec * 3;
   theEventQueue.processEvent(queuedElement);
 }
 /**
  * Get the image pixel value in the given eventOut.
  * <P>
  * The number of items in the pixels array will be
  * <CODE>width * height<CODE>. If there are less items than this an
  * ArrayIndexOutOfBoundsException will be generated. The integer values
  * are represented according to the number of components.
  * <P>
  * <B>1 Component Images</B><BR>
  * The integer has the intensity value stored in the lowest byte and can be
  * obtained:
  * <PRE>
  *    intensity = (pixel[i]     ) & 0xFF;
  * </PRE>
  * <P>
  * <B>2 Component Images</B><BR>
  * The integer has the transparency value stored in the lowest byte and the
  * intensity in the next byte:
  * <PRE>
  *    intensity = (pixel[i] >> 8) & 0xFF;
  *    alpha     = (pixel[i]     ) & 0xFF;
  * </PRE>
  * <P>
  * <B>3 Component Images</B><BR>
  * The three color components are stored in the integer array as follows:
  * <PRE>
  *    red   = (pixel[i] >> 16) & 0xFF;
  *    green = (pixel[i] >>  8) & 0xFF;
  *    blue  = (pixel[i]      ) & 0xFF;
  * </PRE>
  * <P>
  * <B>4 Component Images</B><BR>
  * The integer has the value stored in the array as follows:
  * <PRE>
  *    red   = (pixel[i] >> 24) & 0xFF;
  *    green = (pixel[i] >> 16) & 0xFF;
  *    blue  = (pixel[i] >>  8) & 0xFF;
  *    alpha = (pixel[i]      ) & 0xFF;
  * </PRE>
  * <P>
  * The width and height values must be greater than or equal to zero. The
  * number of components is between 1 and 4. Any value outside of these
  * bounds will generate an IllegalArgumentException.
  *
  * @param imgIndex The index of the image in the array
  * @param pixels The array to copy pixel values into
  */
 public void getPixels(int imgIndex, int[] pixels) {
   // throw new RuntimeException("Not yet implemented");
   int startOfImageData;
   int pixelSource[];
   if (storedOutput) {
     if (imgIndex < 0) throw new ArrayIndexOutOfBoundsException();
     pixelSource = storedOutputValue;
   } else {
     checkReadAccess();
     VRMLFieldData data = theNode.getFieldValue(fieldIndex);
     if (imgIndex < 0 || imgIndex >= countActualImages(data.intArrayValue, data.numElements))
       throw new ArrayIndexOutOfBoundsException();
     pixelSource = data.intArrayValue;
   }
   startOfImageData = findStartOfImage(imgIndex, pixelSource);
   int imageSize = pixelSource[startOfImageData] * pixelSource[startOfImageData + 1];
   System.arraycopy(pixelSource, startOfImageData + 3, pixels, 0, imageSize);
 }
 /** @see org.web3d.x3d.sai.MFImage#removeValue(int) */
 public void removeValue(int index) throws ArrayIndexOutOfBoundsException {
   checkReadAccess();
   checkWriteAccess();
   synchronized (theEventQueue.eventLock) {
     MFImageWrapper queuedElement = (MFImageWrapper) theEventQueue.getLast(this);
     boolean newEvent = false;
     if (queuedElement == null || !queuedElement.isSetOneValue) {
       // Input and output buffers do not mix
       if (!storedInput && !storedOutput) {
         queuedElement = this;
         loadInputValue();
         isSetOneValue = true;
       } else {
         queuedElement =
             new MFImageWrapper(theNode, fieldIndex, theEventQueue, theEventAdapterFactory, true);
         queuedElement.isSetOneValue = true;
       }
       newEvent = true;
     }
     // Removing a raw byte, rather than an image value.
     if (queuedElement.storedInputLength > 0) {
       if (index + 1 < queuedElement.storedInputLength)
         System.arraycopy(
             queuedElement.storedInputValue,
             index + 1,
             queuedElement.storedInputValue,
             index,
             queuedElement.storedInputLength - index - 1);
       queuedElement.storedInputLength--;
       queuedElement.rogueInputData = true;
       if (newEvent) theEventQueue.processEvent(queuedElement);
     } else {
       // Free up the buffer before throwing the exception
       if (newEvent) queuedElement.isSetOneValue = false;
       throw new ArrayIndexOutOfBoundsException();
     }
   }
 }