/**
  * Set one pixel value at the correct index in this field. Basically a single pixel set, but it
  * could also be width, height, number of components. This must be used with great care as it
  * could well corrupt the user data.
  *
  * @param index The position in the array to set
  * @param value The value to use at that position
  */
 public void set1Value(int index, int value) throws ArrayIndexOutOfBoundsException {
   checkReadAccess();
   checkWriteAccess();
   if (value < 0) throw new IllegalArgumentException("Pixels may not be negative.");
   if (index < 0) throw new ArrayIndexOutOfBoundsException();
   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;
     }
     queuedElement.storedInputValue[index] = value;
     queuedElement.rogueInputData = true;
     if (newEvent) theEventQueue.processEvent(queuedElement);
   }
 }
 /**
  * Inserts a value into an existing index of the field. Current field values from the index to the
  * end of the field are shifted down and the field length is increased by one to accomodate the
  * new element.
  *
  * <p>This method modifies the integer array rather than the conceptual image array.
  *
  * <p>If the index is out of the bounds of the current field an ArrayIndexOutofBoundsException
  * will be generated.
  *
  * @param index The position at which to insert
  * @param value The new element to insert
  * @exception ArrayIndexOutOfBoundsException The index was outside the current field size.
  */
 public void insertValue(int index, int value) 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;
     }
     queuedElement.ensureArraySize(queuedElement.storedInputLength + 1);
     System.arraycopy(
         queuedElement.storedInputValue,
         index,
         queuedElement.storedInputValue,
         index + 1,
         queuedElement.storedInputLength - index);
     queuedElement.storedInputValue[index] = value;
     queuedElement.storedInputLength++;
     queuedElement.rogueInputData = true;
     if (newEvent) theEventQueue.processEvent(queuedElement);
   }
 }
 /**
  * Copy a region of the argument RenderedImage to replace a portion of the current SFimage.
  *
  * <p>The sub image set shall not resize the base image representation and therefore performs an
  * intersection clip of the provided image. The user provided image shall be of the same format
  * (pixel depth, pixel representation) as the original image obtained through the getImage()
  * method.
  *
  * <p>RenderedImages are row order from top to bottom. A 4x8 RenderImage is indexed as follows:
  *
  * <PRE>
  *
  * X >01234567
  *   ----------
  * 0 |********|
  * 1 |********|
  * 2 |********|
  * 3 |********|
  * ^ ----------
  * Y
  *
  * </PRE>
  *
  * SFImages are row order from bottom to top. A 4x8 RenderImage is indexed as follows:
  *
  * <PRE>
  *
  * X >01234567
  *   ----------
  * 3 |********|
  * 2 |********|
  * 1 |********|
  * 0 |********|
  * ^ ----------
  * Y
  *
  * </PRE>
  *
  * <p>Note: The parameter srcYOffset is referenced to the RenderedImage object (indexed top to
  * bottom). <br>
  * The parameter destYOffset is referenced to the SFImage object (indexed bottom to top).
  *
  * @param imgIndex The index of the image in the array
  * @param img The new image to use as the source
  * @param srcWidth The width of the argument sub-image region to copy
  * @param srcHeight The height of the argument sub-image region to copy
  * @param srcXOffset The initial x dimension (width) offset into the argument sub-image that
  *     begins the region to copy
  * @param srcYOffset The initial y dimension (height) offset into the argument sub-image that
  *     begins the region to copy
  * @param destXOffset The initial x dimension (width) offset in the SFimage object that begins the
  *     region to receive the copy
  * @param destYOffset The initial y dimension (height) offset in the SFimage object that begins
  *     the region to receive the copy
  */
 public void setSubImage(
     int imgIndex,
     RenderedImage img,
     int srcWidth,
     int srcHeight,
     int srcXOffset,
     int srcYOffset,
     int destXOffset,
     int destYOffset)
     throws InvalidOperationTimingException, InvalidFieldValueException,
         InvalidWritableFieldException, InvalidFieldException {
   checkWriteAccess();
   if (imgIndex < 0) throw new ArrayIndexOutOfBoundsException();
   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;
         // TODO: Insert image values
       } else {
         // If this generates an ArrayIndexOutOfBounds its okay,
         // the element will be garbage.
         queuedElement =
             new MFImageWrapper(theNode, fieldIndex, theEventQueue, theEventAdapterFactory, true);
         queuedElement.isSetOneValue = true;
         // TODO: Insert image values
       }
       theEventQueue.processEvent(queuedElement);
     } else {
       checkDataSanity();
       // TODO: Insert image values
     }
   }
 }
 /** @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();
     }
   }
 }
 /**
  * Set the image value in the given writable field to the new image defined by a set of pixels.
  *
  * <p>
  *
  * @param imgIndex The index of the image in the array
  * @param img The new image to use as the source
  */
 public void setImage(int imgIndex, RenderedImage img)
     throws InvalidOperationTimingException, InvalidFieldValueException,
         InvalidWritableFieldException, InvalidFieldException {
   if (imgIndex < 0) throw new ArrayIndexOutOfBoundsException();
   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 < 0) throw new ArrayIndexOutOfBoundsException();
         loadInputValue();
         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, img.getWidth(), img.getHeight());
       SFImageUtils.convertRenderedImageToData(
           img, queuedElement.storedInputValue, queuedElement.findStartOfInputImage(imgIndex));
       theEventQueue.processEvent(queuedElement);
     } else {
       checkDataSanity();
       queuedElement.rewriteImageToSize(imgIndex, img.getWidth(), img.getHeight());
       SFImageUtils.convertRenderedImageToData(
           img, queuedElement.storedInputValue, queuedElement.findStartOfInputImage(imgIndex));
       queuedElement.getSize();
     }
   }
 }
 /**
  * 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);
     }
   }
 }
 int findStartOfInputImage(int index) {
   return MFImageWrapper.findStartOfImage(index, storedInputValue);
 }