Re: [visad] Strange rendering depending on axis range

Hello Sir

Attached herewith a modified version of ShadowImageByRefFunctionTypeJ3D and a slightly modified version of ShadowFunctionSetTypeJ3D.
Keep the old jars.

Kindly recompile them and just see this time you will be able to see the details you have been looking for. Just confirm me if there any artifact that is coming higher resolution. I have tested in both the programs that you sent me. I am seeing no issues.
Just let me know if there are any.

I will again quote the same DISCLAIMER NOTICE:
It is pretty much a TEMPORARY (not very TESTED) solution but still very EFFICIENT ;-)

This is something pretty New as Tom Rink Sir says "DISCOVERY BY ACCIDENT" :-) because we are able to generate this type of surface details using geometry only.

But now we are doing it using Textures.

It is gonna change our way we were thinking till now in visAD.


with regards
Ghansham




On 05/31/2012 11:30 PM, visad-request@xxxxxxxxxxxxxxxx wrote:
Send visad mailing list submissions to
        visad@xxxxxxxxxxxxxxxx

To subscribe or unsubscribe via the World Wide Web, visit
        http://mailman.unidata.ucar.edu/mailman/listinfo/visad
or, via email, send a message with subject or body 'help' to
        visad-request@xxxxxxxxxxxxxxxx

You can reach the person managing the list at
        visad-owner@xxxxxxxxxxxxxxxx

When replying, please edit your Subject line so it is more specific
than "Re: Contents of visad digest..."


Today's Topics:

    1. Re: Strange rendering depending on axis range (Ghansham Sangar)
    2. Re: Strange rendering depending on axis range (Tomas Pluskal)


----------------------------------------------------------------------

Message: 1
Date: Thu, 31 May 2012 11:54:22 +0530
From: Ghansham Sangar<ghansham@xxxxxxxxxxxxxxx>
To: visad@xxxxxxxxxxxxxxxx
Subject: Re: [visad] Strange rendering depending on axis range
Message-ID:<4FC70E96.50701@xxxxxxxxxxxxxxx>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed

R/Sir

I would suggest you to just check with the modified render for the range
setting issue.
That will be really appreciated.

regards
Ghansham


On 05/31/2012 11:15 AM, visad-request@xxxxxxxxxxxxxxxx wrote:
Send visad mailing list submissions to
        visad@xxxxxxxxxxxxxxxx

To subscribe or unsubscribe via the World Wide Web, visit
        http://mailman.unidata.ucar.edu/mailman/listinfo/visad
or, via email, send a message with subject or body 'help' to
        visad-request@xxxxxxxxxxxxxxxx

You can reach the person managing the list at
        visad-owner@xxxxxxxxxxxxxxxx

When replying, please edit your Subject line so it is more specific
than "Re: Contents of visad digest..."


Today's Topics:

     1. Re: Strange rendering depending on axis range (Tomas Pluskal)


----------------------------------------------------------------------

Message: 1
Date: Thu, 31 May 2012 05:44:55 +0000
From: Tomas Pluskal<pluskal@xxxxxxx>
To: "visad@xxxxxxxxxxxxxxxx"<visad@xxxxxxxxxxxxxxxx>
Subject: Re: [visad] Strange rendering depending on axis range
Message-ID:<AFA0F858-9E23-4E74-83B4-E0CA2A4F3766@xxxxxxx>
Content-Type: text/plain; charset="windows-1252"

Hi Tom,


formally setting the ranges to decimal values fixes the problem for me.

Just a followup to this issue: setting the range to 44027 -  44028 shows the 
same problem, despite using decimal values (screenshot is attached).

Tomas
[cid:71D3DE54-921A-4BAD-8A61-699176429D50@oist.jp]
===============================================
Tom?? Pluskal
G0 Cell Unit, Okinawa Institute of Science and Technology Graduate University
1919-1 Tancha, Onna-son, Okinawa 904-0495, Japan
TEL: +81-98-966-8684
Fax: +81-98-966-2890

-------------- next part --------------
An HTML attachment was scrubbed...
URL:<http://mailman.unidata.ucar.edu/mailing_lists/archives/visad/attachments/20120531/11a1504e/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Screen Shot 2012-05-31 at 2.40.27 PM.png
Type: image/png
Size: 24416 bytes
Desc: Screen Shot 2012-05-31 at 2.40.27 PM.png
URL:<http://mailman.unidata.ucar.edu/mailing_lists/archives/visad/attachments/20120531/11a1504e/attachment.png>

------------------------------

_______________________________________________
visad mailing list
visad@xxxxxxxxxxxxxxxx
For list information, to unsubscribe, visit: 
http://www.unidata.ucar.edu/mailing_lists/

End of visad Digest, Vol 30, Issue 15
*************************************



------------------------------

Message: 2
Date: Thu, 31 May 2012 07:57:17 +0000
From: Tomas Pluskal<pluskal@xxxxxxx>
To: "visad@xxxxxxxxxxxxxxxx"<visad@xxxxxxxxxxxxxxxx>
Subject: Re: [visad] Strange rendering depending on axis range
Message-ID:<8AD72553-F8A3-4297-A693-4720AF715CED@xxxxxxx>
Content-Type: text/plain; charset="Windows-1252"

Dear Gransham,

Please note that this issue only appears with texture set to OFF.
When I set textures to ON, I get a nice flat plane (using default renderer) .
When I use your modified DisplayRendererJ3D, I also get a nice flat plane.

Best regards,

Tomas


On May 31, 2012, at 3:24 PM, Ghansham Sangar wrote:

R/Sir

I would suggest you to just check with the modified render for the range 
setting issue.
That will be really appreciated.

regards
Ghansham



===============================================
Tom?? Pluskal
G0 Cell Unit, Okinawa Institute of Science and Technology Graduate University
1919-1 Tancha, Onna-son, Okinawa 904-0495, Japan
TEL: +81-98-966-8684
Fax: +81-98-966-2890



------------------------------

_______________________________________________
visad mailing list
visad@xxxxxxxxxxxxxxxx
For list information, to unsubscribe, visit: 
http://www.unidata.ucar.edu/mailing_lists/

End of visad Digest, Vol 30, Issue 16
*************************************


//
// ShadowFunctionOrSetTypeJ3D.java
//

/*
VisAD system for interactive analysis and visualization of numerical
data.  Copyright (C) 1996 - 2009 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/

package visad.java3d;

import visad.*;
import visad.util.ThreadManager;

import javax.media.j3d.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import java.rmi.*;

import java.awt.image.*;


/**
   The ShadowFunctionOrSetTypeJ3D is an abstract parent for
   ShadowFunctionTypeJ3D and ShadowSetTypeJ3D.<P>
*/
public class ShadowFunctionOrSetTypeJ3D extends ShadowTypeJ3D {

  ShadowRealTupleTypeJ3D Domain;
  ShadowTypeJ3D Range; // null for ShadowSetTypeJ3D

  private Vector AccumulationVector = new Vector();

  public ShadowFunctionOrSetTypeJ3D(MathType t, DataDisplayLink link,
                                    ShadowType parent)
      throws VisADException, RemoteException {
    super(t, link, parent);
    if (this instanceof ShadowFunctionTypeJ3D) {
      Domain = (ShadowRealTupleTypeJ3D)
               ((FunctionType) Type).getDomain().buildShadowType(link, this);
      Range = (ShadowTypeJ3D)
              ((FunctionType) Type).getRange().buildShadowType(link, this);
      adaptedShadowType =
        new ShadowFunctionType(t, link, getAdaptedParent(parent),
                       (ShadowRealTupleType) Domain.getAdaptedShadowType(),
                       Range.getAdaptedShadowType());
    }
    else {
      Domain = (ShadowRealTupleTypeJ3D)
               ((SetType) Type).getDomain().buildShadowType(Link, this);
      Range = null;
      adaptedShadowType =
        new ShadowSetType(t, link, getAdaptedParent(parent),
                       (ShadowRealTupleType) Domain.getAdaptedShadowType());
    }
  }

  public ShadowRealTupleTypeJ3D getDomain() {
    return Domain;
  }

  public ShadowTypeJ3D getRange() {
    return Range;
  }

  /** clear AccumulationVector */
  public void preProcess() throws VisADException {
    AccumulationVector.removeAllElements();
    if (this instanceof ShadowFunctionTypeJ3D) {
      Range.preProcess();
    }
  }

  /** transform data into a Java3D scene graph;
      add generated scene graph components as children of group;
      value_array are inherited valueArray values;
      default_values are defaults for each display.DisplayRealTypeVector;
      return true if need post-process */
  public boolean doTransform(Object group, Data data, final float[] value_array,
                             final float[] default_values, final DataRenderer 
renderer)
         throws VisADException, RemoteException {

    boolean post = true; // FIXME what value for animation?
    boolean isAnimation1d = false;
    boolean isTerminal = adaptedShadowType.getIsTerminal();
    
    ScalarMap timeMap = null; // used in the animation case to get control
    DataDisplayLink[] link_s = renderer.getLinks();
    DataDisplayLink link = link_s[0];
    Vector scalarMaps = link.getSelectedMapVector();
    
    // only determine if it's an animation if non-terminal. isTerminal will
    // only be determined if there are scalar maps - defaults to false
    if (!isTerminal && !scalarMaps.isEmpty()) {
      // determine if it's an animation
      MathType mtype = data.getType();
      if (mtype instanceof FunctionType) {
        int ani_map_idx = 0;
        FunctionType function = (FunctionType) mtype;
        RealTupleType functionD = function.getDomain();
        for (int kk = 0; kk < scalarMaps.size(); kk++) {
          ScalarMap scalarMap = (ScalarMap) scalarMaps.elementAt(kk);
          String scalar_name = scalarMap.getScalarName();
          if (scalar_name.equals(((RealType) 
functionD.getComponent(0)).getName())) {
            if (((scalarMap.getDisplayScalar()).equals(Display.Animation))
                && (functionD.getDimension() == 1)) {
              isAnimation1d = true;
              ani_map_idx = kk;
            }
          }
        }
        // animation domain
        timeMap = (ScalarMap) scalarMaps.elementAt(ani_map_idx);
      }
    }
    // animation logic
    if (isAnimation1d){
      
      // analyze data's domain (its a Field)
      Set domainSet = ((Field) data).getDomainSet();
      
      // create and add switch with nodes for animation images
      int domainLength = domainSet.getLength(); // num of domain nodes
      Switch swit = (Switch) makeSwitch(domainLength);
      AnimationControlJ3D control = (AnimationControlJ3D)timeMap.getControl();
      
      addSwitch(group, swit, control, domainSet, renderer);


      /***
          Old code:
       // render frames
      for (int i=0; i<domainLength; i++) {
        BranchGroup node = (BranchGroup) swit.getChild(i);
        // not necessary, but perhaps if this is modified
        // int[] lat_lon_indices = renderer.getLatLonIndices();
        BranchGroup branch = (BranchGroup) makeBranch();
        recurseRange(branch, ((Field) data).getSample(i),
                     value_array, default_values, renderer);
        node.addChild(branch);
        // not necessary, but perhaps if this is modified
        // renderer.setLatLonIndices(lat_lon_indices);
      }
      ****/

      //jeffmc:First construct the branches
      List<BranchGroup> branches = new ArrayList<BranchGroup>();
      for (int i=0; i<domainLength; i++) {
          BranchGroup node = (BranchGroup) swit.getChild(i);
          BranchGroup branch = (BranchGroup) makeBranch();
          branches.add(branch);
      }

      ThreadManager threadManager = new ThreadManager("animation rendering");
      for (int i=0; i<domainLength; i++) {
          final BranchGroup branch = (BranchGroup) branches.get(i);
          final Data sample  = ((Field) data).getSample(i);
          final BranchGroup node = (BranchGroup) swit.getChild(i);
          threadManager.addRunnable(new ThreadManager.MyRunnable() {
                  public void run()  throws Exception {
                      recurseRange(branch, sample,
                                   value_array, default_values, renderer);
                      node.addChild(branch);          
                  }
              });
      }

      threadManager.runInParallel();
    } 
    else {
      ShadowFunctionOrSetType shadow = 
(ShadowFunctionOrSetType)adaptedShadowType;
      post = shadow.doTransform(group, data, value_array, default_values, 
renderer, this); 
    }
    
    ensureNotEmpty(group);
    return post;
  }

  /**
   * Get the possibly adjusted texture width.
   * @param data_width The initial texture width.
   * @return If <code>DisplayImplJ3D.TEXTURE_NPOT</code> then return
   *  <code>data_width</code>, otherwise return the minimum power of two greater
   *  than <code>data_width</code>.
   * @see DisplayImplJ3D#TEXTURE_NPOT
   */
  public int textureWidth(int data_width) {
    if (DisplayImplJ3D.TEXTURE_NPOT) return data_width;
    // must be a power of 2 in Java3D
    int texture_width = 1;
    while (texture_width < data_width) texture_width *= 2;
    return texture_width;
  }

  /**
   * Get the possibly adjusted texture height.
   * @param data_height The initial texture height.
   * @return If <code>DisplayImplJ3D.TEXTURE_NPOT</code> then return
   *  <code>data_height</code>, otherwise return the minimum power of two 
greater
   *  than <code>data_height</code>.
   * @see DisplayImplJ3D#TEXTURE_NPOT
   */
  public int textureHeight(int data_height) {
    if (DisplayImplJ3D.TEXTURE_NPOT) return data_height;
    // must be a power of 2 in Java3D
    int texture_height = 1;
    while (texture_height < data_height) texture_height *= 2;
    return texture_height;
  }

  /**
   * Get the possibly adjusted texture depth.
   * @param data_depth The initial texture depth.
   * @return If <code>DisplayImplJ3D.TEXTURE_NPOT</code> then return
   *  <code>data_depth</code>, otherwise return the minimum power of two greater
   *  than <code>data_depth</code>.
   * @see DisplayImplJ3D#TEXTURE_NPOT
   */
  public int textureDepth(int data_depth) {
    if (DisplayImplJ3D.TEXTURE_NPOT) return data_depth;
    // must be a power of 2 in Java3D
    int texture_depth = 1;
    while (texture_depth < data_depth) texture_depth *= 2;
    return texture_depth;
  }

  public void adjustZ(float[] coordinates) {
    if (display.getDisplayRenderer().getMode2D()) {
      for (int i=2; i<coordinates.length; i+=3) {
        coordinates[i] = DisplayImplJ3D.BACK2D;
      }
    }
  }

  public int getImageComponentType(int buffImgType) {
    if (buffImgType == BufferedImage.TYPE_4BYTE_ABGR) {
      return ImageComponent2D.FORMAT_RGBA8;
    }
    else if (buffImgType == BufferedImage.TYPE_3BYTE_BGR) {
      return ImageComponent2D.FORMAT_RGB8;
    }
    else if (buffImgType == BufferedImage.TYPE_BYTE_GRAY) {
      return ImageComponent2D.FORMAT_CHANNEL8;
    }
    return ImageComponent2D.FORMAT_RGBA8;
  }

  public int getTextureType(int buffImgType) {
    if (buffImgType == BufferedImage.TYPE_4BYTE_ABGR) {
      return Texture2D.RGBA;
    }
    else if (buffImgType == BufferedImage.TYPE_3BYTE_BGR) {
      return Texture2D.RGB;
    }
    else if (buffImgType == BufferedImage.TYPE_BYTE_GRAY) {
      return Texture2D.INTENSITY;
    //-return Texture2D.LUMINANCE; Not sure if this matters?
    }
    return Texture2D.RGBA;
  }

  public void setTexCoords(float[] texCoords, float ratiow, float ratioh) {
    setTexCoords(texCoords, ratiow, ratioh, false);
  }

  public void setTexCoords(float[] texCoords, float ratiow, float ratioh, 
boolean yUp) {
    if (!yUp) { // the default
      // corner 0
      texCoords[0] = 0.0f;
      texCoords[1] = 1.0f;
      // corner 1
      texCoords[2] = ratiow;
      texCoords[3] = 1.0f;
      // corner 2
      texCoords[4] = ratiow;
      texCoords[5] = 1.0f - ratioh;
      // corner 3
      texCoords[6] = 0.0f;
      texCoords[7] = 1.0f - ratioh;
    }
    else {  // yUp = true, for imageByReference=true
      // corner 0
      texCoords[0] = 0.0f;
      texCoords[1] = 0.0f;
      // corner 1
      texCoords[2] = 0.0f;
      texCoords[3] = ratioh;
      // corner 2
      texCoords[4] = ratiow;
      texCoords[5] = ratioh;
      // corner 3
      texCoords[6] = ratiow;
      texCoords[7] = 0.0f;
    }
  }

  public float[] setTex3DCoords(int length, int axis, float ratiow,
                                float ratioh, float ratiod) {
    // need to flip Y and Z in X and Y views?
    float[] texCoords = new float[12 * length];
    if (axis == 2) {
      for (int i=0; i<length; i++) {
        int i12 = i * 12;
        float depth = 0.0f + (ratiod - 0.0f) * i / (length - 1.0f);
        // corner 0
        texCoords[i12] = 0.0f;
        texCoords[i12 + 1] = 1.0f;
        texCoords[i12 + 2] = depth;
        // corner 1
        texCoords[i12 + 3] = ratiow;
        texCoords[i12 + 4] = 1.0f;
        texCoords[i12 + 5] = depth;
        // corner 2
        texCoords[i12 + 6] = ratiow;
        texCoords[i12 + 7] = 1.0f - ratioh;
        texCoords[i12 + 8] = depth;
        // corner 3
        texCoords[i12 + 9] = 0.0f;
        texCoords[i12 + 10] = 1.0f - ratioh;
        texCoords[i12 + 11] = depth;
      }
    }
    else if (axis == 1) {
      for (int i=0; i<length; i++) {
        int i12 = i * 12;
        float height = 1.0f - ratioh * i / (length - 1.0f);
        // corner 0
        texCoords[i12] = 0.0f;
        texCoords[i12 + 1] = height;
        texCoords[i12 + 2] = 0.0f;
        // corner 1
        texCoords[i12 + 3] = ratiow;
        texCoords[i12 + 4] = height;
        texCoords[i12 + 5] = 0.0f;
        // corner 2
        texCoords[i12 + 6] = ratiow;
        texCoords[i12 + 7] = height;
        texCoords[i12 + 8] = ratiod;
        // corner 3
        texCoords[i12 + 9] = 0.0f;
        texCoords[i12 + 10] = height;
        texCoords[i12 + 11] = ratiod;
      }
    }
    else if (axis == 0) {
      for (int i=0; i<length; i++) {
        int i12 = i * 12;
        float width = 0.0f + (ratiow - 0.0f) * i / (length - 1.0f);
        // corner 0
        texCoords[i12] = width;
        texCoords[i12 + 1] = 1.0f;
        texCoords[i12 + 2] = 0.0f;
        // corner 1
        texCoords[i12 + 3] = width;
        texCoords[i12 + 4] = 1.0f - ratioh;
        texCoords[i12 + 5] = 0.0f;
        // corner 2
        texCoords[i12 + 6] = width;
        texCoords[i12 + 7] = 1.0f - ratioh;
        texCoords[i12 + 8] = ratiod;
        // corner 3
        texCoords[i12 + 9] = width;
        texCoords[i12 + 10] = 1.0f;
        texCoords[i12 + 11] = ratiod;
      }
    }
    return texCoords;
  }

  // WLH 17 March 2000
  private static float EPS = 0.00f;

  public float[] setTexStackCoords(int length, int axis, float ratiow,
                                   float ratioh, float ratiod) {
    float[] texCoords = new float[8 * length];
    if (axis == 2) {
      for (int i=0; i<length; i++) {
        int i8 = i * 8;
        // corner 0
        texCoords[i8] = 0.0f + EPS;
        texCoords[i8 + 1] = 1.0f - EPS;
        // corner 1
        texCoords[i8 + 2] = ratiow - EPS;
        texCoords[i8 + 3] = 1.0f - EPS;
        // corner 2
        texCoords[i8 + 4] = ratiow - EPS;
        texCoords[i8 + 5] = 1.0f - ratioh + EPS;
        // corner 3
        texCoords[i8 + 6] = 0.0f + EPS;
        texCoords[i8 + 7] = 1.0f - ratioh + EPS;
      }
    }
    else if (axis == 1) {
      // WLH 23 Feb 2000 - flip Z
      for (int i=0; i<length; i++) {
        int i8 = i * 8;
        // corner 0
        texCoords[i8] = 0.0f + EPS;
        texCoords[i8 + 1] = 1.0f - EPS;
        // corner 1
        texCoords[i8 + 2] = ratiow - EPS;
        texCoords[i8 + 3] = 1.0f - EPS;
        // corner 2
        texCoords[i8 + 4] = ratiow - EPS;
        texCoords[i8 + 5] = 1.0f - ratiod + EPS;
        // corner 3
        texCoords[i8 + 6] = 0.0f + EPS;
        texCoords[i8 + 7] = 1.0f - ratiod + EPS;
      }
    }
    else if (axis == 0) {
      // WLH 23 Feb 2000 - flip Y and Z
      for (int i=0; i<length; i++) {
        int i8 = i * 8;
        // corner 0
        texCoords[i8] = 0.0f + EPS;
        texCoords[i8 + 1] = 1.0f - EPS;
        // corner 1
        texCoords[i8 + 2] = ratioh - EPS;
        texCoords[i8 + 3] = 1.0f - EPS;
        // corner 2
        texCoords[i8 + 4] = ratioh - EPS;
        texCoords[i8 + 5] = 1.0f - ratiod + EPS;
        // corner 3
        texCoords[i8 + 6] = 0.0f + EPS;
        texCoords[i8 + 7] = 1.0f - ratiod + EPS;
      }
    }
/* WLH 17 March 2000
    if (axis == 2) {
      for (int i=0; i<length; i++) {
        int i8 = i * 8;
        // corner 0
        texCoords[i8] = 0.0f;
        texCoords[i8 + 1] = 1.0f;
        // corner 1
        texCoords[i8 + 2] = ratiow;
        texCoords[i8 + 3] = 1.0f;
        // corner 2
        texCoords[i8 + 4] = ratiow;
        texCoords[i8 + 5] = 1.0f - ratioh;
        // corner 3
        texCoords[i8 + 6] = 0.0f;
        texCoords[i8 + 7] = 1.0f - ratioh;
      }
    }
    else if (axis == 1) {
      // WLH 23 Feb 2000 - flip Z
      for (int i=0; i<length; i++) {
        int i8 = i * 8;
        // corner 0
        texCoords[i8] = 0.0f;
        texCoords[i8 + 1] = 1.0f;
        // corner 1
        texCoords[i8 + 2] = ratiow;
        texCoords[i8 + 3] = 1.0f;
        // corner 2
        texCoords[i8 + 4] = ratiow;
        texCoords[i8 + 5] = 1.0f - ratiod;
        // corner 3
        texCoords[i8 + 6] = 0.0f;
        texCoords[i8 + 7] = 1.0f - ratiod;
      }
    }
    else if (axis == 0) {
      // WLH 23 Feb 2000 - flip Y and Z
      for (int i=0; i<length; i++) {
        int i8 = i * 8;
        // corner 0
        texCoords[i8] = 0.0f;
        texCoords[i8 + 1] = 1.0f;
        // corner 1
        texCoords[i8 + 2] = ratioh;
        texCoords[i8 + 3] = 1.0f;
        // corner 2
        texCoords[i8 + 4] = ratioh;
        texCoords[i8 + 5] = 1.0f - ratiod;
        // corner 3
        texCoords[i8 + 6] = 0.0f;
        texCoords[i8 + 7] = 1.0f - ratiod;
      }
    }
*/
    return texCoords;
  }

  public Vector getTextMaps(int i, int[] textIndices) {
    if (i < 0) {
      return ((ShadowTextTypeJ3D) Range).getSelectedMapVector();
    }
    else {
      ShadowTextTypeJ3D text = (ShadowTextTypeJ3D)
        ((ShadowTupleTypeJ3D) Range).getComponent(textIndices[i]);
      return text.getSelectedMapVector();
    }
  }

  public void textureToGroup(Object group, VisADGeometryArray array,
                            BufferedImage image, GraphicsModeControl mode,
                            float constant_alpha, float[] constant_color,
                            int texture_width, int texture_height) throws 
VisADException {
    textureToGroup(group, array, image, mode, constant_alpha, constant_color, 
texture_width, texture_height, false, false, null, false);
  }

  public void textureToGroup(Object group, VisADGeometryArray array,
                            BufferedImage image, GraphicsModeControl mode,
                            float constant_alpha, float[] constant_color,
                            int texture_width, int texture_height, 
                            boolean byReference, boolean yUp, VisADImageTile 
tile, boolean smoothen)
         throws VisADException {
    GeometryArray geometry = display.makeGeometry(array);
    // System.out.println("texture geometry");
    // create basic Appearance
    TransparencyAttributes c_alpha = null;

    if (constant_alpha == 1.0f) {
      // constant opaque alpha = NONE
      c_alpha = null;
    }
    else if (constant_alpha == constant_alpha) {
      // c_alpha = new TransparencyAttributes(mode.getTransparencyMode(),
      c_alpha = new TransparencyAttributes(TransparencyAttributes.BLENDED,
                                           constant_alpha);
        c_alpha.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE); 
//REUSE GEOMETRY/COLORBYTE REQUIREMENT
    }
    else {
      c_alpha = new TransparencyAttributes();
      c_alpha.setTransparencyMode(TransparencyAttributes.BLENDED);
        c_alpha.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE); 
//REUSE GEOMETRY/COLORBYTE REQUIREMENT
    }
    ColoringAttributes c_color = null;
    if (constant_color != null && constant_color.length == 3) {
      c_color = new ColoringAttributes();
      c_color.setColor(constant_color[0], constant_color[1], constant_color[2]);
    }
    Appearance appearance =
      makeAppearance(mode, c_alpha, null, geometry, false);
    appearance.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE); 
//REUSE GEOMETRY/COLORBYTE REQUIREMENT
    // create TextureAttributes
    TextureAttributes texture_attributes = new TextureAttributes();

    // WLH 20 June 2001
        if (smoothen) {
            texture_attributes.setTextureMode(TextureAttributes.MODULATE);
        } else {
            texture_attributes.setTextureMode(TextureAttributes.REPLACE);
        }

    texture_attributes.setPerspectiveCorrectionMode(
                          TextureAttributes.NICEST);
    appearance.setTextureAttributes(texture_attributes);
    // create Texture2D
// TextureLoader uses 1st argument = 1
/*
System.out.println("Texture.BASE_LEVEL = " + Texture.BASE_LEVEL); // 1
System.out.println("Texture.RGBA = " + Texture.RGBA); // 6
*/
    Texture2D texture = new Texture2D(Texture.BASE_LEVEL, 
getTextureType(image.getType()),
                                      texture_width, texture_height);
    texture.setCapability(Texture.ALLOW_IMAGE_READ);
    ImageComponent2D image2d =
      new ImageComponent2D(getImageComponentType(image.getType()), image, 
byReference, yUp);
    image2d.setCapability(ImageComponent.ALLOW_IMAGE_READ);
    if (byReference) {
      image2d.setCapability(ImageComponent.ALLOW_IMAGE_WRITE);
    }
    texture.setImage(0, image2d);

    //
    // from TextureLoader
    // TextureLoader uses 3 for both setMinFilter and setMagFilter
/*
System.out.println("Texture.FASTEST = " + Texture.FASTEST); // 0
System.out.println("Texture.NICEST = " + Texture.NICEST); // 1
System.out.println("Texture.BASE_LEVEL_POINT = " + Texture.BASE_LEVEL_POINT); 
// 2
System.out.println("Texture.BASE_LEVEL_LINEAR = " + Texture.BASE_LEVEL_LINEAR); 
// 3
*/
 ///for interpolation:
        if (smoothen) {
                texture.setMinFilter(Texture.BASE_LEVEL_LINEAR);
                texture.setMagFilter(Texture.BASE_LEVEL_LINEAR);
        } else {
                texture.setMinFilter(Texture.BASE_LEVEL_POINT);
                texture.setMagFilter(Texture.BASE_LEVEL_POINT);
        }
    texture.setEnable(true);
    // end of from TextureLoader
    //
    Shape3D shape = new Shape3D(geometry, appearance);
    shape.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
    shape.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);  //REUSE 
GEOMETRY/COLORBYTE REQUIREMENT
    shape.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
    appearance.setTexture(texture);
    appearance.setCapability(Appearance.ALLOW_TEXTURE_READ);
    appearance.setCapability(Appearance.ALLOW_TEXTURE_WRITE);  //REUSE 
GEOMETRY/COLORBYTE REQUIREMENT

    // WLH 6 April 2000
    // ((Group) group).addChild(shape);
    BranchGroup branch = new BranchGroup();
    branch.setCapability(BranchGroup.ALLOW_DETACH);
    branch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
    branch.addChild(shape);
    if (((Group) group).numChildren() > 0) {
      ((Group) group).setChild(branch, 0);
    }
    else {
      ((Group) group).addChild(branch);
    }

    if (tile != null) {
      tile.setImageComponent(image2d);
    }
  }

  public void texture3DToGroup(Object group, VisADGeometryArray arrayX,
                    VisADGeometryArray arrayY, VisADGeometryArray arrayZ,
                    VisADGeometryArray arrayXrev,
                    VisADGeometryArray arrayYrev,
                    VisADGeometryArray arrayZrev,
                    BufferedImage[] images, GraphicsModeControl mode,
                    float constant_alpha, float[] constant_color,
                    int texture_width, int texture_height,
                    int texture_depth, DataRenderer renderer)
         throws VisADException {

    GeometryArray geometryX = display.makeGeometry(arrayX);
    GeometryArray geometryY = display.makeGeometry(arrayY);
    GeometryArray geometryZ = display.makeGeometry(arrayZ);
    GeometryArray geometryXrev = display.makeGeometry(arrayXrev);
    GeometryArray geometryYrev = display.makeGeometry(arrayYrev);
    GeometryArray geometryZrev = display.makeGeometry(arrayZrev);
    // System.out.println("texture geometry");
    // create basic Appearance
    TransparencyAttributes c_alpha = null;

    if (constant_alpha == 1.0f) {
      // constant opaque alpha = NONE
      c_alpha = null;
    }
    else if (constant_alpha == constant_alpha) {
      // c_alpha = new TransparencyAttributes(mode.getTransparencyMode(),
      c_alpha = new TransparencyAttributes(TransparencyAttributes.BLENDED,
                                           constant_alpha);
    }
    else {
      c_alpha = new TransparencyAttributes();
      c_alpha.setTransparencyMode(TransparencyAttributes.BLENDED);
    }
    ColoringAttributes c_color = null;
    if (constant_color != null && constant_color.length == 3) {
      c_color = new ColoringAttributes();
      c_color.setColor(constant_color[0], constant_color[1], constant_color[2]);
    }
    Appearance appearance =
      makeAppearance(mode, c_alpha, null, geometryX, true);
    // create TextureAttributes
    TextureAttributes texture_attributes = new TextureAttributes();
    // texture_attributes.setTextureMode(TextureAttributes.REPLACE);
    texture_attributes.setTextureMode(TextureAttributes.MODULATE);
    texture_attributes.setPerspectiveCorrectionMode(
                          TextureAttributes.NICEST);
    appearance.setTextureAttributes(texture_attributes);
    // create Texture2D
// TextureLoader uses 1st argument = 1
/*
System.out.println("Texture.BASE_LEVEL = " + Texture.BASE_LEVEL); // 1
System.out.println("Texture.RGBA = " + Texture.RGBA); // 6
*/
    Texture3D texture = new Texture3D(Texture.BASE_LEVEL, Texture.RGBA,
                          texture_width, texture_height, texture_depth);
    texture.setCapability(Texture.ALLOW_IMAGE_READ);
    ImageComponent3D image3d =
      new ImageComponent3D(ImageComponent.FORMAT_RGBA, texture_width,
                           texture_height, texture_depth);
    image3d.setCapability(ImageComponent.ALLOW_IMAGE_READ);
    for (int i=0; i<texture_depth; i++) {
      image3d.set(i, images[i]);
      images[i] = null; // take out the garbage
    }
    texture.setImage(0, image3d);
    //
    // from TextureLoader
    // TextureLoader uses 3 for both setMinFilter and setMagFilter
/*
System.out.println("Texture.FASTEST = " + Texture.FASTEST); // 0
System.out.println("Texture.NICEST = " + Texture.NICEST); // 1
System.out.println("Texture.BASE_LEVEL_POINT = " + Texture.BASE_LEVEL_POINT); 
// 2
System.out.println("Texture.BASE_LEVEL_LINEAR = " + Texture.BASE_LEVEL_LINEAR); 
// 3
*/
/* for interpolation: */
    texture.setMinFilter(Texture.BASE_LEVEL_LINEAR);
    texture.setMagFilter(Texture.BASE_LEVEL_LINEAR);
/* for sampling:
    texture.setMinFilter(Texture.BASE_LEVEL_POINT);
    texture.setMagFilter(Texture.BASE_LEVEL_POINT);
*/
    texture.setEnable(true);
    // end of from TextureLoader

    // OK to share appearance ??
    Shape3D shapeX = new Shape3D(geometryX, appearance);
    shapeX.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
    Shape3D shapeY = new Shape3D(geometryY, appearance);
    shapeY.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
    Shape3D shapeZ = new Shape3D(geometryZ, appearance);
    shapeZ.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
    Shape3D shapeXrev = new Shape3D(geometryXrev, appearance);
    Shape3D shapeYrev = new Shape3D(geometryYrev, appearance);
    Shape3D shapeZrev = new Shape3D(geometryZrev, appearance);
    appearance.setTexture(texture);
    appearance.setCapability(Appearance.ALLOW_TEXTURE_READ);

    shapeX.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
    shapeX.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
    shapeY.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
    shapeY.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
    shapeZ.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
    shapeZ.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
    shapeXrev.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
    shapeXrev.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
    shapeYrev.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
    shapeYrev.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
    shapeZrev.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
    shapeZrev.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
    
    Switch swit = (Switch) makeSwitch();
    swit.addChild(shapeX);
    swit.addChild(shapeY);
    swit.addChild(shapeZ);
    swit.addChild(shapeXrev);
    swit.addChild(shapeYrev);
    swit.addChild(shapeZrev);

    // WLH 6 April 2000
    // ((Group) group).addChild(swit);
    BranchGroup branch = new BranchGroup();
    branch.setCapability(BranchGroup.ALLOW_DETACH);
    branch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
    branch.addChild(swit);
    if (((Group) group).numChildren() > 0) {
      ((Group) group).setChild(branch, 0);
    }
    else {
      ((Group) group).addChild(branch);
    }

    ProjectionControlJ3D control =
      (ProjectionControlJ3D) display.getProjectionControl();
    control.addPair(swit, renderer);
  }

  public void textureStackToGroup(Object group, VisADGeometryArray arrayX,
                    VisADGeometryArray arrayY, VisADGeometryArray arrayZ,
                    VisADGeometryArray arrayXrev,
                    VisADGeometryArray arrayYrev,
                    VisADGeometryArray arrayZrev,
                    BufferedImage[] imagesX,
                    BufferedImage[] imagesY,
                    BufferedImage[] imagesZ,
                    GraphicsModeControl mode,
                    float constant_alpha, float[] constant_color,
                    int texture_width, int texture_height,
                    int texture_depth, DataRenderer renderer)
         throws VisADException {

    GeometryArray[] geometryX = makeGeometrys(arrayX);
    GeometryArray[] geometryY = makeGeometrys(arrayY);
    GeometryArray[] geometryZ = makeGeometrys(arrayZ);
/* not needed ??
    GeometryArray[] geometryXrev = makeGeometrys(arrayXrev);
    GeometryArray[] geometryYrev = makeGeometrys(arrayYrev);
    GeometryArray[] geometryZrev = makeGeometrys(arrayZrev);
*/

    int nx = arrayX.coordinates.length;
    boolean flipX = (arrayX.coordinates[0] > arrayX.coordinates[nx-3]);
    int ny = arrayY.coordinates.length;
    boolean flipY = (arrayY.coordinates[1] > arrayY.coordinates[ny-2]);
    int nz = arrayZ.coordinates.length;
    boolean flipZ = (arrayZ.coordinates[2] > arrayZ.coordinates[nz-1]);
    // System.out.println("flipX = " + flipX + " flipY = " + flipY +
    //                    " flipZ = " + flipZ);

    // create Attributes for Appearances
    TransparencyAttributes c_alpha = null;
    if (constant_alpha == 1.0f) {
      // constant opaque alpha = NONE
      c_alpha = null;
    }
    else if (constant_alpha == constant_alpha) {
      // c_alpha = new TransparencyAttributes(mode.getTransparencyMode(),
      c_alpha = new TransparencyAttributes(TransparencyAttributes.BLENDED,
                                           constant_alpha);
    }
    else {
      c_alpha = new TransparencyAttributes();
      c_alpha.setTransparencyMode(TransparencyAttributes.BLENDED);
    }
    ColoringAttributes c_color = null;
    if (constant_color != null && constant_color.length == 3) {
      c_color = new ColoringAttributes();
      c_color.setColor(constant_color[0], constant_color[1], constant_color[2]);
    }
    TextureAttributes texture_attributes = new TextureAttributes();

    // WLH 17 March 2000
    // texture_attributes.setTextureMode(TextureAttributes.MODULATE);
    texture_attributes.setTextureMode(TextureAttributes.REPLACE);

    texture_attributes.setPerspectiveCorrectionMode(
                          TextureAttributes.NICEST);

    int transparencyMode = mode.getTransparencyMode();

    OrderedGroup branchX = new OrderedGroup();
    branchX.setCapability(Group.ALLOW_CHILDREN_READ);
    int data_depth = geometryX.length;
    Shape3D[] shapeX = new Shape3D[data_depth];
    for (int ii=0; ii<data_depth; ii++) {
      int i = flipX ? data_depth-1-ii : ii;
      int width = imagesX[i].getWidth();
      int height = imagesX[i].getHeight();
      Texture2D texture = new Texture2D(Texture.BASE_LEVEL, Texture.RGBA,
                                        width, height);
      texture.setCapability(Texture.ALLOW_IMAGE_READ);
      ImageComponent2D image2d =
        new ImageComponent2D(ImageComponent.FORMAT_RGBA, imagesX[i]);
      image2d.setCapability(ImageComponent.ALLOW_IMAGE_READ);
      texture.setImage(0, image2d);
      Appearance appearance =
        makeAppearance(mode, c_alpha, null, geometryX[i], true);
      appearance.setTextureAttributes(texture_attributes);
      // WLH 17 March 2000
      if (transparencyMode == TransparencyAttributes.FASTEST) {
        texture.setMinFilter(Texture.BASE_LEVEL_POINT);
        texture.setMagFilter(Texture.BASE_LEVEL_POINT);
      }
      else {
        texture.setBoundaryModeS(Texture.CLAMP);
        texture.setBoundaryModeT(Texture.CLAMP);
        texture.setMinFilter(Texture.BASE_LEVEL_LINEAR);
        texture.setMagFilter(Texture.BASE_LEVEL_LINEAR);
      }
      texture.setEnable(true);
      appearance.setTexture(texture);
      appearance.setCapability(Appearance.ALLOW_TEXTURE_READ);
      shapeX[i] = new Shape3D(geometryX[i], appearance);
      shapeX[i].setCapability(Shape3D.ALLOW_GEOMETRY_READ);
      shapeX[i].setCapability(Shape3D.ALLOW_APPEARANCE_READ);
      branchX.addChild(shapeX[i]);
    }
    OrderedGroup branchXrev = new OrderedGroup();
    branchXrev.setCapability(Group.ALLOW_CHILDREN_READ);
    for (int ii=data_depth-1; ii>=0; ii--) {
      int i = flipX ? data_depth-1-ii : ii;
      int width = imagesX[i].getWidth();
      int height = imagesX[i].getHeight();
      Texture2D texture = new Texture2D(Texture.BASE_LEVEL, Texture.RGBA,
                                        width, height);
      texture.setCapability(Texture.ALLOW_IMAGE_READ);
      ImageComponent2D image2d =
        new ImageComponent2D(ImageComponent.FORMAT_RGBA, imagesX[i]);
      image2d.setCapability(ImageComponent.ALLOW_IMAGE_READ);
      texture.setImage(0, image2d);
      Appearance appearance =
        makeAppearance(mode, c_alpha, null, geometryX[i], true);
      appearance.setTextureAttributes(texture_attributes);
      // WLH 17 March 2000
      if (transparencyMode == TransparencyAttributes.FASTEST) {
        texture.setMinFilter(Texture.BASE_LEVEL_POINT);
        texture.setMagFilter(Texture.BASE_LEVEL_POINT);
      }
      else {
        texture.setBoundaryModeS(Texture.CLAMP);
        texture.setBoundaryModeT(Texture.CLAMP);
        texture.setMinFilter(Texture.BASE_LEVEL_LINEAR);
        texture.setMagFilter(Texture.BASE_LEVEL_LINEAR);
      }
      texture.setEnable(true);
      appearance.setTexture(texture);
      appearance.setCapability(Appearance.ALLOW_TEXTURE_READ);
      shapeX[i] = new Shape3D(geometryX[i], appearance);
      shapeX[i].setCapability(Shape3D.ALLOW_GEOMETRY_READ);
      shapeX[i].setCapability(Shape3D.ALLOW_APPEARANCE_READ);
      branchXrev.addChild(shapeX[i]);
    }
    shapeX = null;

    OrderedGroup branchY = new OrderedGroup();
    branchY.setCapability(Group.ALLOW_CHILDREN_READ);
    int data_height = geometryY.length;
    Shape3D[] shapeY = new Shape3D[data_height];
    for (int ii=0; ii<data_height; ii++) {
      int i = flipY ? data_height-1-ii : ii;
      int width = imagesY[i].getWidth();
      int height = imagesY[i].getHeight();
      Texture2D texture = new Texture2D(Texture.BASE_LEVEL, Texture.RGBA,
                                        width, height);
      texture.setCapability(Texture.ALLOW_IMAGE_READ);
      // flip texture on Y axis
      ImageComponent2D image2d =
        new ImageComponent2D(ImageComponent.FORMAT_RGBA, imagesY[i]);
      image2d.setCapability(ImageComponent.ALLOW_IMAGE_READ);
      texture.setImage(0, image2d);
      Appearance appearance =
        makeAppearance(mode, c_alpha, null, geometryY[i], true);
      appearance.setTextureAttributes(texture_attributes);
      // WLH 17 March 2000
      if (transparencyMode == TransparencyAttributes.FASTEST) {
        texture.setMinFilter(Texture.BASE_LEVEL_POINT);
        texture.setMagFilter(Texture.BASE_LEVEL_POINT);
      }
      else {
        texture.setBoundaryModeS(Texture.CLAMP);
        texture.setBoundaryModeT(Texture.CLAMP);
        texture.setMinFilter(Texture.BASE_LEVEL_LINEAR);
        texture.setMagFilter(Texture.BASE_LEVEL_LINEAR);
      }
      texture.setEnable(true);
      appearance.setTexture(texture);
      appearance.setCapability(Appearance.ALLOW_TEXTURE_READ);
      shapeY[i] = new Shape3D(geometryY[i], appearance);
      shapeY[i].setCapability(Shape3D.ALLOW_GEOMETRY_READ);
      shapeY[i].setCapability(Shape3D.ALLOW_APPEARANCE_READ);
      branchY.addChild(shapeY[i]);
    }
    OrderedGroup branchYrev = new OrderedGroup();
    branchYrev.setCapability(Group.ALLOW_CHILDREN_READ);
    for (int ii=data_height-1; ii>=0; ii--) {
      int i = flipY ? data_height-1-ii : ii;
      int width = imagesY[i].getWidth();
      int height = imagesY[i].getHeight();
      Texture2D texture = new Texture2D(Texture.BASE_LEVEL, Texture.RGBA,
                                        width, height);
      texture.setCapability(Texture.ALLOW_IMAGE_READ);
      // flip texture on Y axis
      ImageComponent2D image2d =
        new ImageComponent2D(ImageComponent.FORMAT_RGBA, imagesY[i]);
      image2d.setCapability(ImageComponent.ALLOW_IMAGE_READ);
      texture.setImage(0, image2d);
      Appearance appearance =
        makeAppearance(mode, c_alpha, null, geometryY[i], true);
      appearance.setTextureAttributes(texture_attributes);
      // WLH 17 March 2000
      if (transparencyMode == TransparencyAttributes.FASTEST) {
        texture.setMinFilter(Texture.BASE_LEVEL_POINT);
        texture.setMagFilter(Texture.BASE_LEVEL_POINT);
      }
      else {
        texture.setBoundaryModeS(Texture.CLAMP);
        texture.setBoundaryModeT(Texture.CLAMP);
        texture.setMinFilter(Texture.BASE_LEVEL_LINEAR);
        texture.setMagFilter(Texture.BASE_LEVEL_LINEAR);
      }
      texture.setEnable(true);
      appearance.setTexture(texture);
      appearance.setCapability(Appearance.ALLOW_TEXTURE_READ);
      shapeY[i] = new Shape3D(geometryY[i], appearance);
      shapeY[i].setCapability(Shape3D.ALLOW_GEOMETRY_READ);
      shapeY[i].setCapability(Shape3D.ALLOW_APPEARANCE_READ);
      branchYrev.addChild(shapeY[i]);
    }
    shapeY = null;

    OrderedGroup branchZ = new OrderedGroup();
    branchZ.setCapability(Group.ALLOW_CHILDREN_READ);
    int data_width = geometryZ.length;
    Shape3D[] shapeZ = new Shape3D[data_width];
    for (int ii=0; ii<data_width; ii++) {
      int i = flipZ ? data_width-1-ii : ii;
      int width = imagesZ[i].getWidth();
      int height = imagesZ[i].getHeight();
      Texture2D texture = new Texture2D(Texture.BASE_LEVEL, Texture.RGBA,
                                        width, height);
      texture.setCapability(Texture.ALLOW_IMAGE_READ);
      ImageComponent2D image2d =
        new ImageComponent2D(ImageComponent.FORMAT_RGBA, imagesZ[i]);
      image2d.setCapability(ImageComponent.ALLOW_IMAGE_READ);
      texture.setImage(0, image2d);
      Appearance appearance =
        makeAppearance(mode, c_alpha, null, geometryZ[i], true);
      appearance.setTextureAttributes(texture_attributes);
      // WLH 17 March 2000
      if (transparencyMode == TransparencyAttributes.FASTEST) {
        texture.setMinFilter(Texture.BASE_LEVEL_POINT);
        texture.setMagFilter(Texture.BASE_LEVEL_POINT);
      }
      else {
        texture.setBoundaryModeS(Texture.CLAMP);
        texture.setBoundaryModeT(Texture.CLAMP);
        texture.setMinFilter(Texture.BASE_LEVEL_LINEAR);
        texture.setMagFilter(Texture.BASE_LEVEL_LINEAR);
      }
      texture.setEnable(true);
      appearance.setTexture(texture);
      appearance.setCapability(Appearance.ALLOW_TEXTURE_READ);
      shapeZ[i] = new Shape3D(geometryZ[i], appearance);
      shapeZ[i].setCapability(Shape3D.ALLOW_GEOMETRY_READ);
      shapeZ[i].setCapability(Shape3D.ALLOW_APPEARANCE_READ);
      branchZ.addChild(shapeZ[i]);
    }
    OrderedGroup branchZrev = new OrderedGroup();
    branchZrev.setCapability(Group.ALLOW_CHILDREN_READ);
    for (int ii=data_width-1; ii>=0; ii--) {
      int i = flipZ ? data_width-1-ii : ii;
      int width = imagesZ[i].getWidth();
      int height = imagesZ[i].getHeight();
      Texture2D texture = new Texture2D(Texture.BASE_LEVEL, Texture.RGBA,
                                        width, height);
      texture.setCapability(Texture.ALLOW_IMAGE_READ);
      ImageComponent2D image2d =
        new ImageComponent2D(ImageComponent.FORMAT_RGBA, imagesZ[i]);
      image2d.setCapability(ImageComponent.ALLOW_IMAGE_READ);
      texture.setImage(0, image2d);
      Appearance appearance =
        makeAppearance(mode, c_alpha, null, geometryZ[i], true);
      appearance.setTextureAttributes(texture_attributes);
      // WLH 17 March 2000
      if (transparencyMode == TransparencyAttributes.FASTEST) {
        texture.setMinFilter(Texture.BASE_LEVEL_POINT);
        texture.setMagFilter(Texture.BASE_LEVEL_POINT);
      }
      else {
        texture.setBoundaryModeS(Texture.CLAMP);
        texture.setBoundaryModeT(Texture.CLAMP);
        texture.setMinFilter(Texture.BASE_LEVEL_LINEAR);
        texture.setMagFilter(Texture.BASE_LEVEL_LINEAR);
      }
      texture.setEnable(true);
      appearance.setTexture(texture);
      appearance.setCapability(Appearance.ALLOW_TEXTURE_READ);
      shapeZ[i] = new Shape3D(geometryZ[i], appearance);
      shapeZ[i].setCapability(Shape3D.ALLOW_GEOMETRY_READ);
      shapeZ[i].setCapability(Shape3D.ALLOW_APPEARANCE_READ);
      branchZrev.addChild(shapeZ[i]);
    }
    shapeZ = null;

    Switch swit = (Switch) makeSwitch();
    swit.addChild(branchX);
    swit.addChild(branchY);
    swit.addChild(branchZ);
    swit.addChild(branchXrev);
    swit.addChild(branchYrev);
    swit.addChild(branchZrev);

    // WLH 6 April 2000
    // ((Group) group).addChild(swit);
    BranchGroup branch = new BranchGroup();
    branch.setCapability(BranchGroup.ALLOW_DETACH);
    branch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
    branch.addChild(swit);
    if (((Group) group).numChildren() > 0) {
      ((Group) group).setChild(branch, 0);
    }
    else {
      ((Group) group).addChild(branch);
    }

    ProjectionControlJ3D control =
      (ProjectionControlJ3D) display.getProjectionControl();
    control.addPair(swit, renderer);
  }

/*
  GeometryArray[] makeGeometrys(VisADGeometryArray array)
                  throws VisADException {
    int count = array.vertexCount;
    int depth = count / 4;
    int color_length = array.colors.length / count;
    int tex_length = array.texCoords.length / count;

    GeometryArray[] geometrys = new GeometryArray[depth];
    for (int d=0; d<depth; d++) {
      int i12 = d * 4 * 3;
      int i4c = d * 4 * color_length;
      int i4t = d * 4 * tex_length;
      VisADQuadArray qarray = new VisADQuadArray();
      qarray.vertexCount = 4;
      qarray.coordinates = new float[12];
      qarray.texCoords = new float[tex_length * 4];
      qarray.colors = new byte[color_length * 4];
      qarray.normals = new float[12];
      for (int i=0; i<12; i++) {
        qarray.coordinates[i] = array.coordinates[i12 + i];
        qarray.normals[i] = array.normals[i12 + i];
      }
      for (int i=0; i<4*color_length; i++) {
        qarray.colors[i] = array.colors[i4c + i];
      }
      for (int i=0; i<4*tex_length; i++) {
        qarray.texCoords[i] = array.texCoords[i4t + i];
      }
      geometrys[d] = display.makeGeometry(qarray);
    }
    return geometrys;
  }
*/

  public GeometryArray[] makeGeometrys(VisADGeometryArray array)
                  throws VisADException {
    int count = array.vertexCount;
    int depth = count / 4;
    VisADGeometryArray[] qarrays = makeVisADGeometrys(array);
    GeometryArray[] geometrys = new GeometryArray[depth];
    for (int d=0; d<depth; d++) {
      geometrys[d] = display.makeGeometry(qarrays[d]);
    }
    return geometrys;
  }

  public VisADGeometryArray[] makeVisADGeometrys(VisADGeometryArray array)
                  throws VisADException {
    int count = array.vertexCount;
    int depth = count / 4;
    int color_length = array.colors.length / count;
    int tex_length = array.texCoords.length / count;

    VisADGeometryArray[] geometrys = new VisADGeometryArray[depth];
    for (int d=0; d<depth; d++) {
      int i12 = d * 4 * 3;
      int i4c = d * 4 * color_length;
      int i4t = d * 4 * tex_length;
      VisADQuadArray qarray = new VisADQuadArray();
      qarray.vertexCount = 4;
      qarray.coordinates = new float[12];
      qarray.texCoords = new float[tex_length * 4];
      qarray.colors = new byte[color_length * 4];
      qarray.normals = new float[12];
      for (int i=0; i<12; i++) {
        qarray.coordinates[i] = array.coordinates[i12 + i];
        qarray.normals[i] = array.normals[i12 + i];
      }
      for (int i=0; i<4*color_length; i++) {
        qarray.colors[i] = array.colors[i4c + i];
      }
      for (int i=0; i<4*tex_length; i++) {
        qarray.texCoords[i] = array.texCoords[i4t + i];
      }
      geometrys[d] = qarray;
    }
    return geometrys;
  }

  public Object makeSwitch() {
    Switch swit = new Switch();
    swit.setCapability(Switch.ALLOW_SWITCH_READ);
    swit.setCapability(Switch.ALLOW_SWITCH_WRITE);
    swit.setCapability(BranchGroup.ALLOW_DETACH);
    swit.setCapability(Group.ALLOW_CHILDREN_READ);
    swit.setCapability(Group.ALLOW_CHILDREN_WRITE);
    return swit;
  }

  public Object makeSwitch(int length) throws VisADException {
    Switch swit = (Switch)makeSwitch();

//  -TDR
    swit.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
    for (int i=0; i<length; i++) {
      BranchGroup node = new BranchGroup();
      node.setCapability(BranchGroup.ALLOW_DETACH);
      node.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
      node.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
      node.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
      ensureNotEmpty(node);
      addToSwitch(swit, node);
    }
    return swit;
  }
  
  public Object makeBranch() {
    BranchGroup branch = new BranchGroup();
    branch.setCapability(BranchGroup.ALLOW_DETACH);
    branch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
    return branch;
  }

  public void addToGroup(Object group, Object branch)
         throws VisADException {
/* WLH 18 Aug 98
   empty BranchGroup or Shape3D may cause NullPointerException
   from Shape3DRetained.setLive
*/
    ensureNotEmpty((BranchGroup) branch);
    ((BranchGroup) group).addChild((BranchGroup) branch);
  }

  public void addToSwitch(Object swit, Object branch)
         throws VisADException {
/* WLH 18 Aug 98
   empty BranchGroup or Shape3D may cause NullPointerException
   from Shape3DRetained.setLive
*/
    ensureNotEmpty((BranchGroup) branch);
    ((Switch) swit).addChild((BranchGroup) branch);
  }

  public void addSwitch(Object group, Object swit, Control control,
                        Set domain_set, DataRenderer renderer)
         throws VisADException {
    ((AVControlJ3D) control).addPair((Switch) swit, domain_set, renderer);
    ((AVControlJ3D) control).init();
    // WLH 06 Feb 06 - fix problem adding a new switch to an existing group
    // ((Group) group).addChild((Switch) swit);
    BranchGroup branch = new BranchGroup();
    branch.setCapability(BranchGroup.ALLOW_DETACH);
    branch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
    branch.addChild((Switch) swit);
    ((Group) group).addChild(branch);

  }

  public boolean recurseRange(Object group, Data data, float[] value_array,
                             float[] default_values, DataRenderer renderer)
         throws VisADException, RemoteException {
    return Range.doTransform(group, data, value_array,
                             default_values, renderer);
  }

  public boolean wantIndexed() {
/* doesn't seem to matter to memory use
    return true;
*/
    return false;
  }


  /** render accumulated Vector of value_array-s to
      and add to group; then clear AccumulationVector */
  public void postProcess(Object group) throws VisADException {
    if (((ShadowFunctionOrSetType) adaptedShadowType).getFlat()) {
      int LevelOfDifficulty = getLevelOfDifficulty();
      if (LevelOfDifficulty == LEGAL) {
        throw new UnimplementedException("terminal LEGAL unimplemented: " +
                                         
"ShadowFunctionOrSetTypeJ3D.postProcess");
      }
      else {
        // includes !isTerminal
        // nothing to do
      }
    }
    else {
      if (this instanceof ShadowFunctionTypeJ3D) {
        Range.postProcess(group);
      }
    }
    AccumulationVector.removeAllElements();
  }

}

//
// ShadowImageByRefFunctionTypeJ3D.java
//

/*
VisAD system for interactive analysis and visualization of numerical
data.  Copyright (C) 1996 - 2009 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/

package visad.bom;

import visad.*;
import visad.data.CachedBufferedByteImage;
import visad.java3d.*;
import visad.data.mcidas.BaseMapAdapter;
import visad.data.mcidas.AreaAdapter;
import visad.data.gif.GIFForm;
import visad.util.Util;

import javax.media.j3d.*;

import java.io.*;

import java.util.Arrays;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Iterator;
import java.util.ArrayList;
import java.rmi.*;

import java.net.URL;

import java.awt.event.*;
import javax.swing.*;
import java.awt.color.*;
import java.awt.image.*;

/**
   The ShadowImageFunctionTypeJ3D class shadows the FunctionType class for
   ImageRendererJ3D, within a DataDisplayLink, under Java3D.<P>
*/
public class ShadowImageByRefFunctionTypeJ3D extends ShadowFunctionTypeJ3D {

  private static final int MISSING1 = Byte.MIN_VALUE;      // least byte

  private VisADImageNode imgNode = null;
  private VisADImageNode prevImgNode = null;
  private int prevDataWidth = -1;
  private int prevDataHeight = -1;
  private int prevNumImages = -1;

  //- Ghansham (New variables introduced to preserve scaled values and 
colorTables)
  private byte scaled_Bytes[][];  //scaled byte values 
  private float scaled_Floats[][];  //scaled Float Values
  private float rset_scalarmap_lookup[][]; //GHANSHAM:30AUG2011 create a lookup 
for rset FlatField range values

  private byte[][] itable; //For single band
  private byte[][] fast_table; //For fast_lookup
  private byte[][][] threeD_itable; //for multiband

  private float[][] color_values; //special case
  private boolean first_time; //This variable indicates the first tile of the 
image.
  private float topo_samples[];
  
//------------------------------------------------------------------------------

  AnimationControlJ3D animControl = null;

  private boolean reuse = false;
  private boolean reuseImages = false;

  int[] inherited_values = null;
  ShadowFunctionOrSetType adaptedShadowType = null;
  int levelOfDifficulty = -1;

  //REUSE GEOMETRY/COLORBYTE VARIABLES (STARTS HERE)
  boolean regen_colbytes = false;
  boolean regen_geom = false;
  boolean apply_alpha = false;
  //REUSE GEOMETRY/COLORBYTE VARIABLES (ENDS HERE)

  public ShadowImageByRefFunctionTypeJ3D(MathType t, DataDisplayLink link, 
ShadowType parent) 
         throws VisADException, RemoteException {
    super(t, link, parent);
  }

  public ShadowImageByRefFunctionTypeJ3D(MathType t, DataDisplayLink link, 
ShadowType parent,
                  int[] inherited_values, ShadowFunctionOrSetType 
adaptedShadowType, int levelOfDifficulty)
         throws VisADException, RemoteException {
    super(t, link, parent);
    this.inherited_values  = inherited_values;
    this.adaptedShadowType = adaptedShadowType;
    this.levelOfDifficulty = levelOfDifficulty;
  }

  //REUSE GEOMETRY/COLORBYTE UTILITY METHODS (STARTS HERE)
   /*This method returns two things:
        1. whether any spatial maps has return true in checkTicks() function 
        2. Current ZAxis value 
  */
  private Object[] findSpatialMapTicksAndCurrZValue(ShadowFunctionOrSetType 
MyAdaptedShadowType, DisplayImpl display, 
                                      float  default_values[], float 
value_array[], int valueToScalar[], DataRenderer renderer, 
                                      DataDisplayLink link, int 
valueArrayLength) throws VisADException, DisplayException {
    ShadowRealTupleType Domain = MyAdaptedShadowType.getDomain();
    ShadowRealType[] DomainComponents = 
MyAdaptedShadowType.getDomainComponents();
    ShadowRealTupleType domain_reference = Domain.getReference();
    ShadowRealType[] DC = DomainComponents;
    if (domain_reference != null && domain_reference.getMappedDisplayScalar()) {
        DC = MyAdaptedShadowType.getDomainReferenceComponents();
    }

    int[] tuple_index = new int[3];
    DisplayTupleType spatial_tuple = null;
    boolean spatial_maps_check_ticks = false;
    for (int i=0; i<DC.length; i++) {
      Enumeration maps = DC[i].getSelectedMapVector().elements();
      ScalarMap map = (ScalarMap) maps.nextElement();
      if (map.checkTicks(renderer, link)) {
              spatial_maps_check_ticks = true;
      }
      DisplayRealType real = map.getDisplayScalar();
      spatial_tuple = real.getTuple();
      if (spatial_tuple == null) {
        /*throw new DisplayException("texture with bad tuple: " +
                                   "ShadowImageFunctionTypeJ3D.doTransform");*/
        return null;
      }
      tuple_index[i] = real.getTupleIndex();
      if (maps.hasMoreElements()) {
        /*throw new DisplayException("texture with multiple spatial: " +
                                   "ShadowImageFunctionTypeJ3D.doTransform");*/
        return null;
      }
    } 


    // get spatial index not mapped from domain_set
    tuple_index[2] = 3 - (tuple_index[0] + tuple_index[1]);
    DisplayRealType real = (DisplayRealType) 
spatial_tuple.getComponent(tuple_index[2]);
    int value2_index = display.getDisplayScalarIndex(real);
    float value2 = default_values[value2_index];
    for (int i=0; i<valueArrayLength; i++) {
      if (inherited_values[i] > 0 && 
real.equals(display.getDisplayScalar(valueToScalar[i])) ) {
        value2 = value_array[i];
        break;
      }
    }
    tuple_index = null;
    Object ret_values[] = new Object[2];
    ret_values[0] = spatial_maps_check_ticks;
    ret_values[1] = value2;
    return ret_values;
  }

  /*This method retuns whether any of the rangemap has return true in 
checkTicks()*/
  private boolean findRadianceMapColorControlCheckTicks(ScalarMap cmap, 
ScalarMap cmaps[], DataRenderer renderer, DataDisplayLink link) {
        BaseColorControl cc;
        boolean color_map_changed = false;
        if (cmap!= null) {
                cc = (BaseColorControl) cmap.getControl();
                color_map_changed = (cmap.checkTicks(renderer, link) || 
cc.checkTicks(renderer,link));
        } else if (cmaps !=null) {
                for (int i = 0; i < cmaps.length; i++) {
                        cc = (BaseColorControl) cmaps[i].getControl();
                        if (null != cc) {
                                if (cc.checkTicks(renderer,link) || 
cmaps[i].checkTicks(renderer, link)) {
                                        color_map_changed = true;
                                        break;
                                }
                        } else {
                                if (cmaps[i].checkTicks(renderer, link)) {
                                        color_map_changed = true;
                                        break;
                                }
                        }
                }
        }
        return color_map_changed;
  }
  /*This method just applies the texture on the already generated geometry.
    This is used when only colorbytes are generated and geometry is reused. 
    This does away with buildTexture(Linear/Curve) when geometry is reused */
  private void applyTexture(Shape3D shape, VisADImageTile tile, boolean 
apply_alpha, float constant_alpha) {
        Appearance app = shape.getAppearance();
        if (regen_colbytes) {
              if (animControl == null) {
                  imgNode.setCurrent(0);
              }
        }

        if (apply_alpha) {
            TransparencyAttributes transp_attribs = 
app.getTransparencyAttributes();
            if (null == transp_attribs) {
                transp_attribs = new TransparencyAttributes();
                
transp_attribs.setTransparencyMode(TransparencyAttributes.BLENDED);
                transp_attribs.setTransparency(constant_alpha);
                
transp_attribs.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE);
                app.setTransparencyAttributes(transp_attribs);
            } else {
                transp_attribs.setTransparency(constant_alpha);
            }
        }
  }


    /* This is the real nasty logic that decides following things:
        1. Regenerate gometry
        2. Regenerate ColorBytes
        3. Change in alpha
        Before doing this it inializes range ScalarMaps, constant_alpha value.
        It also takes out the terminal ShadowType required in case of animations
    */
        //GHANSHAM:30AUG2011 Changed the signaure of initRegenFlags.. passing 
the ShadowFunctionOrSetType, constant_lapha, cmap and cmaps
  private void initRegenFlags(ImageRendererJ3D imgRenderer, 
ShadowFunctionOrSetType MyAdaptedShadowType, 
                        float constant_alpha, ScalarMap cmap, ScalarMap 
cmaps[], Data data, DisplayImpl display, 
                        float default_values[], float[] value_array, int 
[]valueToScalar, int valueArrayLength, 
                        //DataDisplayLink link, int curved_size) throws 
BadMappingException, VisADException {
                        DataDisplayLink link, int curved_size, ScalarMap 
topo_map) throws BadMappingException, VisADException {
        
        /*The nasty logic starts from here
                Retrieves the curve size, zaxis value, alpha, ff hashcode  
value from Renderer class.
                Compares them with current values and does other checks.
                Finally store the current values for above variables in the 
renderer class.*/
        int last_curve_size = imgRenderer.getLastCurveSize();
        float last_zaxis_value = imgRenderer.getLastZAxisValue();
        float last_alpha_value = imgRenderer.getLastAlphaValue();
        long last_data_hash_code = imgRenderer.getLastDataHashCode();
        long current_data_hash_code = data.hashCode();
        
        boolean last_adjust_projection_seam = 
imgRenderer.getLastAdjustProjectionSeam(); //27FEB2012: Projection Seam Change 
Bug Fix
        boolean current_adjust_projection_seam = 
adaptedShadowType.getAdjustProjectionSeam(); //27FEB2012: Projection Seam 
Change Bug Fix
        
        Object map_ticks_z_value[] = 
findSpatialMapTicksAndCurrZValue(MyAdaptedShadowType, display, default_values, 
value_array, valueToScalar, imgRenderer, link, valueArrayLength);
        if (null == map_ticks_z_value) {
                return;
        }
        float current_zaxis_value = 
Float.parseFloat(map_ticks_z_value[1].toString());
        if ((-1 != last_curve_size) && Float.isNaN(last_zaxis_value) && (-1 == 
last_data_hash_code)) { //First Time
                regen_colbytes = true;
                regen_geom = true;
                apply_alpha = true;
        } else {
                boolean data_hash_code_changed = (current_data_hash_code != 
last_data_hash_code);
                if (data_hash_code_changed) { //dataref.setData()
                        regen_colbytes = true;
                        regen_geom = true;
                        apply_alpha =true;
                } else {
                        boolean spatial_maps_check_ticks = 
Boolean.parseBoolean(map_ticks_z_value[0].toString());
                        boolean zaxis_value_changed = 
(Float.compare(last_zaxis_value, current_zaxis_value) != 0);
                        boolean curve_texture_value_change = (last_curve_size 
!= curved_size);
                        boolean alpha_changed = (Float.compare(constant_alpha, 
last_alpha_value) != 0);
                        boolean radiancemap_colcontrol_check_ticks = 
findRadianceMapColorControlCheckTicks(cmap, cmaps, imgRenderer, link);
                        boolean projection_seam_changed = 
(current_adjust_projection_seam != last_adjust_projection_seam); //27FEB2012: 
Projection Seam Change Bug Fix
                        if  (spatial_maps_check_ticks ||  zaxis_value_changed 
|| curve_texture_value_change || projection_seam_changed) { //change in 
geometry 27FEB2012: Projection Seam Change Bug Fix
                                regen_geom = true;
                        } else if (alpha_changed) { //change in alpha value
                                apply_alpha = true;
                        } else if (radiancemap_colcontrol_check_ticks) { 
//change in Radiance ScalarMaps or ColorTable
                                regen_colbytes = true;
                                regen_geom = (null != topo_map);
                        } else { //Assuming that ff.setSamples() has been 
called.
                                regen_colbytes = true;
                                regen_geom = (null != topo_map);
                        }
                }
        }
        imgRenderer.setLastCurveSize(curved_size);
        imgRenderer.setLastZAxisValue(current_zaxis_value);
        imgRenderer.setLastAlphaValue(constant_alpha);
        
imgRenderer.setLastAdjustProjectionSeam(current_adjust_projection_seam); 
//27FEB2012: Projection Seam Change Bug Fix
        imgRenderer.setLastDataHashCode(current_data_hash_code);
    }
    //REUSE GEOMETRY/COLORBYTE UTILITY METHODS (ENDS HERE)

  // transform data into a depiction under group
  public boolean doTransform(Object group, Data data, float[] value_array,
                             float[] default_values, DataRenderer renderer)
         throws VisADException, RemoteException {
        
        DataDisplayLink link = renderer.getLink();
        // return if data is missing or no ScalarMaps
        if (data.isMissing()) {
                ((ImageRendererJ3D) renderer).markMissingVisADBranch();
                return false;
        }

        if (levelOfDifficulty == -1) {
                levelOfDifficulty = getLevelOfDifficulty();
        }

        if (levelOfDifficulty == NOTHING_MAPPED) return false;


        if (group instanceof BranchGroup && ((BranchGroup) group).numChildren() 
> 0) {
                Node g = ((BranchGroup) group).getChild(0);
                // WLH 06 Feb 06 - support switch in a branch group.
                if (g instanceof BranchGroup && ((BranchGroup) g).numChildren() 
> 0) {
                        reuseImages = true;
                }
        }

        DisplayImpl display = getDisplay();

        int cMapCurveSize = (int) 
default_values[display.getDisplayScalarIndex(Display.CurvedSize)];

        int curved_size = (cMapCurveSize > 0) ? cMapCurveSize : 
display.getGraphicsModeControl().getCurvedSize();
 
        // length of ValueArray
        int valueArrayLength = display.getValueArrayLength();
        // mapping from ValueArray to DisplayScalar
        int[] valueToScalar = display.getValueToScalar();
        //GHANSHAM:30AUG2011 Restrutured the code  to extract the 
constant_alpha, cmap, cmaps and ShadowFunctionType so that they can be passed 
to initRegenFlags method
        if (adaptedShadowType == null) {
                adaptedShadowType = (ShadowFunctionOrSetType) 
getAdaptedShadowType();
        }

        boolean anyContour = adaptedShadowType.getAnyContour();
        boolean anyFlow = adaptedShadowType.getAnyFlow();
        boolean anyShape = adaptedShadowType.getAnyShape();
        boolean anyText = adaptedShadowType.getAnyText();

        if (anyContour || anyFlow || anyShape || anyText) {
                throw new BadMappingException("no contour, flow, shape or text 
allowed");
        }

        FlatField imgFlatField = null;
        Set domain_set = ((Field) data).getDomainSet();

        ShadowRealType[] DomainComponents = 
adaptedShadowType.getDomainComponents();
        int numImages = 1;
        if (!adaptedShadowType.getIsTerminal()) {

                Vector domain_maps = DomainComponents[0].getSelectedMapVector();
                ScalarMap amap = null;
                if (domain_set.getDimension() == 1 && domain_maps.size() == 1) {
                        ScalarMap map = (ScalarMap) domain_maps.elementAt(0);
                        if (Display.Animation.equals(map.getDisplayScalar())) {
                                amap = map;
                        }
                }
                if (amap == null) {
                        throw new BadMappingException("time must be mapped to 
Animation");
                }
                animControl = (AnimationControlJ3D) amap.getControl();

                numImages = domain_set.getLength();

                adaptedShadowType = (ShadowFunctionOrSetType) 
adaptedShadowType.getRange();
                DomainComponents = adaptedShadowType.getDomainComponents();
                imgFlatField = (FlatField) ((FieldImpl)data).getSample(0);
        } else {
                imgFlatField = (FlatField)data;
        }

         // check that range is single RealType mapped to RGB only
        ShadowRealType[] RangeComponents = 
adaptedShadowType.getRangeComponents();
        int rangesize = RangeComponents.length;
        if (rangesize != 1 && rangesize != 3) {
                throw new BadMappingException("image values must single or 
triple");
        }
        ScalarMap cmap  = null;
        ScalarMap[] cmaps = null;
        int[] permute = {-1, -1, -1};
        boolean hasAlpha = false;
        ScalarMap topo_map = null;
        if (rangesize == 1) {
                Vector mvector = RangeComponents[0].getSelectedMapVector();
                //Added to allow Range  Component Mapping to ZAxis
                if (mvector.size() != 1 && mvector.size()!= 2) {
                        throw new BadMappingException("image values must be 
mapped to RGB only or RGB and Axis only");
                }
                ScalarMap scalar_map = null;
                for (int i = 0; i < mvector.size(); i++) {
                        scalar_map = (ScalarMap) mvector.elementAt(i);
                        DisplayRealType display_scalar = 
scalar_map.getDisplayScalar();
                        if (display_scalar.equals(Display.RGB)) {
                                cmap = scalar_map;
                        } else if (display_scalar.equals(Display.RGBA)) {
                                hasAlpha = true;
                                cmap = scalar_map;
                        } else if (display_scalar.equals(Display.ZAxis)) {
                                topo_map = scalar_map;
                        } else {
                                throw new BadMappingException("image values 
must be mapped to RGB only or RGB and Axis only");
                        }
                }
                /*if (mvector.size() != 1) {
                        throw new BadMappingException("image values must be 
mapped to RGB only");
                }
                cmap = (ScalarMap) mvector.elementAt(0);
                if (Display.RGB.equals(cmap.getDisplayScalar())) {

                } else if (Display.RGBA.equals(cmap.getDisplayScalar())) {
                        hasAlpha = true;
                } else {
                        throw new BadMappingException("image values must be 
mapped to RGB or RGBA");
                }*/
        } else {
                cmaps = new ScalarMap[3];
                for (int i=0; i<3; i++) {
                        Vector mvector = 
RangeComponents[i].getSelectedMapVector();
                        if (mvector.size() != 1) {
                                throw new BadMappingException("image values 
must be mapped to color only");
                        }
                        cmaps[i] = (ScalarMap) mvector.elementAt(0);
                        if (Display.Red.equals(cmaps[i].getDisplayScalar())) {
                                permute[0] = i;
                        } else if 
(Display.Green.equals(cmaps[i].getDisplayScalar())) {
                                permute[1] = i;
                        } else if 
(Display.Blue.equals(cmaps[i].getDisplayScalar())) {
                                permute[2] = i;
                        } else if 
(Display.RGB.equals(cmaps[i].getDisplayScalar())) { //Inserted by Ghansham for 
Mapping all the three scalarMaps to Display.RGB (starts here) 
                                permute[i] = i;
                        } else {               ////Inserted by Ghansham for 
Mapping all the three scalarMaps to Display.RGB(ends here)
                                throw new BadMappingException("image values 
must be mapped to Red, Green or Blue only");
                        }
                }
                if (permute[0] < 0 || permute[1] < 0 || permute[2] < 0) {
                        throw new BadMappingException("image values must be 
mapped to Red, Green or Blue only");
                }
                //Inserted by Ghansham for Checking that all should be mapped 
to Display.RGB or not even a single one should be mapped to Display.RGB(starts 
here)
                //This is to check if there is a single Display.RGB ScalarMap
                int indx = -1;
                for (int i = 0; i < 3; i++) {
                        if (cmaps[i].getDisplayScalar().equals(Display.RGB)) {
                                indx = i;
                                break;
                        }
                }

                if (indx != -1){    //if there is a even a single Display.RGB 
ScalarMap, others must also Display.RGB only
                        for (int i = 0; i < 3; i++) {
                                if (i !=indx && 
!(cmaps[i].getDisplayScalar().equals(Display.RGB))) {
                                        throw new BadMappingException("image 
values must be mapped to (Red, Green, Blue) or (RGB,RGB,RGB) only");
                                }
                        }
                }
                //Inserted by Ghansham for Checking that all should be mapped 
to Display.RGB or not even a single one should be mapped to Display.RGB(Ends 
here)        
        }

        float constant_alpha = 
default_values[display.getDisplayScalarIndex(Display.Alpha)];
        int color_length;
        ImageRendererJ3D imgRenderer = (ImageRendererJ3D) renderer;
        int imageType = imgRenderer.getSuggestedBufImageType();
        if (imageType == BufferedImage.TYPE_4BYTE_ABGR) {
                color_length = 4;
                if (!hasAlpha) {
                        color_length = 3;
                        imageType = BufferedImage.TYPE_3BYTE_BGR;
                }
        } else if (imageType == BufferedImage.TYPE_3BYTE_BGR) {
                color_length = 3;
        } else if (imageType == BufferedImage.TYPE_USHORT_GRAY) {
                color_length = 2;
        } else if (imageType == BufferedImage.TYPE_BYTE_GRAY) {
                color_length = 1;
        } else {
                // we shouldn't ever get here because the renderer validates 
the 
                // imageType before we get it, but just in case...
                throw new VisADException("renderer returned unsupported image 
type");
        }
        if (color_length == 4) constant_alpha = Float.NaN; // WLH 6 May 2003


        //REUSE GEOMETRY/COLORBYTE LOGIC (STARTS HERE)
        regen_colbytes = false;
        regen_geom = false;
        apply_alpha = false; 
        //initRegenFlags((ImageRendererJ3D)renderer, adaptedShadowType, 
constant_alpha, cmap, cmaps, data, display, default_values, value_array, 
valueToScalar, valueArrayLength, link, curved_size);
        initRegenFlags((ImageRendererJ3D)renderer, adaptedShadowType, 
constant_alpha, cmap, cmaps, data, display, default_values, value_array, 
valueToScalar, valueArrayLength, link, curved_size, topo_map);
        if(!reuseImages) {
                regen_geom = true;
                regen_colbytes = true;
                apply_alpha = true;
        }

        /**
        System.err.println("Regenerate Color Bytes:" + regen_colbytes);
        System.err.println("Regenerate Geometry:" + regen_geom);
        System.err.println("Apply Alpha:" + apply_alpha);
        System.err.println("ReuseImages:" + reuseImages);
        */
        
        //REUSE GEOMETRY/COLORBYTE LOGIC (ENDS HERE)
        prevImgNode = ((ImageRendererJ3D)renderer).getImageNode();

        BranchGroup bgImages = null;

        /*REUSE GEOM/COLBYTE: Replaced reuse with reuseImages. Earlier else 
part of this decision was never being used.
          The reason was reuse was always set to false. Compare with your 
version.
          Added one extra line in the else part where I extract the bgImages 
from the switch.
          Now else part occurs when either reuse_colbytes or regen_geom is true.
          But when regen_colbytes and regen_geom both are true, then I assume 
that a new flatfield is set so
          go with the if part.
        */
        if (!reuseImages || (regen_colbytes && regen_geom)) { //REUSE 
GEOM/COLBYTE:Earlier reuse variable was used. Replaced it with reuseImages.
                                                                //Added 
regen_colbytes and regen_geom. 
                                                                //This is used 
when either its first time or full new data has been with different dims.
                BranchGroup branch = new BranchGroup();
                branch.setCapability(BranchGroup.ALLOW_DETACH);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
                Switch swit = (Switch) makeSwitch();

                imgNode = new VisADImageNode();

                bgImages = new BranchGroup();
                bgImages.setCapability(BranchGroup.ALLOW_DETACH);
                bgImages.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
                bgImages.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
                bgImages.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);

                swit.addChild(bgImages);
                swit.setWhichChild(0);
                branch.addChild(swit);

                imgNode.setBranch(branch);
                imgNode.setSwitch(swit);
                ((ImageRendererJ3D)renderer).setImageNode(imgNode);

                if ( ((BranchGroup) group).numChildren() > 0 ) {
                        ((BranchGroup)group).setChild(branch, 0);
                } else {
                        ((BranchGroup)group).addChild(branch);
         /*
         // make sure group is live.  group not empty (above addChild)
         if (group instanceof BranchGroup) {
           ((ImageRendererJ3D) renderer).setBranchEarly((BranchGroup) group);
         }
         */
                }
        } else { //REUSE GEOM/COLBYTE: If its not the first time. And the dims 
have not changed but either color bytes or geometry has changed.
                imgNode = ((ImageRendererJ3D)renderer).getImageNode();
                bgImages = (BranchGroup) imgNode.getSwitch().getChild(0);       
//REUSE GEOM/COLBYTE:Extract the bgImages from the avaialable switch
        } 


    GraphicsModeControl mode = (GraphicsModeControl)
          display.getGraphicsModeControl().clone();

    // get some precomputed values useful for transform
    // mapping from ValueArray to MapVector
    int[] valueToMap = display.getValueToMap();
    Vector MapVector = display.getMapVector();

    Unit[] dataUnits = null;
    CoordinateSystem dataCoordinateSystem = null;


    if (animControl != null) {
        Switch swit = new SwitchNotify(imgNode, numImages);  
        ((AVControlJ3D) animControl).addPair((Switch) swit, domain_set, 
renderer);
        ((AVControlJ3D) animControl).init();
    }


    domain_set = imgFlatField.getDomainSet();
    dataUnits = ((Function) imgFlatField).getDomainUnits();
    dataCoordinateSystem =
      ((Function) imgFlatField).getDomainCoordinateSystem();

    int domain_length = domain_set.getLength();
    int[] lengths = ((GriddedSet) domain_set).getLengths();
    int data_width = lengths[0];
    int data_height = lengths[1];

    imgNode.numImages = numImages;
    imgNode.data_width = data_width;
    imgNode.data_height = data_height;

    int texture_width_max = 
link.getDisplay().getDisplayRenderer().getTextureWidthMax();
    int texture_height_max = 
link.getDisplay().getDisplayRenderer().getTextureWidthMax();

    int texture_width = textureWidth(data_width);
    int texture_height = textureHeight(data_height);

    if (reuseImages) {
      if (prevImgNode.numImages != numImages || 
          prevImgNode.data_width != data_width || prevImgNode.data_height != 
data_height) {
        reuseImages = false;
      }
    }
    if (reuseImages) {
      imgNode.numChildren = prevImgNode.numChildren;
      imgNode.imageTiles = prevImgNode.imageTiles;
    }
    else {
        Mosaic mosaic = new Mosaic(data_height, texture_height_max, data_width, 
texture_width_max);
        for (Iterator iter = mosaic.iterator(); iter.hasNext();) {
                Tile tile = (Tile) iter.next();
                imgNode.addTile(new VisADImageTile(numImages, tile.height, 
tile.y_start, tile.width, tile.x_start));
        }
    }

    prevImgNode = imgNode;

    ShadowRealTupleType Domain = adaptedShadowType.getDomain();
    Unit[] domain_units = ((RealTupleType) Domain.getType()).getDefaultUnits();
    float[] constant_color = null;

    // check that domain is only spatial
    if (!Domain.getAllSpatial() || Domain.getMultipleDisplayScalar()) {
      throw new BadMappingException("domain must be only spatial");
    }

    // check domain and determine whether it is square or curved texture
    boolean isTextureMap = adaptedShadowType.getIsTextureMap() &&
                             (domain_set instanceof Linear2DSet ||
                              (domain_set instanceof LinearNDSet &&
                               domain_set.getDimension() == 2)) && 
                             //(domain_set.getManifoldDimension() == 2);
                             (domain_set.getManifoldDimension() == 2 && 
(topo_map == null));


    boolean curvedTexture = adaptedShadowType.getCurvedTexture() &&
                            !isTextureMap &&
                            curved_size > 0 &&
                            (domain_set instanceof Gridded2DSet ||
                             (domain_set instanceof GriddedSet &&
                              domain_set.getDimension() == 2)) &&
                             (domain_set.getManifoldDimension() == 2);

        if (group instanceof BranchGroup) {
                ((ImageRendererJ3D) renderer).setBranchEarly((BranchGroup) 
group);
        }

    first_time =true; //Ghansham: this variable just indicates to 
makeColorBytes whether it's the first tile of the image
    boolean branch_added = false;
    if (isTextureMap) { // linear texture

        if (imgNode.getNumTiles() == 1) {
          VisADImageTile tile = imgNode.getTile(0);
          if (regen_colbytes) { //REUSE COLBYTES: regenerate only if required
                  makeColorBytesDriver(imgFlatField, cmap, cmaps, 
constant_alpha, RangeComponents, color_length, domain_length, permute,
                              data_width, data_height, imageType, tile, 0, 
topo_map != null);
          }
                if (regen_geom) { //REUSE : REGEN GEOM  regenerate the geometry
                        buildLinearTexture(bgImages, domain_set, dataUnits, 
domain_units, default_values, DomainComponents,
                             valueArrayLength, inherited_values, valueToScalar, 
mode, constant_alpha, 
                             value_array, constant_color, display, tile);
                } else { //REUSE Reuse the branch fully along with geometry. 
Just apply the colorbytes(Buffered Image)
                    BranchGroup Branch_L1 = (BranchGroup) bgImages.getChild(0);
                    Shape3D shape = (Shape3D) Branch_L1.getChild(0);
                    applyTexture(shape, tile, apply_alpha, constant_alpha);
                }

        }
        else {
          BranchGroup branch = null;
          //if (!reuseImages || (regen_colbytes && regen_geom)) { //REUSE: Make 
a fresh branch
          if (!reuseImages) {
                branch = new BranchGroup();
                branch.setCapability(BranchGroup.ALLOW_DETACH);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
           } else { //REUSE the branch
                branch = (BranchGroup) bgImages.getChild(0);
           }
          int branch_tile_indx = 0; //REUSE: to get the branch for a tile in 
case of multi-tile rendering
          for (Iterator iter = imgNode.getTileIterator(); iter.hasNext();) {
             VisADImageTile tile = (VisADImageTile) iter.next();

                if (regen_colbytes) { //REUSE COLBYTES: regenerate only if 
required
                        makeColorBytesDriver(imgFlatField, cmap, cmaps, 
constant_alpha, RangeComponents, color_length, domain_length, permute,
                                data_width, data_height, imageType, tile, 0, 
topo_map != null);
                        first_time = false; //Ghansham: setting 'first_time' 
variable false after the first tile has been generated
                }
                if (regen_geom) { //REUSE: Regenerate the geometry

                        float[][] g00 = ((GriddedSet)domain_set).gridToValue(
                                        new float[][] {{tile.xStart}, 
{tile.yStart}});
                        float[][] g11 = ((GriddedSet)domain_set).gridToValue(
                                        new float[][] 
{{tile.xStart+tile.width-1}, {tile.yStart+tile.height-1}});

                        double x0 = g00[0][0];
                        double x1 = g11[0][0];
                        double y0 = g00[1][0];
                        double y1 = g11[1][0];
                        Set dset = new Linear2DSet(x0, x1, tile.width, y0, y1, 
tile.height);

                        BranchGroup branch1 = null;
                        if (!reuseImages || (regen_colbytes && regen_geom)) { 
//REUSE: Make a fresh branch for each tile
                                branch1 = new BranchGroup();
                                branch1.setCapability(BranchGroup.ALLOW_DETACH);
                                
branch1.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
                                
branch1.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
                                
branch1.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
                        } else { //REUSE: Reuse the already built branch for 
each tile
                                branch1 = (BranchGroup) 
branch.getChild(branch_tile_indx);
                        }

                        buildLinearTexture(branch1, dset, dataUnits, 
domain_units, default_values, DomainComponents,
                                 valueArrayLength, inherited_values, 
valueToScalar, mode, constant_alpha, 
                                 value_array, constant_color, display, tile);
                        if (!reuseImages|| (regen_colbytes && regen_geom)) {
                                branch.addChild(branch1);
                        }
                        g00 = null;
                        g11 = null;
                        dset = null;
                } else { //REUSE Reuse the branch fully along with geometry. 
Just apply the colorbytes(Buffered Image)
                        BranchGroup branch1 = (BranchGroup) 
branch.getChild(branch_tile_indx);
                        BranchGroup branch2 = (BranchGroup) 
branch1.getChild(0); //Beause we create a branch in textureToGroup
                        Shape3D shape = (Shape3D) branch2.getChild(0);
                        applyTexture(shape, tile, apply_alpha, constant_alpha);
                }
                if (0 == branch_tile_indx) { //Add the branch to get rendered 
as early as possible
                        if (!reuseImages || (regen_colbytes && regen_geom)) { 
//REUSE : Add a new branch if created
                                if (((Group) bgImages).numChildren() > 0) {
                                        ((Group) bgImages).setChild(branch, 0);
                                } else {
                                        ((Group) bgImages).addChild(branch);
                                }
                        }
                }

                branch_tile_indx++;

          }

        }
      } // end if (isTextureMap)
      else if (curvedTexture) {

        int[] lens = ((GriddedSet)domain_set).getLengths();
        int[] domain_lens = lens;

        if (imgNode.getNumTiles() == 1) {
          VisADImageTile tile = imgNode.getTile(0);
                if (regen_colbytes) {  //REUSE COLBYTES: regenerate only if 
required
                        makeColorBytesDriver(imgFlatField, cmap, cmaps, 
constant_alpha, RangeComponents, color_length, domain_length, permute,
                                data_width, data_height, imageType, tile,  0, 
topo_map != null);
                }
                if (regen_geom) { //REUSE: REGEN GEOM regenerate 
                        buildCurvedTexture(bgImages, domain_set, dataUnits, 
domain_units, default_values, DomainComponents,
                             valueArrayLength, inherited_values, valueToScalar, 
mode, constant_alpha,
                             value_array, constant_color, display, curved_size, 
Domain,
                             dataCoordinateSystem, renderer, adaptedShadowType, 
new int[] {0,0},
                             //domain_lens[0], domain_lens[1], null, 
domain_lens[0], domain_lens[1], tile);
                             domain_lens[0], domain_lens[1], null, 
domain_lens[0], domain_lens[1], tile, topo_samples, topo_map);
                } else { //REUSE Reuse the branch fully along with geometry. 
Just apply the colorbytes(Buffered Image)
                        BranchGroup Branch_L1 = (BranchGroup) 
bgImages.getChild(0);
                        Shape3D shape = (Shape3D) Branch_L1.getChild(0);
                        applyTexture(shape, tile, apply_alpha, constant_alpha);
                }
        }
        else
        {
          float[][] samples = ((GriddedSet)domain_set).getSamples(false);

          BranchGroup branch = null;
        if (!reuseImages || (regen_colbytes && regen_geom)) {  //REUSE: Make a 
fresh branch
                branch = new BranchGroup();
                branch.setCapability(BranchGroup.ALLOW_DETACH);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
                branch.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
          } else { //REUSE: Reuse already built branch 
                branch = (BranchGroup) bgImages.getChild(0);
          } 
          int branch_tile_indx = 0; //REUSE: to get the branch for a tile in 
case of multi-tile rendering
          for (Iterator iter = imgNode.getTileIterator(); iter.hasNext();) {
             VisADImageTile tile = (VisADImageTile) iter.next();
                if (regen_colbytes) { //REUSE COLBYTES: regenerate only if 
required
                        makeColorBytesDriver(imgFlatField, cmap, cmaps, 
constant_alpha, RangeComponents, color_length, domain_length, permute,
                                data_width, data_height, imageType, tile, 0, 
topo_map != null);
                        first_time = false; //Ghansham: setting 'first_time' 
variable false after the first tile has been generated
                }

                if (regen_geom) { //REUSE REGEN GEOM regenerate geometry 
                        BranchGroup branch1 = null;
                        if (!reuseImages || (regen_colbytes && regen_geom)) { 
//REUSE: Make a fresh branch group for each tile
                                branch1 = new BranchGroup();
                                branch1.setCapability(BranchGroup.ALLOW_DETACH);
                                
branch1.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
                                
branch1.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
                                
branch1.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
                        } else { //REUSE: Reuse the already existing branch for 
each tile
                                branch1 = (BranchGroup) 
branch.getChild(branch_tile_indx);
                        }
                        
                        buildCurvedTexture(branch1, null, dataUnits, 
domain_units, default_values, DomainComponents,
                                valueArrayLength, inherited_values, 
valueToScalar, mode, constant_alpha,
                                value_array, constant_color, display, 
curved_size, Domain,
                                dataCoordinateSystem, renderer, 
adaptedShadowType, 
                                new int[] {tile.xStart,tile.yStart}, 
tile.width, tile.height,
                                samples, domain_lens[0], domain_lens[1], tile, 
topo_samples, topo_map);

                        if (!reuseImages || (regen_colbytes && regen_geom)) { 
//REUSE: Add newly created branch 
                              branch.addChild(branch1);
                        }
                } else { //REUSE Reuse the branch fully along with geometry. 
Just apply the colorbytes(Buffered Image)
                        BranchGroup branch1 = (BranchGroup) 
branch.getChild(branch_tile_indx);
                        BranchGroup branch2 = (BranchGroup) branch1.getChild(0);
                        Shape3D shape = (Shape3D) branch2.getChild(0);
                        applyTexture(shape, tile, apply_alpha, constant_alpha);
                }
                if (0 == branch_tile_indx) { //Add the branch to get rendered 
as early as possible
                        if (!reuseImages || (regen_colbytes && regen_geom)) { 
//REUSE : Add a new branch if created
                                if (((Group) bgImages).numChildren() > 0) {
                                        ((Group) bgImages).setChild(branch, 0);
                                } else {
                                        ((Group) bgImages).addChild(branch);
                                }
                        }
                }
                branch_tile_indx++;
           }

        }
      } // end if (curvedTexture)
      else { // !isTextureMap && !curvedTexture
        throw new BadMappingException("must be texture map or curved texture 
map");
      } 
        topo_samples = null;

      // make sure group is live.  group not empty (above addChild)
      /*if (group instanceof BranchGroup) {
        ((ImageRendererJ3D) renderer).setBranchEarly((BranchGroup) group);
      }*/


      for (int k=1; k<numImages; k++) {
        FlatField ff = (FlatField) ((Field)data).getSample(k);
        CoordinateSystem dcs = ff.getDomainCoordinateSystem();
        GriddedSet domSet = (GriddedSet) ff.getDomainSet();
        int[] lens = domSet.getLengths();

        // if image dimensions, or dataCoordinateSystem not equal to first 
image, resample to first
        if (regen_colbytes) { //REUSE COLBYTES: resample the flatfield only if 
colorbytes need to be regenerated
                if ( (lens[0] != data_width || lens[1] != data_height) || 
!(dcs.equals(dataCoordinateSystem))) {
                        ff = (FlatField) 
ff.resample(imgFlatField.getDomainSet(), Data.NEAREST_NEIGHBOR, Data.NO_ERRORS);
                }
        }

        first_time = true;
        scaled_Bytes = null; //scaled byte values 
        scaled_Floats = null; //scaled Float Values
        fast_table = null;
        rset_scalarmap_lookup = null; //GHANSHAM:30AUG2011 create a lookup for 
rset FlatField range values
        itable = null; //For single band
        threeD_itable = null; //for multiband
        color_values = null; //special case

        for (Iterator iter = imgNode.getTileIterator(); iter.hasNext();) {
          VisADImageTile tile = (VisADImageTile) iter.next();
          if(regen_colbytes) {  //REUSE COLBYTES: regenerate colobytes only if 
required
                makeColorBytesDriver(ff, cmap, cmaps, constant_alpha, 
RangeComponents, color_length, domain_length, permute,
                        data_width, data_height, imageType, tile, k, false);
                first_time = false;
          }
          //image.bytesChanged(byteData);
        }
      }

      cmaps = null;
      first_time = true;
      scaled_Bytes = null; //scaled byte values 
      scaled_Floats = null; //scaled Float Values
      fast_table = null;
      rset_scalarmap_lookup = null; //GHANSHAM:30AUG2011 create a lookup for 
rset FlatField range values
      itable = null; //For single band
      threeD_itable = null; //for multiband
      color_values = null; //special case


      ensureNotEmpty(bgImages);
      return false;
  }


// This function calls makeColorBytes function (Ghansham)
public void makeColorBytesDriver(Data imgFlatField, ScalarMap cmap, ScalarMap[] 
cmaps, float constant_alpha,
              ShadowRealType[] RangeComponents, int color_length, int 
domain_length, int[] permute,
              int data_width, int data_height,
              int imageType, VisADImageTile tile, int image_index, boolean 
extract_topo) throws VisADException, RemoteException {
        BufferedImage image = null;
        byte byteData[] = null;
        int tile_width = tile.width;
        int tile_height = tile.height;
        int xStart = tile.xStart;
        int yStart = tile.yStart;
        int texture_width = textureWidth(tile_width);
        int texture_height = textureHeight(tile_height);

       if (!reuseImages) {
         image = createImageByRef(texture_width, texture_height, imageType);
         tile.setImage(image_index, image);
       } else {
         //image = (CachedBufferedByteImage) tile.getImage(0);
         image = (BufferedImage) tile.getImage(image_index);
       }

       java.awt.image.Raster raster = image.getRaster();
       DataBuffer db = raster.getDataBuffer();
       byteData = ((DataBufferByte)db).getData();
       java.util.Arrays.fill(byteData, (byte)0);
        makeColorBytes(imgFlatField, cmap, cmaps, constant_alpha, 
RangeComponents, color_length, domain_length, permute,
                    byteData,
                    data_width, data_height, tile_width, tile_height, xStart, 
yStart, texture_width, texture_height, extract_topo);
}

/*  New version contributed by Ghansham (ISRO)
 This function scales the flatfield values and the colortable for the first 
tile only using the first_time variable. Rest of the time it only
 uses scaled values and color table to generate colorbytes for respective tile. 
Just see the first_time variable use. That is the only difference between
 this function and earlier function makeColorBytes(). Some new class variables 
have been introduced to preserve scaled values and colortable.
 They are made null after all the tiles for a single image has been generated. 
At the end of doTransform(), they are made null.
*/
public void makeColorBytes(Data data, ScalarMap cmap, ScalarMap[] cmaps, float 
constant_alpha,
              ShadowRealType[] RangeComponents, int color_length, int 
domain_length, int[] permute,
              byte[] byteData, int data_width, int data_height, int tile_width, 
int tile_height, int xStart, int yStart,
              int texture_width, int texture_height, boolean extract_topo)
                throws VisADException, RemoteException {
        if (cmap != null) {
                BaseColorControl control = (BaseColorControl) cmap.getControl();
                float[][] table = control.getTable();
                Set rset = null;
                boolean is_default_unit = false;

                if (data instanceof FlatField) {
                        // for fast byte color lookup, need:
                        // 1. range data values are packed in bytes
                        //bytes = ((FlatField) data).grabBytes();
                        if (first_time) {
                                scaled_Bytes = ((FlatField) data).grabBytes();
                        }
                        // 2. range set is Linear1DSet
                        Set[] rsets = ((FlatField) data). getRangeSets();
                        if (rsets != null) rset = rsets[0];
                        // 3. data Unit equals default Unit
                        RealType rtype = (RealType) 
RangeComponents[0].getType();
                        Unit def_unit = rtype.getDefaultUnit();
                        if (def_unit == null) {
                                is_default_unit = true;
                        } else {
                                Unit[][] data_units = ((FlatField) 
data).getRangeUnits();
                                Unit data_unit = (data_units == null) ? null : 
data_units[0][0];
                                is_default_unit = def_unit.equals(data_unit);
                        }
                }
                if (table != null) {
                        // combine color table RGB components into ints
                        if (first_time) {
                                itable = new byte[table[0].length][4];
                                // int r, g, b, a = 255;
                                int r, g, b;
                                int c = (int) (255.0 * (1.0f - constant_alpha));
                                int a = (c < 0) ? 0 : ((c > 255) ? 255 : c);
                                for (int j=0; j<table[0].length; j++) {
                                        c = (int) (255.0 * table[0][j]);
                                        r = (c < 0) ? 0 : ((c > 255) ? 255 : c);
                                        c = (int) (255.0 * table[1][j]);
                                        g = (c < 0) ? 0 : ((c > 255) ? 255 : c);
                                        c = (int) (255.0 * table[2][j]);
                                        b = (c < 0) ? 0 : ((c > 255) ? 255 : c);
                                        if (color_length == 4) {
                                                c = (int) (255.0 * table[3][j]);
                                                a = (c < 0) ? 0 : ((c > 255) ? 
255 : c);
                                        }
                                        itable[j][0] = (byte) r;
                                        itable[j][1] = (byte) g;
                                        itable[j][2] = (byte) b;
                                        itable[j][3] = (byte) a;
                                }
                        }
                        int tblEnd = table[0].length - 1;
                        // get scale for color table
                        int table_scale = table[0].length;
                        if (data instanceof ImageFlatField && scaled_Bytes != 
null && is_default_unit) {
                                if (ImageFlatField.DEBUG) {
                                        
System.err.println("ShadowImageFunctionTypeJ3D.doTransform: " + "cmap != null: 
looking up color values");
                                }
                                // avoid unpacking floats for ImageFlatFields
                                if (first_time) {
                                        scaled_Bytes[0]= 
cmap.scaleValues(scaled_Bytes[0], table_scale); 
                                }
                                // fast lookup from byte values to color bytes
                                byte[] bytes0 = scaled_Bytes[0];

                                int k =0;
                                int color_length_times_texture_width = 
texture_width*color_length;
                                for (int y=0; y<tile_height; y++) {
                                        int image_col_factor = 
(y+yStart)*data_width + xStart;
                                        k= y*color_length_times_texture_width;
                                        for (int x=0; x<tile_width; x++) {
                                                int i = x + image_col_factor;
                                                int j = bytes0[i] & 0xff; // 
unsigned
                                                // clip to table
                                                int ndx = j < 0 ? 0 : (j > 
tblEnd ? tblEnd : j);
                                                if (color_length == 4) {
                                                        byteData[k] = 
itable[ndx][3];
                                                        byteData[k+1] = 
itable[ndx][2];
                                                        byteData[k+2] = 
itable[ndx][1];
                                                        byteData[k+3] = 
itable[ndx][0];
                                                }
                                                if (color_length == 3) {
                                                        byteData[k] = 
itable[ndx][2];
                                                        byteData[k+1] = 
itable[ndx][1];
                                                        byteData[k+2] = 
itable[ndx][0];
                                                }
                                                if (color_length == 1) {
                                                        byteData[k] = 
itable[ndx][0];
                                                }
                                                k += color_length;
                                        }
                                }
                        } else if (scaled_Bytes != null && scaled_Bytes[0] != 
null && is_default_unit && rset != null && rset instanceof Linear1DSet) {
                                // fast since FlatField with bytes, data Unit 
equals default
                                // Unit and range set is Linear1DSet
                                // get "scale and offset" for Linear1DSet
                                if (first_time) {
                                        double first = ((Linear1DSet) 
rset).getFirst();
                                        double step = ((Linear1DSet) 
rset).getStep();
                                        // get scale and offset for ScalarMap
                                        double[] so = new double[2];
                                        double[] da = new double[2];
                                        double[] di = new double[2];
                                        cmap.getScale(so, da, di);
                                        double scale = so[0];
                                        double offset = so[1];
                                        // combine scales and offsets for Set, 
ScalarMap and color table
                                        float mult = (float) (table_scale * 
scale * step);
                                        float add = (float) (table_scale * 
(offset + scale * first));

                                        // build table for fast color lookup
                                        fast_table = new byte[256][];
                                        for (int j=0; j<256; j++) {
                                                int index = j - 1;
                                                if (index >= 0) { // not missing
                                                        int k = (int) (add + 
mult * index);
                                                        // clip to table
                                                        int ndx = k < 0 ? 0 : 
(k > tblEnd ? tblEnd : k);
                                                        fast_table[j] = 
itable[ndx];
                                                }
                                        }
                                }
                                // now do fast lookup from byte values to color 
bytes
                                byte[] bytes0 = scaled_Bytes[0];

                                int k = 0;
                                int color_length_times_texture_width = 
texture_width*color_length;
                                for (int y=0; y<tile_height; y++) {
                                        int image_col_factor = 
(y+yStart)*data_width + xStart;
                                        k = y*color_length_times_texture_width;
                                        for (int x=0; x<tile_width; x++) {
                                                int i = x + image_col_factor;
                                                int ndx = ((int) bytes0[i]) - 
MISSING1;
                                                if (color_length == 4) {
                                                        byteData[k] = 
itable[ndx][3];
                                                        byteData[k+1] = 
itable[ndx][2];
                                                        byteData[k+2] = 
itable[ndx][1];
                                                        byteData[k+3] = 
itable[ndx][0];
                                                }
                                                if (color_length == 3) {
                                                        byteData[k] = 
itable[ndx][2];
                                                        byteData[k+1] = 
itable[ndx][1];
                                                        byteData[k+2] = 
itable[ndx][0];
                                                }
                                                if (color_length == 1) {
                                                        byteData[k] = 
itable[ndx][0];
                                                }
                                                k+=color_length;
                                        }
                                }
                        } else {
                                // medium speed way to build texture colors
                                if (first_time) {
                                        scaled_Bytes = null;
                                        scaled_Floats = ((Field) 
data).getFloats(false);
                                        topo_samples = new 
float[scaled_Floats[0].length];
                                        System.arraycopy(scaled_Floats[0], 0, 
topo_samples, 0, scaled_Floats[0].length);
                                        //GHANSHAM:30AUG2011 If rset can be 
used to create a lookup for range values, create them
                                        if (rset instanceof Integer1DSet) {
                                                rset_scalarmap_lookup = new 
float[1][rset.getLength()];
                                                for (int i = 0; i < 
rset_scalarmap_lookup[0].length; i++) {
                                                        
rset_scalarmap_lookup[0][i] = i;
                                                }
                                                rset_scalarmap_lookup[0] = 
cmap.scaleValues(rset_scalarmap_lookup[0], false);
                                        } else {
                                                scaled_Floats[0] = 
cmap.scaleValues(scaled_Floats[0]);
                                        }
                                }
                                // now do fast lookup from byte values to color 
bytes
                                float[] values0 = scaled_Floats[0];
                                int k = 0;
                                int color_length_times_texture_width = 
texture_width*color_length;
                                int image_col_offset = yStart*data_width + 
xStart;
                                int image_col_factor = 0;
                                for (int y=0; y<tile_height; y++) {
                                        image_col_factor = 
y*data_width+image_col_offset;
                                        k = y*color_length_times_texture_width;
                                        for (int x=0; x<tile_width; x++) {
                                                int i = x + image_col_factor;
                                                if (!Float.isNaN(values0[i])) { 
// not missing
                                                        int j = 0;
                                                        //GHANSHAM:30AUG2011 
Use the rset lookup to find scaled Range Values
                                                        if (null != 
rset_scalarmap_lookup && null != rset_scalarmap_lookup[0]) {
                                                                j = (int) 
(table_scale*rset_scalarmap_lookup[0][(int)values0[i]]);
                                                        } else {
                                                                j = (int) 
(table_scale*values0[i]);
                                                        }
                                                        // clip to table
                                                        int ndx = j < 0 ? 0 : 
(j > tblEnd ? tblEnd : j);
                                                        if (color_length == 4) {
                                                                byteData[k] = 
itable[ndx][3];
                                                                byteData[k+1] = 
itable[ndx][2];
                                                                byteData[k+2] = 
itable[ndx][1];
                                                                byteData[k+3] = 
itable[ndx][0];
                                                        }
                                                        if (color_length == 3) {
                                                                byteData[k] = 
itable[ndx][2];
                                                                byteData[k+1] = 
itable[ndx][1];
                                                                byteData[k+2] = 
itable[ndx][0];
                                                        }
                                                        if (color_length == 1) {
                                                                byteData[k] = 
itable[ndx][0];
                                                        }
                                                }
                                                k+=color_length;
                                        }
                                }
                        }
                } else { // if (table == null)
                        // slower, more general way to build texture colors
                        if (first_time) {
                                // call lookupValues which will use function 
since table == null
                                scaled_Bytes = null;
                                itable = null;
                                scaled_Floats = ((Field) data).getFloats(false);
                                scaled_Floats[0] = 
cmap.scaleValues(scaled_Floats[0]);
                                topo_samples = new 
float[scaled_Floats[0].length];
                                System.arraycopy(scaled_Floats[0], 0, 
topo_samples, 0, scaled_Floats[0].length);

                                color_values = 
control.lookupValues(scaled_Floats[0]);
                        }

                        // combine color RGB components into bytes
                        // int r, g, b, a = 255;
                        int r, g, b;
                        int c = (int) (255.0 * (1.0f - constant_alpha));
                        int a = (c < 0) ? 0 : ((c > 255) ? 255 : c);
                        int k = 0;
                        int color_length_times_texture_width = 
texture_width*color_length;
                        int image_col_offset = yStart*data_width + xStart;
                        int image_col_factor = 0;
                        for (int y=0; y<tile_height; y++) {
                                image_col_factor = 
y*data_width+image_col_offset;
                                k = y*color_length_times_texture_width;
                                for (int x=0; x<tile_width; x++) {
                                        int i = x + image_col_factor;
                                        if (!Float.isNaN(scaled_Floats[0][i])) 
{ // not missing
                                                c = (int) (255.0 * 
color_values[0][i]);
                                                r = (c < 0) ? 0 : ((c > 255) ? 
255 : c);
                                                c = (int) (255.0 * 
color_values[1][i]);
                                                g = (c < 0) ? 0 : ((c > 255) ? 
255 : c);
                                                c = (int) (255.0 * 
color_values[2][i]);
                                                b = (c < 0) ? 0 : ((c > 255) ? 
255 : c);
                                                if (color_length == 4) {
                                                        c = (int) (255.0 * 
color_values[3][i]);
                                                        a = (c < 0) ? 0 : ((c > 
255) ? 255 : c);
                                                }
                                                if (color_length == 4) {
                                                        byteData[k] = (byte) a;
                                                        byteData[k+1] = (byte) 
b;
                                                        byteData[k+2] = (byte) 
g;
                                                        byteData[k+3] = (byte) 
r;
                                                }
                                                if (color_length == 3) {
                                                        byteData[k] = (byte) b;
                                                        byteData[k+1] = (byte) 
g;
                                                        byteData[k+2] = (byte) 
r;
                                                }
                                                if (color_length == 1) {
                                                        byteData[k] = (byte) b;
                                                }       
                                        }
                                        k+=color_length;
                                }
                        }
                }
        } else if (cmaps != null) {
                Set rsets[] = null;
                if (data instanceof ImageFlatField) {
                        if (first_time) {
                                scaled_Bytes = ((FlatField) data).grabBytes();
                        }
                }
                //GHANSHAM:30AUG2011 Extract rsets from RGB FlatField
                if (data instanceof FlatField) {
                        rsets = ((FlatField) data). getRangeSets();
                }


                boolean isRGBRGBRGB = ((cmaps[0].getDisplayScalar() == 
Display.RGB) && (cmaps[1].getDisplayScalar() == Display.RGB) && 
(cmaps[2].getDisplayScalar() == Display.RGB));

                int r, g, b, c;
                int tableEnd = 0;
                if (first_time) {
                        if  (isRGBRGBRGB) { //Inserted by Ghansham (starts here)
                                int map_indx;
                                threeD_itable = new byte[cmaps.length][][];
                                for (map_indx = 0; map_indx < cmaps.length; 
map_indx++) {
                                        BaseColorControl basecolorcontrol = 
(BaseColorControl)cmaps[map_indx].getControl();
                                        float color_table[][] = 
basecolorcontrol.getTable();
                                        threeD_itable[map_indx] = new 
byte[color_table[0].length][3];
                                        int table_indx;
                                        for(table_indx = 0; table_indx < 
threeD_itable[map_indx].length; table_indx++) {
                                                c = (int) (255.0 * 
color_table[0][table_indx]);
                                                r = (c < 0) ? 0 : ((c > 255) ? 
255 : c);
                                                c = (int) (255.0 * 
color_table[1][table_indx]);
                                                g = (c < 0) ? 0 : ((c > 255) ? 
255 : c);
                                                c = (int) (255.0 * 
color_table[2][table_indx]);
                                                b = (c < 0) ? 0 : ((c > 255) ? 
255 : c);
                                                
threeD_itable[map_indx][table_indx][0] = (byte) r;
                                                
threeD_itable[map_indx][table_indx][1] = (byte) g;
                                                
threeD_itable[map_indx][table_indx][2] = (byte) b;
                                        }
                                }
                        }
                }

                if (scaled_Bytes != null) {
                        // grab bytes directly from ImageFlatField
                        if (ImageFlatField.DEBUG) {
                                
System.err.println("ShadowImageFunctionTypeJ3D.doTransform: " + "cmaps != null: 
grab bytes directly");
                        }
                        //Inserted by Ghansham starts here
                        //IFF:Assume that FlatField is of type 
(element,line)->(R,G,B) with (Display.RGB,Display.RGB,Display.RGB) as mapping
                        if  (cmaps[0].getDisplayScalar() == Display.RGB && 
cmaps[1].getDisplayScalar() == Display.RGB && cmaps[2].getDisplayScalar() == 
Display.RGB) {
                                int map_indx = 0;
                                for (map_indx = 0; map_indx < cmaps.length; 
map_indx++) {
                                        int table_length = 
threeD_itable[0].length;
                                        int color_indx = permute[map_indx];
                                        if (first_time) {
                                                scaled_Bytes[color_indx] = 
cmaps[color_indx].scaleValues(scaled_Bytes[color_indx], table_length);
                                        }
                                        int domainLength =  
scaled_Bytes[color_indx].length;
                                        int tblEnd = table_length - 1;
                                        int data_indx = 0;
                                        int texture_index = 0;

                                        int image_col_offset = 
yStart*data_width + xStart;
                                        int image_col_factor = 0;
                                        for (int y=0; y<tile_height; y++) { 
                                                image_col_factor = y*data_width 
+ image_col_offset;
                                                for (int x=0; x<tile_width; 
x++) {
                                                        data_indx = x + 
image_col_factor;
                                                        texture_index = x + 
y*texture_width;
                                                        texture_index *= 
color_length;
                                                        int j = 
scaled_Bytes[color_indx][data_indx] & 0xff; // unsigned
                                                        // clip to table
                                                        int ndx = j < 0 ? 0 : 
(j > tblEnd ? tblEnd : j);
                                                        
byteData[texture_index+(color_length-color_indx-1)]=threeD_itable[map_indx][ndx][map_indx];
 //Check if this logic works well
                                                }
                                        }

                                 }
                        } else { //Inserted by Ghansham (Ends here)
                                int data_indx = 0;
                                int texture_index = 0;
                                int offset=0;
                                c = 0;
                                if (color_length == 4) {
                                        c = (int) (255.0 * (1.0f - 
constant_alpha));
                                }
                                //IFF:with (Red,Green,Blue) or 
(Red,Green,Blue,Alpha) as mapping
                                int color_length_times_texture_width = 
color_length*texture_width;
                                int image_col_offset = yStart*data_width + 
xStart;
                                int image_col_factor = 0;
                                for (int y=0; y<tile_height; y++) {
                                        image_col_factor = y*data_width + 
image_col_offset;
                                        texture_index = 
y*color_length_times_texture_width;
                                        for (int x=0; x<tile_width; x++) {
                                                data_indx = x + 
image_col_factor;
                                                if (color_length == 4) {
                                                        byteData[texture_index] 
=   (byte)c; //a
                                                        
byteData[texture_index+1] = scaled_Bytes[2][data_indx]; //b
                                                        
byteData[texture_index+2] = scaled_Bytes[1][data_indx]; //g
                                                        
byteData[texture_index+3] = scaled_Bytes[0][data_indx]; //r

                                                } else {
                                                        byteData[texture_index] 
= scaled_Bytes[2][data_indx]; //b
                                                        
byteData[texture_index+1] = scaled_Bytes[1][data_indx]; //g
                                                        
byteData[texture_index+2] = scaled_Bytes[0][data_indx]; //r
                                                }
                                                texture_index += color_length;
                                        }
                                }

                        }
                } else {
                        if (first_time) {
                                float[][] values = ((Field) 
data).getFloats(false);
                                scaled_Floats = new float[3][];
                                for (int i = 0; i < scaled_Floats.length; i++) {
                                        //GHANSHAM:30AUG2011 Use the rset 
lookup to find scaled Range Values    
                                        if (rsets != null) {
                                                if (rsets[permute[i]] 
instanceof Integer1DSet) {
                                                        if (null == 
rset_scalarmap_lookup) {
                                                                
rset_scalarmap_lookup = new float[3][];
                                                        }
                                                        
rset_scalarmap_lookup[i] = new float[rsets[permute[i]].getLength()];
                                                        for (int j = 0; j < 
rset_scalarmap_lookup[i].length; j++) {
                                                                
rset_scalarmap_lookup[i][j] = j;
                                                        }
                                                        
rset_scalarmap_lookup[i] = 
cmaps[permute[i]].scaleValues(rset_scalarmap_lookup[i], false);
                                                        scaled_Floats[i] = 
values[permute[i]];
                                                } else {
                                                        scaled_Floats[i] = 
cmaps[permute[i]].scaleValues(values[permute[i]]);
                                                }
                                        } else {
                                                scaled_Floats[i] = 
cmaps[permute[i]].scaleValues(values[permute[i]]);
                                        }
                                }
                        }
                        c = (int) (255.0 * (1.0f - constant_alpha));
                        int a = (c < 0) ? 0 : ((c > 255) ? 255 : c);
                        int m = 0;
                        //GHANSHAM:30AUG2011 Create tableLengths for each of 
the tables separately rather than single table_length. More safe
                        int RGB_tableEnd[] = null;;
                        if  (isRGBRGBRGB) {
                                RGB_tableEnd = new int[threeD_itable.length];
                                for (int indx = 0; indx < threeD_itable.length; 
indx++) {
                                        RGB_tableEnd[indx]= 
threeD_itable[indx].length - 1;
                                }
                        }
                        int k = 0;
                        int color_length_times_texture_width = 
color_length*texture_width;
                        int image_col_offset = yStart*data_width + xStart;
                        int image_col_factor = 0;
                        for (int y=0; y<tile_height; y++) {
                                image_col_factor = y*data_width + 
image_col_offset;
                                k = y*color_length_times_texture_width;
                                for (int x=0; x<tile_width; x++) {
                                        int i = x + image_col_factor;
                                        if (!Float.isNaN(scaled_Floats[0][i]) 
&& !Float.isNaN(scaled_Floats[1][i]) && !Float.isNaN(scaled_Floats[2][i])) { // 
not missing
                                                r=0;g=0;b=0;
                                                if (isRGBRGBRGB) { //Inserted 
by Ghansham (start here)
                                                        int indx = -1;
                                                        //GHANSHAM:30AUG2011 
Use the rset_scalarmap lookup to find scaled Range Values
                                                        if 
(rset_scalarmap_lookup != null && rset_scalarmap_lookup[0] != null) {
                                                                indx = 
(int)(RGB_tableEnd[0] * rset_scalarmap_lookup[0][(int)scaled_Floats[0][i]]);
                                                        } else{
                                                                indx = 
(int)(RGB_tableEnd[0] * scaled_Floats[0][i]);
                                                        }
                                                        indx = (indx < 0) ? 0 : 
((indx > RGB_tableEnd[0]) ? RGB_tableEnd[0] : indx);
                                                        r = 
threeD_itable[0][indx][0];
                                                        //GHANSHAM:30AUG2011 
Use the rset_scalarmap lookup to find scaled Range Values
                                                        if 
(rset_scalarmap_lookup != null && rset_scalarmap_lookup[1] != null) {
                                                                indx = 
(int)(RGB_tableEnd[1] * rset_scalarmap_lookup[1][(int)scaled_Floats[1][i]]);
                                                        } else{
                                                                indx = 
(int)(RGB_tableEnd[1] * scaled_Floats[1][i]);
                                                        }
                                                        indx = (indx < 0) ? 0 : 
((indx > RGB_tableEnd[1]) ? RGB_tableEnd[1] : indx);
                                                        g = 
threeD_itable[1][indx][1];
                                                        //GHANSHAM:30AUG2011 
Use the rset_scalarmap lookup to find scaled Range Values
                                                        if 
(rset_scalarmap_lookup != null && rset_scalarmap_lookup[2] != null) {
                                                                indx = 
(int)(RGB_tableEnd[2] * rset_scalarmap_lookup[2][(int)scaled_Floats[2][i]]);
                                                        } else {
                                                                indx = 
(int)(RGB_tableEnd[2] * scaled_Floats[2][i]);
                                                        }

                                                        indx = (indx < 0) ? 0 : 
((indx > RGB_tableEnd[2]) ? RGB_tableEnd[2] : indx);
                                                        b = 
threeD_itable[2][indx][2];
                                                } else { //Inserted by Ghansham 
(ends here)
                                                        //GHANSHAM:30AUG2011 
Use the rset_scalarmap lookup to find scaled Range Values
                                                        if 
(rset_scalarmap_lookup != null && rset_scalarmap_lookup[0] != null) {
                                                                c=(int) (255.0 
* rset_scalarmap_lookup[0][(int)scaled_Floats[0][i]]);
                                                        } else {
                                                                c = (int) 
(255.0 * scaled_Floats[0][i]);
                                                        }
                                                        r = (c < 0) ? 0 : ((c > 
255) ? 255 : c);
                                                        //GHANSHAM:30AUG2011 
Use the rset_scalarmap lookup to find scaled Range Values
                                                        if 
(rset_scalarmap_lookup != null && rset_scalarmap_lookup[1] != null) {
                                                                c=(int) (255.0 
* rset_scalarmap_lookup[1][(int)scaled_Floats[1][i]]);
                                                        } else {
                                                                c = (int) 
(255.0 * scaled_Floats[1][i]);
                                                        }
                                                        g = (c < 0) ? 0 : ((c > 
255) ? 255 : c);
                                                        //GHANSHAM:30AUG2011 
Use the rset_scalarmap lookup to find scaled Range Values
                                                        if 
(rset_scalarmap_lookup != null && rset_scalarmap_lookup[2] != null) {
                                                                c=(int) (255.0 
* rset_scalarmap_lookup[2][(int)scaled_Floats[2][i]]);
                                                        } else {
                                                                c = (int) 
(255.0 * scaled_Floats[2][i]);
                                                        }
                                                        b = (c < 0) ? 0 : ((c > 
255) ? 255 : c);
                                                }
                                                if (color_length == 4) {
                                                        byteData[k] = (byte) a;
                                                        byteData[k+1] = (byte) 
b;
                                                        byteData[k+2] = (byte) 
g;
                                                        byteData[k+3] = (byte) 
r;
                                                } if (color_length == 3) {
                                                        byteData[k] = (byte) b;
                                                        byteData[k+1] = (byte) 
g;
                                                        byteData[k+2] = (byte) 
r;
                                                }
                                                if (color_length == 1) {
                                                        byteData[k] = (byte) b;
                                                }
                                        }
                                        k+=color_length;
                                }
                        }
                        RGB_tableEnd = null;
                }
        } else {
                throw new BadMappingException("cmap == null and cmaps == null 
??");
        }
}


  public void buildCurvedTexture(Object group, Set domain_set, Unit[] 
dataUnits, Unit[] domain_units,
                                 float[] default_values, ShadowRealType[] 
DomainComponents,
                                 int valueArrayLength, int[] inherited_values, 
int[] valueToScalar,
                                 GraphicsModeControl mode, float 
constant_alpha, float[] value_array, 
                                 float[] constant_color, DisplayImpl display,
                                 int curved_size, ShadowRealTupleType Domain, 
CoordinateSystem dataCoordinateSystem,
                                 DataRenderer renderer, ShadowFunctionOrSetType 
adaptedShadowType,
                                 int[] start, int lenX, int lenY, float[][] 
samples, int bigX, int bigY,
                                 VisADImageTile tile, float topo_samples[], 
ScalarMap topo_map)
         throws VisADException, DisplayException {
    float[] coordinates = null;
    float[] texCoords = null;
    int data_width = 0;
    int data_height = 0;
    int texture_width = 1;
    int texture_height = 1;

    int[] lengths = null;

    if (dataCoordinateSystem instanceof CachingCoordinateSystem) {
        dataCoordinateSystem = 
((CachingCoordinateSystem)dataCoordinateSystem).getCachedCoordinateSystem();
    }

    // get domain_set sizes
    if (domain_set != null) {
      lengths = ((GriddedSet) domain_set).getLengths();
    }
    else {
      lengths = new int[] {lenX, lenY};
    }

    data_width = lengths[0];
    data_height = lengths[1];

    // texture sizes must be powers of two on older graphics cards.
    texture_width = textureWidth(data_width);
    texture_height = textureHeight(data_height);
                                                                                
                                   
    // transform for any CoordinateSystem in data (Field) Domain
    ShadowRealTupleType domain_reference = Domain.getReference();
    ShadowRealType[] DC = DomainComponents;

    if (domain_reference != null &&
        domain_reference.getMappedDisplayScalar()) {
      RealTupleType ref = (RealTupleType) domain_reference.getType();
      renderer.setEarthSpatialData(Domain, domain_reference, ref,
                  ref.getDefaultUnits(), (RealTupleType) Domain.getType(),
                  new CoordinateSystem[] {dataCoordinateSystem},
                  domain_units);

      // ShadowRealTypes of DomainReference
      DC = adaptedShadowType.getDomainReferenceComponents();
    }
    else {
      RealTupleType ref = (domain_reference == null) ? null :
                          (RealTupleType) domain_reference.getType();
      Unit[] ref_units = (ref == null) ? null : ref.getDefaultUnits();
      renderer.setEarthSpatialData(Domain, domain_reference, ref,
                  ref_units, (RealTupleType) Domain.getType(),
                  new CoordinateSystem[] {dataCoordinateSystem},
                  domain_units);
    }
                                                                                
                                   
    int[] tuple_index = new int[3];
    int[] spatial_value_indices = {-1, -1, -1};
    ScalarMap[] spatial_maps = new ScalarMap[3];
                                                                                
                                   
    DisplayTupleType spatial_tuple = null;
    for (int i=0; i<DC.length; i++) {
      Enumeration maps =
        DC[i].getSelectedMapVector().elements();
      ScalarMap map = (ScalarMap) maps.nextElement();
      DisplayRealType real = map.getDisplayScalar();
      spatial_tuple = real.getTuple();
      if (spatial_tuple == null) {
        throw new DisplayException("texture with bad tuple: " +
                                   "ShadowImageFunctionTypeJ3D.doTransform");
      }
      // get spatial index
      tuple_index[i] = real.getTupleIndex();
      spatial_value_indices[tuple_index[i]] = map.getValueIndex();
      spatial_maps[tuple_index[i]] = map;
      if (maps.hasMoreElements()) {
        throw new DisplayException("texture with multiple spatial: " +
                                   "ShadowImageFunctionTypeJ3D.doTransform");
      }
    } // end for (int i=0; i<DC.length; i++)


    // get spatial index not mapped from domain_set
    tuple_index[2] = 3 - (tuple_index[0] + tuple_index[1]);
    DisplayRealType real =
      (DisplayRealType) spatial_tuple.getComponent(tuple_index[2]);
    int value2_index = display.getDisplayScalarIndex(real);
    float value2 = default_values[value2_index];

    /*for (int i=0; i<valueArrayLength; i++) {
      if (inherited_values[i] > 0 &&
          real.equals(display.getDisplayScalar(valueToScalar[i])) ) {
        value2 = value_array[i];
        break;
      }
    }*/
         //To take care of Z mapping of RGB values                              
                                                                            
        if (null == topo_samples) {
                for (int i=0; i<valueArrayLength; i++) {
                        if (inherited_values[i] > 0 && 
real.equals(display.getDisplayScalar(valueToScalar[i])) ) {
                                value2 = value_array[i];
                                break;
                        }
                }
        } else {
                
                spatial_maps[tuple_index[2]] = topo_map;
        }
    boolean useLinearTexture = false;
    double[] scale = null;
    double[] offset = null;
    CoordinateSystem coord = null;

    if (spatial_tuple.equals(Display.DisplaySpatialCartesianTuple)) {
// inside 'if (anyFlow) {}' in ShadowType.assembleSpatial()
        renderer.setEarthSpatialDisplay(null, spatial_tuple, display,
               spatial_value_indices, default_values, null);
    } else {
        coord = spatial_tuple.getCoordinateSystem();

        if (coord instanceof CachingCoordinateSystem) {
                coord = 
((CachingCoordinateSystem)coord).getCachedCoordinateSystem();
        }

        if (coord instanceof InverseLinearScaledCS) {
                InverseLinearScaledCS invCS = (InverseLinearScaledCS)coord;
                //useLinearTexture = 
(invCS.getInvertedCoordinateSystem()).equals(dataCoordinateSystem);
                //To take care of Z mapping of RGB values                       
                                                                                
   
                useLinearTexture = 
(invCS.getInvertedCoordinateSystem()).equals(dataCoordinateSystem) && (null == 
topo_samples);
                scale = invCS.getScale();
                offset = invCS.getOffset();
        }

// inside 'if (anyFlow) {}' in ShadowType.assembleSpatial()
        renderer.setEarthSpatialDisplay(coord, spatial_tuple, display,
               spatial_value_indices, default_values, null);
    }
    if (useLinearTexture) {
        float scaleX = (float) scale[0];
        float scaleY = (float) scale[1];
        float offsetX = (float) offset[0];
        float offsetY = (float) offset[1];

        float[][] xyCoords = null;
        if (domain_set != null) {
                xyCoords = getBounds(domain_set, data_width, data_height, 
scaleX, offsetX, scaleY, offsetY);
        } else {
                //If there is tiling in linear texture domain set is coming 
null if number of tiles is greater than 1
                //Code inserted by Ghansham (starts here)
                int indx0 = (start[0]) + (start[1])*bigX;
                int indx1 = (start[0]) + (start[1] + lenY-1)*bigX;
                int indx2 = (start[0] + lenX -1) + (start[1] + lenY - 1)*bigX;
                int indx3 = (start[0] + lenX -1 ) + (start[1])*bigX;

                float x0 = samples[0][indx0];
                float y0 = samples[1][indx0];
                float x1 = samples[0][indx1];
                float y1 = samples[1][indx1];
                float x2 = samples[0][indx2];
                float y2 = samples[1][indx2];
                float x3 = samples[0][indx3];
                float y3 = samples[1][indx3];

                xyCoords = new float[2][4];
                xyCoords[0][0] = (x0 - offsetX)/scaleX;
                xyCoords[1][0] = (y0 - offsetY)/scaleY;

                xyCoords[0][1] = (x1 - offsetX)/scaleX;
                xyCoords[1][1] = (y1 - offsetY)/scaleY;

                xyCoords[0][2] = (x2 - offsetX)/scaleX;
                xyCoords[1][2] = (y2 - offsetY)/scaleY;

                xyCoords[0][3] = (x3 - offsetX)/scaleX;
                xyCoords[1][3] = (y3 - offsetY)/scaleY;
                //Code inserted by Ghansham (Ends here)
        }


      // create VisADQuadArray that texture is mapped onto
      coordinates = new float[12];
      // corner 0 (-1,1)
      coordinates[tuple_index[0]] = xyCoords[0][0];
      coordinates[tuple_index[1]] = xyCoords[1][0];
      coordinates[tuple_index[2]] = value2;
      // corner 1 (-1,-1)
      coordinates[3+tuple_index[0]] = xyCoords[0][1];
      coordinates[3+tuple_index[1]] = xyCoords[1][1];
      coordinates[3 + tuple_index[2]] = value2;
      // corner 2 (1, -1)
      coordinates[6+tuple_index[0]] = xyCoords[0][2];
      coordinates[6+tuple_index[1]] = xyCoords[1][2];
      coordinates[6 + tuple_index[2]] = value2;
      // corner 3 (1,1)
      coordinates[9+tuple_index[0]] = xyCoords[0][3];
      coordinates[9+tuple_index[1]] = xyCoords[1][3];
      coordinates[9 + tuple_index[2]] = value2;

      // move image back in Java3D 2-D mode
      adjustZ(coordinates);

      texCoords = new float[8];
      float ratiow = ((float) data_width) / ((float) texture_width);
      float ratioh = ((float) data_height) / ((float) texture_height);

      boolean yUp = true;
      setTexCoords(texCoords, ratiow, ratioh, yUp);

      VisADQuadArray qarray = new VisADQuadArray();
      qarray.vertexCount = 4;
      qarray.coordinates = coordinates;
      qarray.texCoords = texCoords;

      /*REUSE GEOM/COLORBYTES:I have replaced reuse with reuseImages.
      And here in the else logic I have added a few more lines. 
        The else part of this never got executed because reuse was always false.
        Now else part gets executed when reuse is true and either regen_geom or 
regen_colbytes is true.
        It just applies geometry to the already available texture.
        When both are true then if part gets executed. 
    */
        //if (!reuse) 
        if (!reuseImages || (regen_colbytes && regen_geom)) {   //REUSE 
GEOM/COLORBYTES: Earlier reuse variable was used. Replaced it with reuseImages 
and regeom_colbytes and regen_geom
                BufferedImage image = tile.getImage(0);
                textureToGroup(group, qarray, image, mode, constant_alpha,
                        constant_color, texture_width, texture_height, true, 
true, tile, false);
        } else {        //REUSE GEOM/COLORBYTES: reuse the colorbytes just 
apply the geometry
                int num_children = ((BranchGroup) group).numChildren();
                if (num_children > 0) {
                        BranchGroup branch1 = (BranchGroup) ((BranchGroup) 
group).getChild(0); //This the branch group created by textureToGroup Function
                        Shape3D shape = (Shape3D) branch1.getChild(0);
                        shape.setGeometry(((DisplayImplJ3D) 
display).makeGeometry(qarray));
                }
 
                if (animControl == null) {
                        imgNode.setCurrent(0);
                }
        }

    }
    else {
      // compute size of triangle array to map texture onto
      int size = (data_width + data_height) / 2;
      curved_size = Math.max(1, Math.min(curved_size, size / 32));
      int nwidth = 2 + (data_width - 1) / curved_size;
      int nheight = 2 + (data_height - 1) / curved_size;

      // compute locations of triangle vertices in texture
      int nn = nwidth * nheight;
      int[] is = new int[nwidth];
      int[] js = new int[nheight];

      for (int i=0; i<nwidth; i++) {
        is[i] = Math.min(i * curved_size, data_width - 1);
      }
      for (int j=0; j<nheight; j++) {
        js[j] = Math.min(j * curved_size, data_height - 1);
      }
        

      // get spatial coordinates at triangle vertices
      int k = 0;
      float[][] spline_domain = null;
         //To take care of Z mapping of RGB values                              
                                                                            
        float[] extracted_topo_samples = null;
        if (null != topo_samples) {
                extracted_topo_samples = new float[nn];
        }

      if (domain_set == null) {
        //Ghansham: We generate the indices for the samples directly from 'is' 
and 'js' array
        spline_domain = new float[2][nn];
        int kk = 0;
        int ndx = 0;
        int col_factor = 0;
        for (int j = 0; j < nheight; j++) {
            col_factor = (start[1] + js[j]) * bigX;
            for (int i = 0; i < nwidth; i++) {
                ndx = (start[0] + is[i]) + col_factor;
                spline_domain[0][kk] = samples[0][ndx];
                spline_domain[1][kk] = samples[1][ndx];
                //To take care of Z mapping of RGB values                       
                                                                                
   
                 if (null != topo_samples) {
                        extracted_topo_samples[kk] = topo_samples[ndx];
                }

                kk++;
            }
        }
      }
      else {
        int[] indices = new int[nn]; //Ghansham:Calculate indices only if there 
is a single tile in the full image
        k=0;
        int col_factor;
        for (int j=0; j<nheight; j++) {
                col_factor = data_width * js[j];
                for (int i=0; i<nwidth; i++) {
                        indices[k] = is[i] + col_factor;
                        if (null != topo_samples) {
                                extracted_topo_samples[k] = 
topo_samples[indices[k]];
                        }
                        k++;
                } 
        }
        spline_domain = domain_set.indexToValue(indices);
        indices = null;
      }

      spline_domain = Unit.convertTuple(spline_domain, dataUnits, domain_units, 
false);


       if (domain_reference != null
             && domain_reference.getMappedDisplayScalar()) {
           RealTupleType ref = (RealTupleType) domain_reference.getType();

            spline_domain =
                   CoordinateSystem.transformCoordinates(
                   ref, null, ref.getDefaultUnits(), null,
                   (RealTupleType) Domain.getType(), dataCoordinateSystem,
                   domain_units, null, spline_domain);
       }

       float[][] spatial_values = new float[3][];
       spatial_values[tuple_index[0]] = spline_domain[0];
       spatial_values[tuple_index[1]] = spline_domain[1];
       boolean isSpherical = 
spatial_tuple.equals(Display.DisplaySpatialSphericalTuple);
        if (isSpherical || topo_samples != null) { 
                spatial_values[tuple_index[2]] = new float[nn];
                if (topo_samples != null) {
                        spatial_values[tuple_index[2]] = extracted_topo_samples;
                } else {
                        Arrays.fill(spatial_values[tuple_index[2]], value2);
                }
        } 
       for (int i = 0; i < 3; i++) {                
          if (spatial_maps[i] != null) {
             spatial_values[i] = spatial_maps[i].scaleValues(spatial_values[i], 
false);
          }
       }

       if (!spatial_tuple.equals(Display.DisplaySpatialCartesianTuple)) {
          spatial_values = coord.toReference(spatial_values);
       }

      boolean spatial_all_select = true;

       if (isSpherical || topo_samples != null) {
            for (int i=0; i<nn; i++) {
               if (Float.isNaN(spatial_values[0][i]) || 
Float.isNaN(spatial_values[1][i]) || Float.isNaN(spatial_values[2][i])) {
                      spatial_all_select = false;
                      break;
               }
            }
       } else {
            if (Float.isNaN(value2)) {
                 spatial_all_select = false;
            } else {
                 for (int i=0; i<nn; i++) {
                      if (Float.isNaN(spatial_values[0][i]) || 
Float.isNaN(spatial_values[1][i])) {
                          spatial_all_select = false;
                          break;
                      }
                 }
           }
       } 

                                                                                
                                   
    VisADTriangleStripArray tarray = new VisADTriangleStripArray();
    tarray.stripVertexCounts = new int[nheight - 1];
    java.util.Arrays.fill(tarray.stripVertexCounts, 2 * nwidth);

    int len = (nheight - 1) * (2 * nwidth);
    tarray.vertexCount = len;
    tarray.coordinates = new float[3 * len];
    tarray.texCoords = new float[2 * len];
        /*float temp_normals[] = null;
        float temp_coords[] = null;
        int normalLength;
        int normalLengthX3;*/
        float normals[][] = null;
        if (topo_samples != null) {
                normals = makeNormals(spatial_values, nwidth, nheight);
                tarray.normals = new float[3 *len];
        }
        
                                                                                
                                   
    int m = 0;
    k = 0;
    int kt = 0;
        
        float y_coord = 0f; 
        float y_coord2 = 0f;
        float  x_coord = 0f;
        boolean use_z_samples = (isSpherical || null != topo_samples);
    for (int j=0; j<nheight-1; j++) {
        if (0 ==j){
                y_coord = (0.5f + js[j])/texture_height;
        } else {
                y_coord = y_coord2;
        }
        y_coord2 = (0.5f + js[j+1])/texture_height;
        for (int i=0; i<nwidth; i++) {
                tarray.coordinates[k] = spatial_values[0][m];
                tarray.coordinates[k+1] = spatial_values[1][m];
                tarray.coordinates[k+2] = use_z_samples ? spatial_values[2][m] 
: value2;
                tarray.coordinates[k+3] = spatial_values[0][m+nwidth];
                tarray.coordinates[k+4] = spatial_values[1][m+nwidth];
                tarray.coordinates[k+5] = use_z_samples ? 
spatial_values[2][m+nwidth]: value2;
                if (null != topo_samples) {
                        tarray.normals[k] =   normals[0][m];
                        tarray.normals[k+1] = normals[1][m]; 
                        tarray.normals[k+2] = normals[2][m];
                        tarray.normals[k+3] = normals[0][m+nwidth];
                        tarray.normals[k+4] = normals[1][m+nwidth];
                        tarray.normals[k+5] = normals[2][m+nwidth];
                }

                x_coord = (0.5f + is[i])/texture_width;
                tarray.texCoords[kt++] = x_coord;
                tarray.texCoords[kt++] = y_coord;
                tarray.texCoords[kt++] = x_coord;
                tarray.texCoords[kt++] = y_coord2;
                m += 1;
                k+=6;
      }
    }
        normals = null;
        is = null;
        js = null;
        extracted_topo_samples = null;
        spatial_values[0] = null;
        spatial_values[1] = null;
        spatial_values[2] = null;
        spatial_values = null;
        spline_domain[0] = null;
        spline_domain[1] = null;
        spline_domain = null;
    // do surgery to remove any missing spatial coordinates in texture
    if (!spatial_all_select) {
      tarray = (VisADTriangleStripArray) tarray.removeMissing();
    }

    // do surgery along any longitude split (e.g., date line) in texture
    if (adaptedShadowType.getAdjustProjectionSeam()) {
      tarray = (VisADTriangleStripArray) tarray.adjustLongitude(renderer);
      tarray = (VisADTriangleStripArray) tarray.adjustSeam(renderer);
    }
    
    /*REUSE GEOM/COLORBYTES:I have replaced reuse with reuseImages.
        And here in the else logic I have added a few more lines. 
        The else part of this never got executed because reuse was always false.
        Now else part gets executed when reuseImages is true or either 
regen_geom or regen_colbytes is true.
        It just applies geometry to the already available texture.
        When both regen_geom or regen_colbytes are true then if part gets 
executed. 
    */                                                                          
                                     
    // add texture as sub-node of group in scene graph
        //if (!reuse) 
        if (!reuseImages || (regen_colbytes && regen_geom)) { //REUSE 
GEOM/COLORBYTES: Earlier reuse variable was used. Replaced it with reuseImages 
and regeom_colbytes and regen_geom
                BufferedImage image = tile.getImage(0);
                textureToGroup(group, tarray, image, mode, constant_alpha, 
constant_color, texture_width, texture_height, true, true, tile, null != 
topo_samples);
        } else { //REUSE GEOM/COLORBYTES: Reuse the colorbytes and just apply 
the geometry
                int num_children = ((BranchGroup) group).numChildren();
                if (num_children > 0) {
                        BranchGroup branch1 = (BranchGroup) ((BranchGroup) 
group).getChild(0); //This is the branch group created by textureToGroup 
Function
                        Shape3D shape = (Shape3D) branch1.getChild(0);
                        shape.setGeometry(((DisplayImplJ3D) 
display).makeGeometry(tarray));
                        
                } 
                if (animControl == null) {
                        imgNode.setCurrent(0);
                }
        }

   }
        tuple_index = null;
// System.out.println("end curved texture " + (System.currentTimeMillis() - 
link.start_time));
  }

  public void buildLinearTexture(Object group, Set domain_set, Unit[] 
dataUnits, Unit[] domain_units,
                                 float[] default_values, ShadowRealType[] 
DomainComponents,
                                 int valueArrayLength, int[] inherited_values, 
int[] valueToScalar,
                                 GraphicsModeControl mode, float constant_alpha,
                                 float[] value_array, float[] constant_color, 
DisplayImpl display,
                                 VisADImageTile tile)
         throws VisADException, DisplayException {

    float[] coordinates = null;
    float[] texCoords = null;
    float[] normals = null;
    int data_width = 0;
    int data_height = 0;
    int texture_width = 1;
    int texture_height = 1;

    Linear1DSet X = null;
    Linear1DSet Y = null;
    if (domain_set instanceof Linear2DSet) {
      X = ((Linear2DSet) domain_set).getX();
      Y = ((Linear2DSet) domain_set).getY();
    }
    else {
      X = ((LinearNDSet) domain_set).getLinear1DComponent(0);
      Y = ((LinearNDSet) domain_set).getLinear1DComponent(1);
    }
    float[][] limits = new float[2][2];
    limits[0][0] = (float) X.getFirst();
    limits[0][1] = (float) X.getLast();
    limits[1][0] = (float) Y.getFirst();
    limits[1][1] = (float) Y.getLast();
                                                                                
                                       
    // get domain_set sizes
    data_width = X.getLength();
    data_height = Y.getLength();
    // texture sizes must be powers of two on older graphics cards
    texture_width = textureWidth(data_width);
    texture_height = textureHeight(data_height);
                                                                                
                                       
                                                                                
                                       
    // WLH 27 Jan 2003
    float half_width = 0.5f / ((float) (data_width - 1));
    float half_height = 0.5f / ((float) (data_height - 1));
    half_width = (limits[0][1] - limits[0][0]) * half_width;
    half_height = (limits[1][1] - limits[1][0]) * half_height;
    limits[0][0] -= half_width;
    limits[0][1] += half_width;
    limits[1][0] -= half_height;
    limits[1][1] += half_height;
                                                                                
                                       
                                                                                
                                       
    // convert values to default units (used in display)
    limits = Unit.convertTuple(limits, dataUnits, domain_units);

    int[] tuple_index = new int[3];
    if (DomainComponents.length != 2) {
      throw new DisplayException("texture domain dimension != 2:" +
                                 "ShadowFunctionOrSetType.doTransform");
    }
                                                                                
                                       
    // find the spatial ScalarMaps
    for (int i=0; i<DomainComponents.length; i++) {
      Enumeration maps = DomainComponents[i].getSelectedMapVector().elements();
      ScalarMap map = (ScalarMap) maps.nextElement();
      // scale values
      limits[i] = map.scaleValues(limits[i]);
      DisplayRealType real = map.getDisplayScalar();
      DisplayTupleType tuple = real.getTuple();
      if (tuple == null ||
          !tuple.equals(Display.DisplaySpatialCartesianTuple)) {
        throw new DisplayException("texture with bad tuple: " +
                                   "ShadowFunctionOrSetType.doTransform");
      }
      // get spatial index
      tuple_index[i] = real.getTupleIndex();
      if (maps.hasMoreElements()) {
        throw new DisplayException("texture with multiple spatial: " +
                                   "ShadowFunctionOrSetType.doTransform");
      }
    } // end for (int i=0; i<DomainComponents.length; i++)


    // get spatial index not mapped from domain_set
    tuple_index[2] = 3 - (tuple_index[0] + tuple_index[1]);
    DisplayRealType real = (DisplayRealType)
      Display.DisplaySpatialCartesianTuple.getComponent(tuple_index[2]);
    int value2_index = display.getDisplayScalarIndex(real);
    float value2 = default_values[value2_index];
    for (int i=0; i<valueArrayLength; i++) {
      if (inherited_values[i] > 0 &&
          real.equals(display.getDisplayScalar(valueToScalar[i])) ) {
        // value for unmapped spatial dimension
        value2 = value_array[i];
        break;
      }
    }

    // create VisADQuadArray that texture is mapped onto
    coordinates = new float[12];
    // corner 0
    coordinates[tuple_index[0]] = limits[0][0];
    coordinates[tuple_index[1]] = limits[1][0];
    coordinates[tuple_index[2]] = value2;
    // corner 1
    coordinates[3 + tuple_index[0]] = limits[0][0];
    coordinates[3 + tuple_index[1]] = limits[1][1];
    coordinates[3 + tuple_index[2]] = value2;
    // corner 2
    coordinates[6 + tuple_index[0]] = limits[0][1];
    coordinates[6 + tuple_index[1]] = limits[1][1];
    coordinates[6 + tuple_index[2]] = value2;
    // corner 3
    coordinates[9 + tuple_index[0]] = limits[0][1];
    coordinates[9 + tuple_index[1]] = limits[1][0];
    coordinates[9 + tuple_index[2]] = value2;
                                                                                
                                       
    // move image back in Java3D 2-D mode
    adjustZ(coordinates);
                                                                                
                                       
    texCoords = new float[8];
    float ratiow = ((float) data_width) / ((float) texture_width);
    float ratioh = ((float) data_height) / ((float) texture_height);

    boolean yUp = true;
    setTexCoords(texCoords, ratiow, ratioh, yUp);
                                                                                
                                       
    VisADQuadArray qarray = new VisADQuadArray();
    qarray.vertexCount = 4;
    qarray.coordinates = coordinates;
    qarray.texCoords = texCoords;
 
    /*REUSE GEOM/COLORBYTES:I have replaced reuse with reuseImages.
      And here in the else logic I have added a few more lines. 
        The else part of this never got executed because reuse was always false.
        Now else part gets executed when reuse is true and either regen_geom or 
regen_colbytes is true.
        It just applies geometry to the already available texture.
        When both are true then if part gets executed. 
    */                                                                          
                                            
    // add texture as sub-node of group in scene graph
    if (!reuseImages|| (regen_colbytes && regen_geom)) { //REUSE 
GEOM/COLORBYTES: Earlier reuse variable was used. Replaced it with reuseImages 
and regeom_colbytes and regen_geom
      BufferedImage image = tile.getImage(0);
      textureToGroup(group, qarray, image, mode, constant_alpha,
                     constant_color, texture_width, texture_height, true, true, 
tile, false);
    }
    else {
        int num_children = ((BranchGroup) group).numChildren();
        if (num_children > 0) { //REUSE GEOM/COLORBYTES: Reuse the colorbytes 
and apply geometry
                BranchGroup branch1 = (BranchGroup) ((BranchGroup) 
group).getChild(0); //This the branch group created by textureToGroup Function
                Shape3D shape = (Shape3D) branch1.getChild(0);
                shape.setGeometry(((DisplayImplJ3D) 
display).makeGeometry(qarray));
        }
      if (animControl == null) {
        imgNode.setCurrent(0);
      }
    }

  }

  //public CachedBufferedByteImage createImageByRef(final int texture_width, 
final int texture_height, final int imageType) {
  public BufferedImage createImageByRef(final int texture_width, final int 
texture_height, final int imageType) {
      return new BufferedImage(texture_width, texture_height, imageType);
  }

  public static float[][] getBounds(Set domain_set, float data_width, float 
data_height,
           float scaleX, float offsetX, float scaleY, float offsetY)
      throws VisADException
  {
    float[][] xyCoords = new float[2][4];

    float[][] coords0 = ((GriddedSet)domain_set).gridToValue(new float[][] 
{{0f},{0f}});
    float[][] coords1 = ((GriddedSet)domain_set).gridToValue(new float[][] 
{{0f},{(float)(data_height-1)}});
    float[][] coords2 = ((GriddedSet)domain_set).gridToValue(new float[][] 
{{(data_width-1f)},{(data_height-1f)}});
    float[][] coords3 = ((GriddedSet)domain_set).gridToValue(new float[][] 
{{(data_width-1f)},{0f}});

    float x0 = coords0[0][0];
    float y0 = coords0[1][0];
    float x1 = coords1[0][0];
    float y1 = coords1[1][0];
    float x2 = coords2[0][0];
    float y2 = coords2[1][0];
    float x3 = coords3[0][0];
    float y3 = coords3[1][0];

    xyCoords[0][0] = (x0 - offsetX)/scaleX;
    xyCoords[1][0] = (y0 - offsetY)/scaleY;

    xyCoords[0][1] = (x1 - offsetX)/scaleX;
    xyCoords[1][1] = (y1 - offsetY)/scaleY;

    xyCoords[0][2] = (x2 - offsetX)/scaleX;
    xyCoords[1][2] = (y2 - offsetY)/scaleY;

    xyCoords[0][3] = (x3 - offsetX)/scaleX;
    xyCoords[1][3] = (y3 - offsetY)/scaleY;

    return xyCoords;
  }

public float[][] makeNormals(float[][] coordinates, int LengthX, int LengthY) {
        int Length = LengthX * LengthY;

        //float[] normals = new float[3 * Length];
        float normals[][] = new float[3][Length];
        int k = 0;
        int ki, kj;
        int LengthX3 = 3 * LengthX;
        for (int i = 0; i < LengthY; i++) {
                for (int j = 0; j < LengthX; j++) {
                        /*float c0 = coordinates[k];
                        float c1 = coordinates[k + 1];
                        float c2 = coordinates[k + 2];*/
                        float c0 = coordinates[0][k];
                        float c1 = coordinates[1][k];
                        float c2 = coordinates[2][k];
                        float n0 = 0.0f;
                        float n1 = 0.0f;
                        float n2 = 0.0f;
                        float n, m, m0, m1, m2, q0, q1, q2;
                        for (int ip = -1; ip <= 1; ip += 2) {
                                for (int jp = -1; jp <= 1; jp += 2) {
                                        int ii = i + ip;
                                        int jj = j + jp;
                                        if (0 <= ii && ii < LengthY && 0 <= jj 
&& jj < LengthX) {
                                                ki = k + ip * LengthX;
                                                kj = k + jp;
                                                /*ki = k + ip * LengthX3;
                                                kj = k + jp * 3;
                                                m0 = (coordinates[kj + 2] - c2) 
* (coordinates[ki + 1] - c1) - (coordinates[kj + 1] - c1) * (coordinates[ki + 
2] - c2);
                                                m1 = (coordinates[kj] - c0) * 
(coordinates[ki + 2] - c2) - (coordinates[kj + 2] - c2) * (coordinates[ki] - 
c0);
                                                m2 = (coordinates[kj + 1] - c1) 
* (coordinates[ki] - c0) - (coordinates[kj] - c0) * (coordinates[ki + 1] - 
c1);*/
                                                m0 = (coordinates[2][kj] - c2) 
* (coordinates[1][ki] - c1) - (coordinates[1][kj] - c1) * (coordinates[2][ki] - 
c2);
                                                m1 = (coordinates[0][kj] - c0) 
* (coordinates[2][ki] - c2) - (coordinates[2][kj] - c2) * (coordinates[0][ki] - 
c0);
                                                m2 = (coordinates[1][kj] - c1) 
* (coordinates[0][ki] - c0) - (coordinates[0][kj] - c0) * (coordinates[1][ki] - 
c1);

                                                m = (float) Math.sqrt(m0 * m0 + 
m1 * m1 + m2 * m2);
                                                if (ip == jp) {
                                                        q0 = m0 / m;
                                                        q1 = m1 / m;
                                                        q2 = m2 / m;
                                                } else {
                                                        q0 = -m0 / m;
                                                        q1 = -m1 / m;
                                                        q2 = -m2 / m;
                                                }
                                                if (q0 == q0) {
                                                        n0 += q0;
                                                        n1 += q1;
                                                        n2 += q2;
                                                } else {
                 
                                                }
                                        }
                                }
                        }
                        n = (float) Math.sqrt(n1 * n0 + n1 * n1 + n2 * n2);
                        /*normals[k] = n0 / n;
                        normals[k + 1] = n1 / n;
                        normals[k + 2] = n2 / n;*/
                        normals[0][k] = n0 / n;
                        normals[1][k] = n1 / n;
                        normals[2][k] = n2 / n;
                        if (normals[0][k] != normals[0][k]) {
                                normals[0][k] = 0.0f;
                                normals[1][k] = 0.0f;
                                normals[2][k] = -1.0f;
                        }
                        /*if (normals[k] != normals[k]) {
                                normals[k] = 0.0f;
                                normals[k + 1] = 0.0f;
                                normals[k + 2] = -1.0f;
                        }
                        k+= 3;*/

                        k+=1;
                } // end for (int j=0; j<LengthX; j++)
        } // end for (int i=0; i<LengthY; i++)
        return normals;
  }


}


class SwitchNotify extends Switch {
  VisADImageNode imgNode;
  int numChildren;
  Switch swit;

  SwitchNotify(VisADImageNode imgNode, int numChildren) {
    super();
    this.imgNode = imgNode;
    this.numChildren = numChildren;
    this.swit = imgNode.getSwitch();
  }

  public int numChildren() {
    return numChildren;
  }

  public void setWhichChild(int index) {
    if (index == Switch.CHILD_NONE) {
      swit.setWhichChild(Switch.CHILD_NONE);
    }
    else if (index >= 0) {
      if ( swit.getWhichChild() == Switch.CHILD_NONE) {
        swit.setWhichChild(0);
      }
      imgNode.setCurrent(index);
    }
  }
}


class Mosaic {

  Tile[][] tiles;
  ArrayList<Tile>  tileList = new ArrayList<Tile>();

  int n_x_sub = 1;
  int n_y_sub = 1;

  Mosaic(int lenY, int limitY, int lenX, int limitX) {

    int y_sub_len = limitY;
    n_y_sub = lenY/y_sub_len;
    if (n_y_sub == 0) n_y_sub++;
    if ((lenY - n_y_sub*y_sub_len) > 4) n_y_sub += 1;

    int[][] y_start_stop = new int[n_y_sub][2];
    for (int k = 0; k < n_y_sub-1; k++) {
       y_start_stop[k][0] = k*y_sub_len - k;
       y_start_stop[k][1] = ((k+1)*y_sub_len - 1) - k;
       // check that we don't exceed limit
       if ( ((y_start_stop[k][1]-y_start_stop[k][0])+1) > limitY) {
         y_start_stop[k][1] -= 1; //too big, take away gap fill
       }
    }
    int k = n_y_sub-1;
    y_start_stop[k][0] = k*y_sub_len - k;
    y_start_stop[k][1] = lenY - 1 - k;

    int x_sub_len = limitX;
    n_x_sub = lenX/x_sub_len;
    if (n_x_sub == 0) n_x_sub++;
    if ((lenX - n_x_sub*x_sub_len) > 4) n_x_sub += 1;

    int[][] x_start_stop = new int[n_x_sub][2];
    for (k = 0; k < n_x_sub-1; k++) {
      x_start_stop[k][0] = k*x_sub_len - k;
      x_start_stop[k][1] = ((k+1)*x_sub_len - 1) - k;
      // check that we don't exceed limit
      if ( ((x_start_stop[k][1]-x_start_stop[k][0])+1) > limitX) {
        x_start_stop[k][1] -= 1; //too big, take away gap fill
      }
    }
    k = n_x_sub-1; 
    x_start_stop[k][0] = k*x_sub_len - k;
    x_start_stop[k][1] = lenX - 1 - k;

    tiles = new Tile[n_y_sub][n_x_sub];

    for (int j=0; j<n_y_sub; j++) {
      for (int i=0; i<n_x_sub; i++) {
         tiles[j][i] =
           new Tile(y_start_stop[j][0], y_start_stop[j][1], x_start_stop[i][0], 
x_start_stop[i][1]);
         tileList.add(tiles[j][i]);
      }
    }
  }

  Iterator iterator() {
    return tileList.iterator();
  }
}

class Tile {
   int y_start;
   int x_start;
   int y_stop;
   int x_stop;
 
   int height;
   int width;

   Tile(int y_start, int y_stop, int x_start, int x_stop) {
     this.y_start = y_start;
     this.y_stop = y_stop;
     this.x_start = x_start;
     this.x_stop = x_stop;
     
     height = y_stop - y_start + 1;
     width = x_stop - x_start + 1;
   }
}