示例#1
0
  /**
   * Sets the SharedGroup reference.
   *
   * @param sharedGroup the SharedGroup node
   */
  void setSharedGroup(SharedGroup sharedGroup) {
    // Note that it is possible that the sharedGroup pass
    // in already link to another link and live.
    HashKey newKeys[] = null;
    boolean abort = false;

    if (source.isLive()) {
      // bug 4370407: if sharedGroup is a parent, then don't do anything
      if (sharedGroup != null) {
        synchronized (universe.sceneGraphLock) {
          NodeRetained pa;
          for (pa = parent; pa != null; pa = pa.parent) {
            if (pa == (NodeRetained) sharedGroup.retained) {
              abort = true;
              throw new SceneGraphCycleException(J3dI18N.getString("LinkRetained1"));
            }
          }
        }
        if (abort) return;
      }

      newKeys = getNewKeys(locale.nodeId, localToVworldKeys);

      if (this.sharedGroup != null) {
        ((GroupRetained) parent).checkClearLive(this.sharedGroup, newKeys, true, null, 0, 0, this);
        this.sharedGroup.parents.remove(this);
      }
    }

    if (sharedGroup != null) {
      this.sharedGroup = (SharedGroupRetained) sharedGroup.retained;
    } else {
      this.sharedGroup = null;
    }

    if (source.isLive() && (sharedGroup != null)) {

      this.sharedGroup.parents.add(this);
      visited = true;
      try {
        int ci = ((GroupRetained) parent).indexOfChild((Node) this.sharedGroup.source);
        ((GroupRetained) parent).checkSetLive(this.sharedGroup, ci, newKeys, true, null, 0, this);
      } catch (SceneGraphCycleException e) {
        throw e;
      } finally {
        visited = false;
      }
    }
  }
  void compile(CompileState compState) {
    super.compile(compState);

    // don't remove this group node
    mergeFlag = SceneGraphObjectRetained.DONT_MERGE;

    // XXXX: complete this
  }
  void compile(CompileState compState) {

    // save and reset the keepTG and needNormalsTransform flags

    boolean saveKeepTG = compState.keepTG;
    compState.keepTG = false;

    boolean saveNeedNormalsTransform = compState.needNormalsTransform;
    compState.needNormalsTransform = false;

    super.compile(compState);

    if (compState.keepTG) {
      // keep this transform group, don't merge it

      mergeFlag = SceneGraphObjectRetained.DONT_MERGE;
    }

    if (J3dDebug.devPhase && J3dDebug.debug) {
      compState.numTransformGroups++;
      if (isStatic()) compState.numStaticTransformGroups++;
      if (mergeFlag == SceneGraphObjectRetained.MERGE) compState.numMergedTransformGroups++;
    }

    if (mergeFlag == SceneGraphObjectRetained.DONT_MERGE) {
      // a non-mergeable TG will trigger a merge of its subtree

      compState.staticTransform = null;
      compState.parentGroup = null;
      super.merge(compState);

    } else {
      // flag this TG as to be merged later on
      mergeFlag = SceneGraphObjectRetained.MERGE;
    }

    // restore compile state
    compState.keepTG = saveKeepTG;
    this.needNormalsTransform = compState.needNormalsTransform;
    compState.needNormalsTransform = saveNeedNormalsTransform;
  }
  void setLive(SetLiveState s) {
    if (inBackgroundGroup) {
      throw new IllegalSceneGraphException(J3dI18N.getString("ViewSpecificGroup3"));
    }

    s.inViewSpecificGroup = true;
    ArrayList savedViewList = s.viewLists;
    if (s.changedViewGroup == null) {
      s.changedViewGroup = new ArrayList();
      s.changedViewList = new ArrayList();
      s.keyList = new int[10];
      s.viewScopedNodeList = new ArrayList();
      s.scopedNodesViewList = new ArrayList();
    }
    super.setLive(s);
    s.viewLists = savedViewList;
  }
  void clearLive(SetLiveState s) {

    Targets[] savedTransformTargets = null;

    savedTransformTargets = s.transformTargets;
    // no need to gather targets from tg in clear live
    s.transformTargets = null;

    super.clearLive(s);

    // restore setLiveState from it's local variables.
    // removeNodeData has altered these variables.
    s.localToVworld = localToVworld;
    s.localToVworldIndex = localToVworldIndex;
    s.transformTargets = savedTransformTargets;

    synchronized (this) { // synchronized with TransformStructure
      if (inSharedGroup) {
        if (transformLevels != null) {
          maxTransformLevel = transformLevels[0];
          for (int i = 1; i < transformLevels.length; i++) {
            if (transformLevels[i] > maxTransformLevel) {
              maxTransformLevel = transformLevels[i];
            }
          }
        } else {
          maxTransformLevel = -1;
        }

        if (s.switchTargets != null) {
          for (int i = 0; i < s.switchTargets.length; i++) {
            if (s.switchTargets[i] != null) {
              s.switchTargets[i].addNode(this, Targets.GRP_TARGETS);
            }
          }
        }

      } else {
        maxTransformLevel = -1;
        if (s.switchTargets != null && s.switchTargets[0] != null) {
          s.switchTargets[0].addNode(this, Targets.GRP_TARGETS);
        }
      }
    }
    // XXXX: recontruct targetThreads
  }
  void traverse(boolean sameLevel, int level) {

    System.err.println();
    for (int i = 0; i < level; i++) {
      System.err.print(".");
    }
    System.err.print(this);

    if (isStatic()) {
      System.err.print(" (s)");
    } else {
      System.err.print(" (w)");
    }
    System.err.println();
    System.err.println(transform.toString());
    super.traverse(true, level);
  }
  void merge(CompileState compState) {

    TransformGroupRetained saveStaticTransform;

    // merge the transforms
    if (compState.staticTransform != null) {
      staticTransform = compState.staticTransform;
      mergeTransform(compState.staticTransform);
    }

    if (mergeFlag == SceneGraphObjectRetained.MERGE) {

      // before we push down the static transform, check
      // to see if the transform will be pushed down to shapes
      // with geometry_with_normals and if so, check if
      // the normal transform has uniform scale or not. If
      // it doesn't, don't push it down.

      if (this.needNormalsTransform) {
        Transform3D normalXform = this.getNormalTransform();
        if (!normalXform.isCongruent()) {
          mergeFlag = SceneGraphObjectRetained.DONT_MERGE;
        }
      }
    }

    if (mergeFlag == SceneGraphObjectRetained.MERGE) {
      saveStaticTransform = compState.staticTransform;
      compState.staticTransform = this;

      // go to the merge method of the group node to start
      // pushing down the static transform until it hits
      // a leaf or a subtree which is already merged.
      super.merge(compState);

      // reset the compile state
      compState.staticTransform = saveStaticTransform;

    } else {
      compState.parentGroup.compiledChildrenList.add(this);
      parent = compState.parentGroup;
    }

    mergeFlag = SceneGraphObjectRetained.MERGE_DONE;
  }
  void setNodeData(SetLiveState s) {
    super.setNodeData(s);
    if (!inSharedGroup) {
      int size = s.changedViewGroup.size();
      if (s.keyList.length < size + 1) {
        int[] newKeyList = new int[s.keyList.length + 20];
        System.arraycopy(s.keyList, 0, newKeyList, 0, s.keyList.length);
        s.keyList = newKeyList;
        //		System.err.println("====> setNodeData: Allocating Non-shared");
      }
      setAuxData(s, 0, 0);
    } else {
      // For inSharedGroup case.
      int j, hkIndex;

      int size = s.changedViewGroup.size();
      if (s.keyList.length < size + 1 + s.keys.length) {
        int[] newKeyList = new int[s.keyList.length + s.keys.length + 20];
        System.arraycopy(s.keyList, 0, newKeyList, 0, s.keyList.length);
        s.keyList = newKeyList;
        //		System.err.println("====> setNodeData: Allocating Shared");
      }

      for (j = 0; j < s.keys.length; j++) {
        hkIndex = s.keys[j].equals(localToVworldKeys, 0, localToVworldKeys.length);

        if (hkIndex >= 0) {
          setAuxData(s, j, hkIndex);

        } else {
          MasterControl.getCoreLogger().severe("Can't Find matching hashKey in setNodeData.");
        }
      }
    }
    // Make the VSG's viewLists as the relavant one for its children
    s.viewLists = viewLists;
  }
 void removeNodeData(SetLiveState s) {
   if ((!inSharedGroup) || (s.keys.length == localToVworld.length)) {
     s.changedViewGroup.add(this);
     // Remove everything ..
     int size = s.changedViewGroup.size();
     if (s.keyList.length < size) {
       int[] newKeyList = new int[s.keyList.length + 20];
       System.arraycopy(s.keyList, 0, newKeyList, 0, s.keyList.length);
       s.keyList = newKeyList;
       //		System.err.println("====> RemovedNodeData: Allocating Non-shared");
     }
     s.keyList[size - 1] = -1;
     parentLists.clear();
   }
   // A path of the shared group is removed
   else {
     int i, index;
     int size = s.changedViewGroup.size();
     if (s.keyList.length < size + 1 + s.keys.length) {
       int[] newKeyList = new int[s.keyList.length + s.keys.length + 20];
       System.arraycopy(s.keyList, 0, newKeyList, 0, s.keyList.length);
       s.keyList = newKeyList;
       //		System.err.println("====> RemovedNodeData: Allocating Shared");
     }
     // Must be in reverse, to preserve right indexing.
     for (i = s.keys.length - 1; i >= 0; i--) {
       index = s.keys[i].equals(localToVworldKeys, 0, localToVworldKeys.length);
       if (index >= 0) {
         s.changedViewGroup.add(this);
         s.keyList[s.changedViewGroup.size() - 1] = index;
         parentLists.remove(index);
       }
     }
   }
   s.viewLists = viewLists;
   super.removeNodeData(s);
 }
  void clearLive(SetLiveState s) {
    ArrayList savedViewList = s.viewLists;
    if (s.changedViewGroup == null) {
      s.changedViewGroup = new ArrayList();
      s.changedViewList = new ArrayList();
      s.keyList = new int[10];
      s.viewScopedNodeList = new ArrayList();
      s.scopedNodesViewList = new ArrayList();
    }
    // XXXX: This is a hack since removeNodeData is called before
    // children are clearLives
    int[] tempIndex = null;
    // Don't keep the indices if everything will be cleared
    if (inSharedGroup && (s.keys.length != localToVworld.length)) {
      tempIndex = new int[s.keys.length];
      for (int i = 0; i < s.keys.length; i++) {
        tempIndex[i] = s.keys[i].equals(localToVworldKeys, 0, localToVworldKeys.length);
      }
    }
    super.clearLive(s);
    // Do this after children clearlive since part of the viewLists may get cleared
    // during removeNodeData

    // If the last SharedGroup is being cleared
    if ((!inSharedGroup) || (localToVworld == null)) {
      viewLists.clear();
    } else {
      // Must be in reverse, to preserve right indexing.
      for (int i = tempIndex.length - 1; i >= 0; i--) {
        if (tempIndex[i] >= 0) {
          viewLists.remove(tempIndex[i]);
        }
      }
    }
    s.viewLists = savedViewList;
  }
  @Override
  void setLive(SetLiveState s) {

    int i, j;
    Targets[] newTargets = null;

    // save setLiveState
    Transform3D savedLocalToVworld[][] = s.localToVworld;
    int savedLocalToVworldIndex[][] = s.localToVworldIndex;
    HashKey savedLocalToVworldKeys[] = s.localToVworldKeys;
    ArrayList<OrderedPath> savedOrderedPaths = s.orderedPaths;
    ArrayList<ArrayList<View>> savedViewList = s.viewLists;
    ArrayList<ArrayList<LightRetained>> savedLights = s.lights;
    ArrayList<ArrayList<FogRetained>> savedFogs = s.fogs;
    ArrayList<ArrayList<ModelClipRetained>> savedMclips = s.modelClips;
    ArrayList<ArrayList<AlternateAppearanceRetained>> savedAltApps = s.altAppearances;

    SharedGroupRetained savedLastSharedGroup = s.lastSharedGroup;
    Targets[] savedSwitchTargets = s.switchTargets;
    ArrayList<SwitchState> savedSwitchStates = s.switchStates;
    ArrayList<NodeRetained> savedChildSwitchLinks = s.childSwitchLinks;
    GroupRetained savedParentSwitchLink = s.parentSwitchLink;
    ArrayList<NodeRetained> savedChildTransformLinks = s.childTransformLinks;
    GroupRetained savedParentTransformLink = s.parentTransformLink;
    int[] savedHashkeyIndex = s.hashkeyIndex;

    // update setLiveState for this node
    // Note that s.containsNodesList is updated in super.setLive
    s.lastSharedGroup = this;

    Targets[] savedTransformTargets = s.transformTargets;

    int numPaths = s.keys.length;
    newTargets = new Targets[numPaths];
    for (i = 0; i < numPaths; i++) {
      if (s.transformLevels[i] >= 0) {
        newTargets[i] = new Targets();
      } else {
        newTargets[i] = null;
      }
    }
    s.transformTargets = newTargets;

    super.setLive(s);

    int hkIndex;
    for (i = 0; i < numPaths; i++) {
      if (s.transformTargets[i] != null) {
        hkIndex = s.hashkeyIndex[i];
        cachedTargets[hkIndex] = s.transformTargets[i].snapShotInit();
      }
    }
    // Assign data in cachedTargets to j3dCTs.
    j3dCTs = new CachedTargets[cachedTargets.length];
    copyCachedTargets(TargetsInterface.TRANSFORM_TARGETS, j3dCTs);

    computeTargetThreads(TargetsInterface.TRANSFORM_TARGETS, cachedTargets);

    // restore setLiveState
    s.localToVworld = savedLocalToVworld;
    s.localToVworldIndex = savedLocalToVworldIndex;
    s.localToVworldKeys = savedLocalToVworldKeys;
    s.orderedPaths = savedOrderedPaths;
    s.viewLists = savedViewList;

    s.lights = savedLights;
    s.fogs = savedFogs;
    s.modelClips = savedMclips;
    s.altAppearances = savedAltApps;

    s.lastSharedGroup = savedLastSharedGroup;
    s.switchTargets = savedSwitchTargets;
    s.switchStates = savedSwitchStates;

    s.childSwitchLinks = savedChildSwitchLinks;
    s.parentSwitchLink = savedParentSwitchLink;
    s.childTransformLinks = savedChildTransformLinks;
    s.parentTransformLink = savedParentTransformLink;

    s.transformTargets = savedTransformTargets;
    s.hashkeyIndex = savedHashkeyIndex;
    /*
    // XXXX : port this
            for (int i=0; i < children.size(); i++) {
                if ((childContains[i][0] & ILLEGAL_LEAF_MASK) != 0) {
                    throw new IllegalSharingException(J3dI18N.getString("SharedGroupRetained0"));            }
            }
    */
  }
 void setAuxData(SetLiveState s, int index, int hkIndex) {
   super.setAuxData(s, index, hkIndex);
   perPathData[hkIndex] = new TransformGroupData();
   perPathData[hkIndex].switchState = (SwitchState) s.switchStates.get(hkIndex);
 }
  /** remove the localToVworld transform for a transformGroup */
  void removeNodeData(SetLiveState s) {

    synchronized (this) { // synchronized with TransformStructure
      if (refCount <= 0) {
        childLocalToVworld = null;
        childLocalToVworldIndex = null;
        transformLevels = null;
        // only use by TransformStruct.
        cachedTargets = null;
        perPathData = null;
        targetThreads = 0;

        if (parentTransformLink != null) {
          ArrayList obj;
          if (parentTransformLink instanceof TransformGroupRetained) {
            obj = ((TransformGroupRetained) parentTransformLink).childTransformLinks;
          } else {
            obj = ((SharedGroupRetained) parentTransformLink).childTransformLinks;
          }
          synchronized (obj) {
            obj.remove(this);
          }
        }
        aboveAViewPlatform = false;
      } else {
        int i, index, len;
        // Remove the localToVworld key
        int newLen = localToVworld.length - s.keys.length;

        Transform3D[][] newChildTList = new Transform3D[newLen][];
        int[][] newChildIndexList = new int[newLen][];
        int[] newTransformLevels = new int[newLen];
        ArrayList[] newChildPTG = new ArrayList[newLen];
        CachedTargets[] newTargets = new CachedTargets[newLen];
        TransformGroupData[] newPerPathData = new TransformGroupData[newLen];

        int[] tempIndex = new int[s.keys.length];
        int curStart = 0, newStart = 0;
        boolean found = false;
        for (i = 0; i < s.keys.length; i++) {
          index = s.keys[i].equals(localToVworldKeys, 0, localToVworldKeys.length);

          tempIndex[i] = index;

          if (index >= 0) {
            found = true;

            if (index == curStart) {
              curStart++;
            } else {
              len = index - curStart;
              System.arraycopy(childLocalToVworld, curStart, newChildTList, newStart, len);
              System.arraycopy(childLocalToVworldIndex, curStart, newChildIndexList, newStart, len);
              System.arraycopy(transformLevels, curStart, newTransformLevels, newStart, len);
              System.arraycopy(cachedTargets, curStart, newTargets, newStart, len);
              System.arraycopy(perPathData, curStart, newPerPathData, newStart, len);

              curStart = index + 1;
              newStart = newStart + len;
            }
          } else {
            found = false;
            MasterControl.getCoreLogger().severe("TG.removeNodeData-Can't find matching hashKey.");
          }
        }

        if ((found == true) && (curStart < localToVworld.length)) {
          len = localToVworld.length - curStart;
          System.arraycopy(childLocalToVworld, curStart, newChildTList, newStart, len);
          System.arraycopy(childLocalToVworldIndex, curStart, newChildIndexList, newStart, len);
          System.arraycopy(transformLevels, curStart, newTransformLevels, newStart, len);
          System.arraycopy(cachedTargets, curStart, newTargets, newStart, len);
          System.arraycopy(perPathData, curStart, newPerPathData, newStart, len);
        }

        childLocalToVworld = newChildTList;
        childLocalToVworldIndex = newChildIndexList;
        transformLevels = newTransformLevels;
        cachedTargets = newTargets;
        perPathData = newPerPathData;
      }
      super.removeNodeData(s);
      // Set it back to its parent localToVworld data.
      // This is b/c the parent has changed it localToVworld data arrays.
      s.localToVworld = childLocalToVworld;
      s.localToVworldIndex = childLocalToVworldIndex;
    }
  }
  /** This setlive simply concatinates it's transform onto all the ones passed in. */
  void setLive(SetLiveState s) {
    int i, j;
    Transform3D trans = null;
    Targets[] newTargets = null;
    Targets[] savedTransformTargets = null;
    int oldTraverseFlags = 0;
    int len;
    Object obj;

    // XXXX - optimization for targetThreads computation, require
    // cleanup in GroupRetained.doSetLive()
    // int savedTargetThreads = 0;
    // savedTargetThreads = s.transformTargetThreads;
    // s.transformTargetThreads = 0;

    oldTraverseFlags = s.traverseFlags;

    savedTransformTargets = s.transformTargets;

    int numPaths = (s.inSharedGroup) ? s.keys.length : 1;
    newTargets = new Targets[numPaths];
    for (i = 0; i < numPaths; i++) {
      newTargets[i] = new Targets();
    }

    s.transformTargets = newTargets;
    s.traverseFlags = 0;

    // This is needed b/c super.setlive is called after inSharedGroup check.
    inSharedGroup = s.inSharedGroup;

    trans = new Transform3D();
    transform.getWithLock(trans);
    currentTransform.set(trans);

    ArrayList savedChildTransformLinks = s.childTransformLinks;
    GroupRetained savedParentTransformLink = s.parentTransformLink;
    Transform3D[][] oldCurrentList = s.currentTransforms;
    int[][] oldCurrentIndexList = s.currentTransformsIndex;

    super.doSetLive(s);

    if (!inSharedGroup) {
      if (s.transformTargets[0] != null) {
        cachedTargets[0] = s.transformTargets[0].snapShotInit();
      }
      if (s.switchTargets != null && s.switchTargets[0] != null) {
        s.switchTargets[0].addNode(this, Targets.GRP_TARGETS);
      }
    } else {
      int hkIndex;
      for (i = 0; i < numPaths; i++) {
        if (s.transformTargets[i] != null) {
          hkIndex = s.keys[i].equals(localToVworldKeys, 0, localToVworldKeys.length);
          cachedTargets[hkIndex] = s.transformTargets[i].snapShotInit();
        }
        if (s.switchTargets != null && s.switchTargets[i] != null) {
          s.switchTargets[i].addNode(this, Targets.GRP_TARGETS);
        }
      }
    }

    // Assign data in cachedTargets to j3dCTs.
    j3dCTs = new CachedTargets[cachedTargets.length];
    copyCachedTargets(TargetsInterface.TRANSFORM_TARGETS, j3dCTs);

    computeTargetThreads(TargetsInterface.TRANSFORM_TARGETS, cachedTargets);

    // restore setLiveState from it's local variables.
    // setNodeData did keep a reference to these variables.
    s.localToVworld = localToVworld;
    s.localToVworldIndex = localToVworldIndex;
    s.currentTransforms = oldCurrentList;
    s.currentTransformsIndex = oldCurrentIndexList;

    s.childTransformLinks = savedChildTransformLinks;
    s.parentTransformLink = savedParentTransformLink;

    s.transformTargets = savedTransformTargets;

    if (!s.inSharedGroup) {
      s.transformLevels[0] -= 1;
    } else {
      for (i = 0; i < s.keys.length; i++) {
        s.transformLevels[i] -= 1;
      }
    }

    if ((s.traverseFlags & NodeRetained.CONTAINS_VIEWPLATFORM) != 0) {
      aboveAViewPlatform = true;
    }
    s.traverseFlags |= oldTraverseFlags;

    if (aboveAViewPlatform && !trans.isCongruent()) {
      throw new BadTransformException(J3dI18N.getString("ViewPlatformRetained0"));
    }

    super.markAsLive();
  }
 void mergeTransform(TransformGroupRetained xform) {
   super.mergeTransform(xform);
   transform.mul(xform.transform, transform);
 }
  @Override
  void clearLive(SetLiveState s) {

    int i, j, k, index;

    Transform3D savedLocalToVworld[][] = s.localToVworld;
    int savedLocalToVworldIndex[][] = s.localToVworldIndex;
    HashKey savedLocalToVworldKeys[] = s.localToVworldKeys;
    ArrayList<OrderedPath> savedOrderedPaths = s.orderedPaths;
    ArrayList<ArrayList<View>> savedViewLists = s.viewLists;

    ArrayList<ArrayList<LightRetained>> savedLights = s.lights;
    ArrayList<ArrayList<FogRetained>> savedFogs = s.fogs;
    ArrayList<ArrayList<ModelClipRetained>> savedMclips = s.modelClips;
    ArrayList<ArrayList<AlternateAppearanceRetained>> savedAltApps = s.altAppearances;

    Targets[] savedSwitchTargets = s.switchTargets;
    Targets[] savedTransformTargets = s.transformTargets;
    // no need to gather targets from sg in clear live
    s.transformTargets = null;
    s.switchTargets = null;

    // XXXX: This is a hack since removeNodeData is called before
    // children are clearLives
    int[] tempIndex = null;
    // Don't keep the indices if everything will be cleared
    if (s.keys.length != localToVworld.length) {
      tempIndex = new int[s.keys.length];
      for (i = s.keys.length - 1; i >= 0; i--) {
        tempIndex[i] = s.keys[i].equals(localToVworldKeys, 0, localToVworldKeys.length);
      }
    }

    super.clearLive(s);
    // Do this after children clearlive since part of the viewLists may get cleared
    // during removeNodeData
    if (refCount <= 0) {
      viewLists.clear();
    } else {
      // Must be in reverse, to preserve right indexing.
      for (i = tempIndex.length - 1; i >= 0; i--) {
        if (tempIndex[i] >= 0) {
          viewLists.remove(tempIndex[i]);
        }
      }
    }

    // restore setLiveState from it's local variables.
    // removeNodeData has altered these variables.
    s.localToVworld = savedLocalToVworld;
    s.localToVworldIndex = savedLocalToVworldIndex;
    s.localToVworldKeys = savedLocalToVworldKeys;
    s.orderedPaths = savedOrderedPaths;
    s.viewLists = savedViewLists;
    s.lights = savedLights;
    s.fogs = savedFogs;
    s.modelClips = savedMclips;
    s.altAppearances = savedAltApps;
    s.transformTargets = savedTransformTargets;
    s.switchTargets = savedSwitchTargets;
  }
  // SharedGroup specific data at SetLive.
  @Override
  void setAuxData(SetLiveState s, int index, int hkIndex) {
    int i, size;

    // Group's setAuxData()
    super.setAuxData(s, index, hkIndex);

    branchGroupPaths.add(hkIndex, s.branchGroupPaths.get(index));

    if (orderedPaths == null) {
      orderedPaths = new ArrayList<OrderedPath>(1);
    }
    orderedPaths.add(hkIndex, s.orderedPaths.get(index));

    if (switchStates == null) {
      switchStates = new ArrayList<SwitchState>(1);
    }
    switchStates.add(hkIndex, s.switchStates.get(index));

    if (viewLists == null) {
      viewLists = new ArrayList<ArrayList<View>>(1);
    }
    // If there are some ViewSpecificGroups in the path above this SharedGroup
    //	System.err.println("====> hkIndex = "+hkIndex+" s.viewLists = "+s.viewLists);
    if (s.viewLists != null) {
      viewLists.add(hkIndex, s.viewLists.get(index));
    } else {
      viewLists.add(hkIndex, null);
    }

    if (lights == null) {
      lights = new ArrayList<ArrayList<LightRetained>>(1);
    }
    if (s.lights != null) {
      lights.add(hkIndex, s.lights.get(index));
    } else {
      lights.add(hkIndex, null);
    }

    if (fogs == null) {
      fogs = new ArrayList<ArrayList<FogRetained>>(1);
    }
    if (s.fogs != null) {
      fogs.add(hkIndex, s.fogs.get(index));
    } else {
      fogs.add(hkIndex, null);
    }

    if (modelClips == null) {
      modelClips = new ArrayList<ArrayList<ModelClipRetained>>(1);
    }
    if (s.modelClips != null) {
      modelClips.add(hkIndex, s.modelClips.get(index));
    } else {
      modelClips.add(hkIndex, null);
    }

    if (altAppearances == null) {
      altAppearances = new ArrayList<ArrayList<AlternateAppearanceRetained>>(1);
    }
    if (s.altAppearances != null) {
      altAppearances.add(hkIndex, s.altAppearances.get(index));
    } else {
      altAppearances.add(hkIndex, null);
    }
  }
  // synchronized with TransformStructure
  synchronized void setNodeData(SetLiveState s) {
    int i;

    super.setNodeData(s);

    childTrans = new Transform3D[s.currentTransforms.length][2];
    childTransIndex = new int[s.currentTransforms.length][2];

    for (i = 0; i < s.currentTransforms.length; i++) {
      childTrans[i][0] = new Transform3D();

      childTrans[i][0].mul(
          s.currentTransforms[i][s.currentTransformsIndex[i][CURRENT_LOCAL_TO_VWORLD]],
          currentTransform);
      childTrans[i][1] = new Transform3D(childTrans[i][0]);
      childTransIndex[i][0] = 0;
      childTransIndex[i][1] = 0;
    }

    if (!s.inSharedGroup) {
      s.transformLevels[0] += 1;
      maxTransformLevel = s.transformLevels[0];
    } else {
      for (i = 0; i < s.keys.length; i++) {
        s.transformLevels[i] += 1;
        if (s.transformLevels[i] > maxTransformLevel) {
          maxTransformLevel = s.transformLevels[i];
        }
      }
    }

    if (!inSharedGroup) {
      if (childLocalToVworld == null) {
        // If the node is a transformGroup then need to keep
        // the child transforms as well
        childLocalToVworld = new Transform3D[1][];
        childLocalToVworldIndex = new int[1][];
        transformLevels = new int[1];
        // Use by TransformStructure
        cachedTargets = new CachedTargets[1];
        perPathData = new TransformGroupData[1];
      }
      childLocalToVworld[0] = childTrans[0];
      childLocalToVworldIndex[0] = childTransIndex[0];
      transformLevels[0] = s.transformLevels[0];

      setAuxData(s, 0, 0);
    } else {

      // For inSharedGroup case.
      int j, len;

      if (childLocalToVworld == null) {
        childLocalToVworld = new Transform3D[s.keys.length][];
        childLocalToVworldIndex = new int[s.keys.length][];
        transformLevels = new int[s.keys.length];
        cachedTargets = new CachedTargets[s.keys.length];
        perPathData = new TransformGroupData[s.keys.length];
        len = 0;
      } else {

        len = localToVworld.length - s.keys.length;

        int newLen = localToVworld.length;

        Transform3D newChildTList[][] = new Transform3D[newLen][];
        int newChildIndexList[][] = new int[newLen][];
        int newTransformLevels[] = new int[newLen];
        CachedTargets newTargets[] = new CachedTargets[newLen];
        TransformGroupData newPerPathData[] = new TransformGroupData[newLen];

        System.arraycopy(childLocalToVworld, 0, newChildTList, 0, childLocalToVworld.length);
        System.arraycopy(
            childLocalToVworldIndex, 0, newChildIndexList, 0, childLocalToVworldIndex.length);
        System.arraycopy(transformLevels, 0, newTransformLevels, 0, transformLevels.length);

        System.arraycopy(cachedTargets, 0, newTargets, 0, cachedTargets.length);

        System.arraycopy(perPathData, 0, newPerPathData, 0, perPathData.length);

        childLocalToVworld = newChildTList;
        childLocalToVworldIndex = newChildIndexList;
        transformLevels = newTransformLevels;
        cachedTargets = newTargets;
        perPathData = newPerPathData;
      }

      int hkIndex;
      int hkIndexPlus1, blkSize;

      for (i = len, j = 0; i < localToVworld.length; i++, j++) {
        hkIndex = s.keys[j].equals(localToVworldKeys, 0, localToVworldKeys.length);

        if (hkIndex < 0) {
          MasterControl.getCoreLogger().severe("Can't Find matching hashKey in setNodeData.");
          break;
        } else if (hkIndex >= i) { // Append to last.
          childLocalToVworld[i] = childTrans[j];
          childLocalToVworldIndex[i] = childTransIndex[j];
          transformLevels[i] = s.transformLevels[j];
        } else {
          hkIndexPlus1 = hkIndex + 1;
          blkSize = i - hkIndex;

          System.arraycopy(childLocalToVworld, hkIndex, childLocalToVworld, hkIndexPlus1, blkSize);

          System.arraycopy(
              childLocalToVworldIndex, hkIndex, childLocalToVworldIndex, hkIndexPlus1, blkSize);

          System.arraycopy(transformLevels, hkIndex, transformLevels, hkIndexPlus1, blkSize);

          System.arraycopy(cachedTargets, hkIndex, cachedTargets, hkIndexPlus1, blkSize);

          System.arraycopy(perPathData, hkIndex, perPathData, hkIndexPlus1, blkSize);

          childLocalToVworld[hkIndex] = childTrans[j];
          childLocalToVworldIndex[hkIndex] = childTransIndex[j];
          transformLevels[hkIndex] = s.transformLevels[j];
        }

        setAuxData(s, j, hkIndex);
      }
    }
    if (s.childTransformLinks != null) {
      // do not duplicate shared nodes
      synchronized (s.childTransformLinks) {
        if (!inSharedGroup || !s.childTransformLinks.contains(this)) {
          s.childTransformLinks.add(this);
        }
      }
    }

    s.localToVworld = childLocalToVworld;
    s.localToVworldIndex = childLocalToVworldIndex;
    s.currentTransforms = childTrans;
    s.currentTransformsIndex = childTransIndex;

    s.childTransformLinks = childTransformLinks;
    s.parentTransformLink = this;
  }