aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/RenderBin.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/javax/media/j3d/RenderBin.java')
-rw-r--r--src/javax/media/j3d/RenderBin.java7066
1 files changed, 7066 insertions, 0 deletions
diff --git a/src/javax/media/j3d/RenderBin.java b/src/javax/media/j3d/RenderBin.java
new file mode 100644
index 0000000..aacef06
--- /dev/null
+++ b/src/javax/media/j3d/RenderBin.java
@@ -0,0 +1,7066 @@
+/*
+ * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package javax.media.j3d;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+
+import javax.vecmath.Color3f;
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector3d;
+
+/**
+ * The RenderBin is a structure that optimizes rendering by doing efficient
+ * state sorting of objects to be rendered.
+ */
+
+class RenderBin extends J3dStructure implements ObjectUpdate {
+
+/**
+ * The list of RenderAtoms
+ */
+ArrayList<RenderAtom> renderAtoms = new ArrayList<RenderAtom>(5);
+
+/**
+ * A couple ArrayLists used during light Processing
+ */
+ArrayList<J3dMessage> lightMessageList = new ArrayList<J3dMessage>(5);
+
+ // Messges retrieved when a message is sent to RenderingEnv Structure
+ J3dMessage[] m;
+
+/**
+ * List of renderMolecules that are soleUser have to do a 2 pass, first update
+ * values then sort based on equivalent material
+ */
+ArrayList<RenderMolecule> rmUpdateList = new ArrayList<RenderMolecule>();
+ArrayList<AttributeBin> aBinUpdateList = new ArrayList<AttributeBin>();
+
+/**
+ * List of ShaderBin that are soleUser that needs to have its components updated @updateObject
+ * time
+ */
+ArrayList<ShaderBin> sBinUpdateList = new ArrayList<ShaderBin>();
+
+/**
+ * List of TextureBin that are soleUser that needs to have its components
+ * updated @updateObject time
+ */
+ArrayList<TextureBin> tbUpdateList = new ArrayList<TextureBin>();
+
+/**
+ * List of Bins that are soleUser that have new renderAtom added into, which
+ * requires a pre-update screening to check if any of its node component changes
+ * could have been missed because the changes happen when all the render atoms
+ * are temporarily removed from the bin.
+ */
+ArrayList<NodeComponentUpdate> updateCheckList = new ArrayList<NodeComponentUpdate>();
+
+ /**
+ * The number of lights supported by the underlying context.
+ */
+ int maxLights;
+
+ /**
+ * The opaque objects
+ */
+ LightBin opaqueBin = null;
+
+ /**
+ * OpaqueBins to be added for the next frame
+ */
+ LightBin addOpaqueBin = null;
+
+ // This is a list of textureBins to be rendered, if the transpSortPolicy
+ // is NONE, otherwise, if the transpSortPolicy is geometry, then
+ // this is the list of renderAtoms to be rendered
+ ArrayList allTransparentObjects = new ArrayList(5);
+
+ TransparentRenderingInfo transparentInfo;
+
+/**
+ * List of RenderAtoms whose postion have changed - only used for depth sorted
+ * transparency
+ */
+ArrayList<RenderAtom> positionDirtyList = new ArrayList<RenderAtom>(5);
+
+ /**
+ * Used when ColoringAttributes is null
+ */
+ Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
+
+ /**
+ * Used when Background is null
+ */
+ Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
+
+ /**
+ * The backgound color data.
+ */
+ BackgroundRetained background = new BackgroundRetained();
+
+ /**
+ * The view platform transforms.
+ */
+ // used for rendering - lights and fog modelling
+ Transform3D vworldToVpc = new Transform3D();
+
+ // used for updating vpSchedSphere
+ Transform3D vpcToVworld = new Transform3D();
+
+ /**
+ * Two bounding spheres to track the scheduling region of
+ * the view platform.
+ */
+ BoundingSphere vpSchedSphereInVworld = new BoundingSphere();
+
+ /**
+ * To cache the view frustum bounding box.
+ */
+ BoundingBox viewFrustumBBox = new BoundingBox();
+ BoundingBox canvasFrustumBBox = new BoundingBox();
+
+ /**
+ * To ensure that vpcToVworld is valid (not null) for the first pass
+ */
+ boolean afterFirst = false;
+
+ /**
+ * back clip distance in vworld
+ */
+ double backClipDistanceInVworld;
+
+ boolean backClipActive = false;
+
+ /**
+ * These variables control when compaction occurs
+ */
+ int frameCount = 0;
+ int frameCountCutoff = 150;
+ int notVisibleCount = 75;
+ long removeCutoffTime = -1;
+
+ /**
+ * variables to process transform messages
+ */
+ boolean transformMsg = false;
+ UpdateTargets targets = null;
+ ArrayList blUsers = null;
+
+ /**
+ * The View for this render bin
+ */
+ View view = null;
+
+ private Comparator<TransparencySortGeom> transparencySortComparator = null;
+
+private ArrayList<TextureRetained> toBeAddedTextureResourceFreeList = new ArrayList<TextureRetained>(5);
+private ArrayList<Integer> displayListResourceFreeList = new ArrayList<Integer>(5);
+
+// a list of top level OrderedGroups
+ArrayList<OrderedBin> orderedBins = new ArrayList<OrderedBin>(5);
+
+// List of changed elements in the environment that needs to
+// be reloaded
+ArrayList<LightRetained> changedLts = new ArrayList<LightRetained>(5);
+ArrayList<FogRetained> changedFogs = new ArrayList<FogRetained>(5);
+ArrayList<ModelClipRetained> changedModelClips = new ArrayList<ModelClipRetained>(5);
+
+ // Flag to indicate whether the canvas should be marked
+ static int REEVALUATE_LIGHTS = 0x1;
+ static int REEVALUATE_FOG = 0x2;
+ static int REEVALUATE_MCLIP = 0x4;
+ static int REEVALUATE_ALL_ENV = REEVALUATE_LIGHTS | REEVALUATE_FOG | REEVALUATE_MCLIP;
+ int envDirty = 0;
+
+
+ private boolean reEvaluateBg = true;
+ private boolean reloadBgTexture = true;
+
+ boolean reEvaluateClip = true;
+
+ boolean reEvaluateSortMode = false;
+
+
+ // list of renderMolecule
+ // RenderBin will not reused in two different universe, so it is
+ // safe to pass null in last parameters in new IndexedUnorderSet()
+ IndexedUnorderSet renderMoleculeList =
+ new IndexedUnorderSet(RenderMolecule.class,
+ RenderMolecule.RENDER_MOLECULE_LIST, null);
+
+// List of renderAtoms that have a shared dlist (due to geo.refCount > 1)
+// Fix for Issue 5: change this to a Set rather than a list to
+// avoid duplicates entried
+Collection<RenderAtomListInfo> sharedDList = new HashSet<RenderAtomListInfo>();
+
+ArrayList<RenderMolecule> dirtyRenderMoleculeList = new ArrayList<RenderMolecule>(5);
+
+
+/**
+ * ArrayList of objects to be updated
+ */
+ArrayList<ObjectUpdate> objUpdateList = new ArrayList<ObjectUpdate>(5);
+
+ArrayList<RenderAtom> raLocaleVwcBoundsUpdateList = new ArrayList<RenderAtom>(5);
+
+ /**
+ * remove the bins first before adding them to new ones
+ */
+ IndexedUnorderSet removeRenderAtomInRMList =
+ new IndexedUnorderSet(RenderMolecule.class,
+ RenderMolecule.REMOVE_RENDER_ATOM_IN_RM_LIST, null);
+
+
+/**
+ * list of affect OrderedGroups with childIndexOrder changed.
+ */
+ArrayList<J3dMessage> ogCIOList = new ArrayList<J3dMessage>(5);
+
+/**
+ * list of ordered bins from which orderedCollection are added/removed
+ */
+ArrayList<OrderedBin> obList = new ArrayList<OrderedBin>(5);
+
+/**
+ * Ordered Bin processing
+ */
+ArrayList<ArrayList<OrderedBin>> orderedBinsList = new ArrayList<ArrayList<OrderedBin>>(5);
+ArrayList<ArrayList<OrderedBin>> toBeAddedBinList = new ArrayList<ArrayList<OrderedBin>>(5);
+
+/**
+ * arraylist of geometry that should be locked to ensure
+ * that the same snapshot of the geometry is rendered
+ * across all canvases
+ */
+ArrayList<GeometryRetained> lockGeometryList = new ArrayList<GeometryRetained>(5);
+
+
+ /**
+ * arraylist of dlist that will be rebuilt
+ */
+ ArrayList dlistLockList = new ArrayList(5);
+
+ // Background node that contains geometry
+ BackgroundRetained geometryBackground = null;
+
+ // background geometry processing
+ LightBin bgOpaqueBin = null;
+ LightBin bgAddOpaqueBin = null;
+ArrayList<OrderedBin> bgOrderedBins = new ArrayList<OrderedBin>(5);
+ TransparentRenderingInfo bgTransparentInfo;
+
+
+ // vworldToVpc for background geometry
+ Transform3D infVworldToVpc = new Transform3D();
+
+ // true if vpcToVworld has been modified
+ boolean vpcToVworldDirty = true;
+
+ // current active background
+ BackgroundRetained currentActiveBackground = new BackgroundRetained();
+
+ // Flag to indicate that alternate app is dirty
+ boolean altAppearanceDirty = true;
+
+
+ // List of node components that need special processing, due to
+ // extensions
+ ArrayList nodeComponentList = new ArrayList(5);
+
+
+ // List of node components ***for this frame*** that need special
+ // processing due to extension
+ ArrayList newNodeComponentList = new ArrayList(5);
+ ArrayList removeNodeComponentList = new ArrayList(5);
+ ArrayList dirtyNodeComponentList = new ArrayList(5);
+
+ArrayList<TextureBin> textureBinList = new ArrayList<TextureBin>(5);
+
+/**
+ * arraylist of refernce geometry that should be locked when transparency
+ * is on, so that we can make a mirror copy of the colors safely
+ */
+ArrayList<GeometryArrayRetained> dirtyReferenceGeomList = new ArrayList(5);
+
+// list of all Oriented RenderAtoms
+ArrayList<RenderAtom> orientedRAs = new ArrayList<RenderAtom>(5);
+
+// list of Oriented RenderAtoms whose orientedTransforms require update
+ArrayList<RenderAtom> dirtyOrientedRAs = new ArrayList<RenderAtom>(5);
+
+// Cached copy of dirty oriented RAs to be updated in MasterControl
+ArrayList<RenderAtom> cachedDirtyOrientedRAs = null;
+
+// list of offScreen message that
+ArrayList<J3dMessage> offScreenMessage = new ArrayList<J3dMessage>(5);
+
+ // Vector used for locale translation
+ Vector3d localeTranslation = new Vector3d();
+
+// Separate dlists that were added/removed in this snapshot
+private HashSet<RenderAtomListInfo> addDlist = new HashSet<RenderAtomListInfo>();
+private HashSet<RenderAtomListInfo> removeDlist = new HashSet<RenderAtomListInfo>();
+
+// Separate dlists per rinfo that were added/removed in this snapshot
+ArrayList<RenderAtomListInfo> addDlistPerRinfo = new ArrayList<RenderAtomListInfo>(5);
+ArrayList<RenderAtomListInfo> removeDlistPerRinfo = new ArrayList<RenderAtomListInfo>(5);
+
+ Locale locale = null;
+
+ // Set to true if locale changes as part of UPDATE_VIEW message
+ boolean localeChanged = false;
+
+
+ // Cached copy to be used by all RenderMolecules
+ DisplayListRenderMethod dlistRenderMethod = null;
+
+ // Need to query BHTree again with visibility policy change
+ boolean reactivateView = false;
+
+ /**
+ * A flag indicates that the cached visible GeometryAtoms for this RenderBin might
+ * be invalid.
+ */
+ private boolean visGAIsDirty = false;
+
+ /**
+ * A flag indicates that a visibility query to the GeometryStructure is needed.
+ */
+ private boolean visQuery = false;
+
+// Temporary dirtylist
+ArrayList<RenderAtomListInfo> dirtyList = new ArrayList<RenderAtomListInfo>(5);
+
+ // Transaprency sort mode
+ int transpSortMode = View.TRANSPARENCY_SORT_NONE;
+ int cachedTranspSortMode = View.TRANSPARENCY_SORT_NONE;
+
+
+// Temporary dirtylist
+private LinkedHashSet<RenderAtom> dirtyDepthSortRenderAtom = new LinkedHashSet<RenderAtom>();
+ private int numDirtyTinfo = 0;
+
+ // Eye position in vworld
+ Point3d eyeInVworld = new Point3d();
+ // Number of RenderAtomListInfo in the depthSortedList
+ int nElements = 0;
+
+
+
+ /**
+ * Constructs a new RenderBin
+ */
+ RenderBin(VirtualUniverse u, View v) {
+ super(u, J3dThread.UPDATE_RENDER);
+ vworldToVpc.setIdentity();
+ universe = u;
+ view = v;
+ transpSortMode = v.transparencySortingPolicy;
+ cachedTranspSortMode = v.transparencySortingPolicy;
+ maxLights = VirtualUniverse.mc.maxLights;
+ ViewPlatform vp = view.getViewPlatform();
+ if (vp != null) {
+ locale = ((ViewPlatformRetained) (vp.retained)).locale;
+ }
+ dlistRenderMethod = (DisplayListRenderMethod)
+ VirtualUniverse.mc.getDisplayListRenderMethod();
+ }
+
+ /**
+ * updateObject
+ */
+ @Override
+ public void updateObject() {
+ int i, j, k;
+ RenderAtomListInfo ra;
+ LightBin tmp;
+ ObjectUpdate ob;
+ OrderedBin orderBin;
+ int size;
+
+ // System.err.println("dirtyRenderMoleculeList.size = "+dirtyRenderMoleculeList.size());
+ // System.err.println("reEvaluateBg = "+reEvaluateBg);
+ // System.err.println("reEvaluateClip = "+reEvaluateClip);
+ // System.err.println("<========+End All Cached Values===========>");
+ // Add the new lightBins that have been created
+ // System.err.println("objUpdateList.size = "+objUpdateList.size());
+ // System.err.println("addOpaqueBin = "+addOpaqueBin);
+ // System.err.println("opaqueBin = "+opaqueBin);
+
+ // List of renderMolecule from which renderAtoms have been removed
+ size = removeRenderAtomInRMList.size();
+ if (size > 0) {
+ RenderMolecule[] rmArr = (RenderMolecule[])
+ removeRenderAtomInRMList.toArray(false);
+ for (i=0 ; i<size; i++) {
+ rmArr[i].updateRemoveRenderAtoms();
+ }
+ }
+
+ // Add any OGs that need to be added to this frame
+ // List of Ordered Groups that have been removed
+
+ size = obList.size();
+ if ( size > 0) {
+ for (i = 0 ; i < size; i++) {
+ orderBin = obList.get(i);
+ orderBin.addRemoveOrderedCollection();
+ }
+ }
+
+ size = ogCIOList.size();
+ if(size > 0) {
+ for(i=0; i<size; i++) {
+ J3dMessage m = ogCIOList.get(i);
+
+ switch(m.type) {
+ case J3dMessage.ORDERED_GROUP_TABLE_CHANGED:
+ OrderedGroupRetained og = (OrderedGroupRetained)m.args[3];
+ if(og != null) {
+ og.childIndexOrder = ((int[])m.args[4]);
+ }
+ break;
+
+
+ case J3dMessage.ORDERED_GROUP_INSERTED:
+ case J3dMessage.ORDERED_GROUP_REMOVED:
+ if(m.args[3] != null) {
+ Object[] ogArr = (Object[]) m.args[3];
+ Object[] ogTableArr = (Object[]) m.args[4];
+ for(j=0; j<ogArr.length; j++) {
+ if(ogArr[j] != null) {
+ ((OrderedGroupRetained)ogArr[j]).childIndexOrder =
+ ((int[])ogTableArr[j]);
+ }
+ }
+ }
+
+ break;
+ }
+ m.decRefcount();
+ }
+ }
+
+
+ if (addOpaqueBin != null) {
+
+ if (opaqueBin != null) {
+ tmp = opaqueBin;
+ while (tmp.next != null) {
+ tmp = tmp.next;
+ }
+ addOpaqueBin.prev = tmp;
+ tmp.next = addOpaqueBin;
+ }
+ else {
+ opaqueBin = addOpaqueBin;
+ }
+ }
+
+ if (bgAddOpaqueBin != null) {
+ if (bgOpaqueBin != null) {
+ tmp = bgOpaqueBin;
+ while (tmp.next != null) {
+ tmp = tmp.next;
+ }
+ bgAddOpaqueBin.prev = tmp;
+ tmp.next = bgAddOpaqueBin;
+ }
+ else {
+ bgOpaqueBin = bgAddOpaqueBin;
+ }
+ }
+
+ size = orderedBinsList.size();
+ if (size > 0 ) {
+
+ for (i = 0; i < size; i++) {
+ ArrayList<OrderedBin> obs = orderedBinsList.get(i);
+ ArrayList<OrderedBin> list = toBeAddedBinList.get(i);
+
+ int lSize = list.size();
+ for (j = 0; j < lSize; j++) {
+ obs.add(list.get(j));
+ }
+ }
+ }
+
+
+ size = raLocaleVwcBoundsUpdateList.size();
+ if ( size > 0) {
+ RenderAtom renderAtom;
+ for (i = 0; i < size; i++) {
+ renderAtom = raLocaleVwcBoundsUpdateList.get(i);
+ renderAtom.updateLocaleVwcBounds();
+ }
+ }
+
+ if ((size = aBinUpdateList.size()) > 0) {
+ for (i = 0; i < size; i++) {
+ AttributeBin abin = aBinUpdateList.get(i);
+ abin.updateNodeComponent();
+ }
+ }
+
+ if ((size = sBinUpdateList.size()) > 0) {
+ for (i = 0; i < size; i++) {
+ ShaderBin sbin = sBinUpdateList.get(i);
+ sbin.updateNodeComponent();
+ }
+ }
+
+ // Update the sole user TextureBins.
+ if (tbUpdateList.size() > 0) {
+ TextureBin tb;
+ size = tbUpdateList.size();
+ for (i = 0; i < size; i++) {
+ tb = tbUpdateList.get(i);
+ tb.updateNodeComponent();
+ }
+
+ // do another pass to re-sort TextureBin based on the
+ // texture in the first texture unit state
+ for (i = 0; i < size; i++) {
+ tb = tbUpdateList.get(i);
+ // Bug Id : 4701430 - Have to be sure tb.shaderBin is
+ // not equal to null. This is a temporary fix for j3d1.3.
+ if (((tb.tbFlag & TextureBin.RESORT) != 0) &&
+ (tb.shaderBin != null)) {
+
+ tb.shaderBin.reInsertTextureBin(tb);
+ tb.tbFlag &= ~TextureBin.RESORT;
+ }
+ }
+ }
+
+
+ // Update the soleUser node components first
+ // This way material equivalence during insertion
+ // of new RMs is based on the updated ones
+ if ((size = rmUpdateList.size()) > 0) {
+ for (i = 0; i < size; i++) {
+ RenderMolecule rm = rmUpdateList.get(i);
+
+ boolean changeLists = rm.updateNodeComponent();
+ // If an existing rm went from opaque to transparent or vice-versa
+ // and has not been removed, then switch the RM
+ if (changeLists && rm.textureBin != null) {
+ rm.textureBin.changeLists(rm);
+ }
+ }
+ for (i = 0; i < size; i++) {
+ rmUpdateList.get(i).reEvaluateEquivalence();
+ }
+ }
+
+
+
+ size = objUpdateList.size();
+ if ( size > 0) {
+ for (i = 0; i < size; i++) {
+ ob = objUpdateList.get(i);
+ ob.updateObject();
+ }
+ }
+
+ size = dirtyReferenceGeomList.size();
+ if ( size > 0) {
+ GeometryArrayRetained geo;
+ Canvas3D canvases[] = view.getCanvases();
+
+ for (i = 0; i < size; i++) {
+ geo = dirtyReferenceGeomList.get(i);
+ // Evaluate the nodeComponentList for all the canvases
+ geo.geomLock.getLock();
+ j = 0;
+ // Do the setup only once{if necessary} for each geometry
+ boolean found = false;
+ while(j < canvases.length && !found) {
+ if ((geo.vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+ geo.setupMirrorInterleavedColorPointer(true);
+ found = true;
+ }
+ else {
+ geo.setupMirrorColorPointer((geo.vertexType & GeometryArrayRetained.COLOR_DEFINED),true);
+ found = true;
+ }
+ j++;
+ }
+ geo.geomLock.unLock();
+
+ }
+
+ }
+
+ if (reEvaluateBg) {
+ setBackground(currentActiveBackground);
+ }
+
+ size = textureBinList.size();
+//System.err.println("textureBinList.size= " + size);
+ if (size > 0) {
+ Canvas3D canvasList[][] = view.getCanvasList(false);
+ Canvas3D cv;
+ boolean useSharedCtx = false;
+ TextureRetained texture;
+
+ // do a quick check to see if there is any canvas using
+ // shared context
+ for (j = 0; j < canvasList.length && !useSharedCtx; j++) {
+ cv = canvasList[j][0];
+ if (cv.useSharedCtx) {
+ useSharedCtx = true;
+ }
+ }
+
+ for (int m = 0; m <size; m++) {
+ k = 0;
+ TextureBin tb = textureBinList.get(m);
+ tb.tbFlag |= TextureBin.ON_RENDER_BIN_LIST;
+
+ if (tb.texUnitState == null)
+ continue;
+
+ for (i = 0; i < tb.texUnitState.length; i++) {
+ if (tb.texUnitState[i] != null &&
+ tb.texUnitState[i].texture != null) {
+
+ texture = tb.texUnitState[i].texture;
+
+ // for all the textures in this texture bin list that
+ // need to be reloaded, add the textures to the
+ // corresponding resource reload list if the
+ // resource uses shared context,
+ // so that the texture can be reloaded up front, and
+ // we don't need to do make context current for
+ // each texture reload. Make Context current isn't
+ // cheap.
+
+ if (useSharedCtx) {
+ synchronized (texture.resourceLock) {
+ for (j = 0; j < canvasList.length; j++) {
+ cv = canvasList[j][0];
+ if (cv.useSharedCtx &&
+ cv.screen.renderer != null &&
+ ((cv.screen.renderer.rendererBit &
+ (texture.resourceCreationMask |
+ texture.resourceInReloadList)) == 0)) {
+
+ cv.screen.renderer.textureReloadList.add(texture);
+
+ texture.resourceInReloadList |=
+ cv.screen.renderer.rendererBit;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ size = newNodeComponentList.size();
+ if ( size > 0) {
+//System.err.println("newNodeComponentlist.size= " + size);
+ Canvas3D canvases[] = view.getCanvases();
+ for (i = 0; i < size; i++) {
+ // Evaluate the nodeComponentList for all the canvases
+ ImageComponentRetained nc = (ImageComponentRetained)newNodeComponentList.get(i);
+ if (nc.isByReference()) {
+ nc.geomLock.getLock();
+ for (j = 0; j <canvases.length; j++) {
+ // If the context is null, then the extension
+ // will be evaluated during context creation in
+ // the renderer
+ if (canvases[j].ctx != null) {
+ nc.evaluateExtensions(canvases[j]);
+ }
+ }
+ nc.geomLock.unLock();
+ } else {
+ for (j = 0; j <canvases.length; j++) {
+ // If the context is null, then the extension
+ // will be evaluated during context creation in
+ // the renderer
+ if (canvases[j].ctx != null) {
+ nc.evaluateExtensions(canvases[j]);
+ }
+ }
+ }
+ nodeComponentList.add(nc);
+ }
+ }
+
+ size = removeNodeComponentList.size();
+ if ( size > 0) {
+ for (i = 0; i < size; i++) {
+ nodeComponentList.remove(removeNodeComponentList.get(i));
+ }
+ }
+
+
+ // reevaluate dirty node component
+ size = dirtyNodeComponentList.size();
+ if (size > 0) {
+ Canvas3D canvases[] = view.getCanvases();
+ for (i = 0; i < size; i++) {
+ // Evaluate the nodeComponentList for all the canvases
+ ImageComponentRetained nc =
+ (ImageComponentRetained)dirtyNodeComponentList.get(i);
+ if (nc.isByReference()) {
+ nc.geomLock.getLock();
+ for (j = 0; j <canvases.length; j++) {
+ // If the context is null, then the extension
+ // will be evaluated during context creation in
+ // the renderer
+ if (canvases[j].ctx != null) {
+ nc.evaluateExtensions( canvases[j]);
+ }
+ }
+ nc.geomLock.unLock();
+ }
+ else {
+ for (j = 0; j <canvases.length; j++) {
+ // If the context is null, then the extension
+ // will be evaluated during context creation in
+ // the renderer
+ if (canvases[j].ctx != null) {
+ nc.evaluateExtensions(canvases[j]);
+ }
+ }
+ }
+ }
+ }
+
+
+ if (reEvaluateClip) {
+ double[] retVal = null;
+ if ((retVal = universe.renderingEnvironmentStructure.backClipDistanceInVworld(vpSchedSphereInVworld, view)) != null) {
+ backClipDistanceInVworld = retVal[0];
+ backClipActive = true;
+ }
+ else {
+ backClipActive = false;
+ }
+ view.vDirtyMask |= View.CLIP_DIRTY;
+ }
+
+ // Issue 113 - multiScreen no longer used
+// multiScreen = ((view.getScreens()).length > 1);
+
+ // renderBin is ready now, so send the offScreen message
+ size = offScreenMessage.size();
+ if ( size > 0) {
+ for (i=size-1; i>=0; i--) {
+ J3dMessage m = offScreenMessage.get(i);
+ m.threads = J3dThread.RENDER_THREAD;
+ ((Canvas3D)m.args[0]).screen.renderer.rendererStructure.addMessage(m);
+
+ // the above call will increment the reference count again
+ m.decRefcount();
+ }
+ }
+
+ // called from renderBin when there are dirtyOrientedRAs
+ // This routin cache the dirtyOrintedRAs to be updated
+ // by mastercontrol
+ if (dirtyOrientedRAs.size() > 0) {
+ // Keep a copy to be handled by mastercontrol
+ cachedDirtyOrientedRAs = new ArrayList<RenderAtom>(dirtyOrientedRAs);
+ }
+ boolean sortAll = false;
+ if (reEvaluateSortMode && transpSortMode != cachedTranspSortMode) {
+ convertTransparentRenderingStruct(transpSortMode, cachedTranspSortMode);
+ transpSortMode = cachedTranspSortMode;
+ if (transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY) {
+ if (transparentInfo != null){
+ sortAll = true;
+ }
+ }
+ }
+
+ if (vpcToVworldDirty) {
+ vworldToVpc.invert(vpcToVworld);
+ // Have the send down the lights, so set the canvas
+ // lightbin to null
+ Canvas3D canvases[] = view.getCanvases();
+ for (i = 0; i < canvases.length; i++) {
+ canvases[i].lightBin = null;
+ }
+ if (canvases.length > 0) {
+ Transform3D xform;
+ canvases[0].getCenterEyeInImagePlate(eyeInVworld);
+ // xform is imagePlateToLocal
+ xform = canvases[0].canvasViewCache.getImagePlateToVworld();
+ xform.transform(eyeInVworld);
+ }
+ if (transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY && transparentInfo != null) {
+ // System.err.println("sortAll 1");
+ sortAll = true;
+ }
+ }
+ size = dirtyDepthSortRenderAtom.size();
+
+
+ if (sortAll || size > 0) {
+ int tsize = allTransparentObjects.size();
+
+ double zVal;
+ for (i = 0; i < tsize; i++) {
+ RenderAtom renderAtom = (RenderAtom)allTransparentObjects.get(i);
+ for (k = 0; k < renderAtom.rListInfo.length; k++) {
+ if (renderAtom.rListInfo[k].geometry() == null)
+ continue;
+ zVal = renderAtom.geometryAtom.centroid[k].distanceSquared(eyeInVworld);
+ renderAtom.parentTInfo[k].zVal = zVal;
+ renderAtom.parentTInfo[k].geometryAtom = renderAtom.geometryAtom;
+ }
+ }
+
+ // Check to see if a majority of the transparent Objects have changed
+ // If less than 66% of all transparentStructs are dirty
+ // then, remove and insert, otherwise resort everything
+
+
+ if (size > 0 && 1.5f * numDirtyTinfo > nElements) {
+ // System.err.println("sortAll 3, size = "+size);
+ sortAll = true;
+ }
+
+ if (size > 0) {
+ TransparentRenderingInfo dirtyList = null;
+ Iterator<RenderAtom> dirtyDepthSortIterator = dirtyDepthSortRenderAtom.iterator();
+ while (dirtyDepthSortIterator.hasNext()) {
+ RenderAtom renderAtom = dirtyDepthSortIterator.next();
+ if (!renderAtom.inRenderBin())
+ continue;
+ renderAtom.dirtyMask &= ~RenderAtom.IN_SORTED_POS_DIRTY_TRANSP_LIST;
+ if (!sortAll) {
+ dirtyList = collectDirtyTRInfo(dirtyList, renderAtom);
+ }
+ }
+
+ if (dirtyList != null) {
+ // System.err.println("====> sort Some");
+ dirtyList = depthSortAll(dirtyList);
+ // Now merge the newly sorted list with the old one
+ transparentInfo = mergeDepthSort(transparentInfo, dirtyList);
+ }
+ }
+ // Sort all the transparent renderAtoms
+ if (sortAll) {
+ transparentInfo = depthSortAll(transparentInfo);
+ }
+ }
+
+ // Remove entries that are found on both the add and remove lists
+ if (addDlist.size() > 0 && removeDlist.size() > 0) {
+ RenderAtomListInfo arr[] = new RenderAtomListInfo[addDlist.size()];
+ arr = addDlist.toArray(arr);
+ for (i = 0; i < arr.length; i++) {
+ if (removeDlist.contains(arr[i])) {
+ addDlist.remove(arr[i]);
+ removeDlist.remove(arr[i]);
+ }
+ }
+ }
+
+ if (addDlist.size() > 0 || removeDlist.size() > 0) {
+ Canvas3D canvasList[][] = view.getCanvasList(false);
+ Canvas3D cv;
+ ArrayList<Renderer> rlist = new ArrayList<Renderer>(5);
+
+ for (i = 0; i < canvasList.length; i++) {
+ cv = canvasList[i][0];
+ if (cv.useSharedCtx) {
+ // Do this only once per renderer for this view
+ if (!rlist.contains(cv.screen.renderer)) {
+ rlist.add(cv.screen.renderer);
+ updateDlistRendererResource(cv.screen.renderer);
+ }
+ } else {
+ updateDlistCanvasResource(canvasList[i]);
+ }
+ }
+
+ }
+
+
+
+ if (dirtyRenderMoleculeList.size() > 0 ||
+ addDlistPerRinfo.size() > 0 ||
+ removeDlistPerRinfo.size() > 0 ||
+ displayListResourceFreeList.size() > 0 ||
+ toBeAddedTextureResourceFreeList.size() > 0 ) {
+
+ Canvas3D canvasList[][] = view.getCanvasList(false);
+ Canvas3D cv;
+
+ for (i = 0; i < canvasList.length; i++) {
+ cv = canvasList[i][0];
+ if (cv.useSharedCtx && (cv.screen.renderer != null)) {
+ updateRendererResource(cv.screen.renderer);
+ } else {
+ updateCanvasResource(canvasList[i]);
+ }
+ }
+
+ Integer id;
+ size = displayListResourceFreeList.size();
+ for (i = 0; i < size; i++) {
+ id = displayListResourceFreeList.get(i);
+ VirtualUniverse.mc.freeDisplayListId(id);
+ }
+
+ // lock list of dlist
+ // XXXX: Instead of copying could we keep 2 arrays
+ // and just toggle?
+ size = dirtyRenderMoleculeList.size();
+ for (i = 0; i < size; i++) {
+ RenderMolecule rm = dirtyRenderMoleculeList.get(i);
+ rm.onUpdateList = 0;
+ ra = rm.primaryRenderAtomList;
+ while (ra != null) {
+ dlistLockList.add(ra.geometry());
+ ra = ra.next;
+ }
+ }
+ size = addDlistPerRinfo.size();
+ for (i = 0; i < size; i++) {
+ ra = addDlistPerRinfo.get(i);
+ if (ra.geometry() != null) {
+ dlistLockList.add(ra.geometry());
+ }
+ }
+
+ }
+
+ clearAllUpdateObjectState();
+ /*
+ if (opaqueBin != null) {
+ System.err.println(this + "***** Begin Dumping OpaqueBin *****");
+ dumpBin(opaqueBin);
+ System.err.println("***** End Dumping OpaqueBin *****");
+ }
+ */
+
+ }
+
+
+ // Shared context case
+ void updateDlistRendererResource(Renderer rdr) {
+ int i;
+ int size = 0;
+ RenderAtomListInfo arr[];
+ RenderAtomListInfo ra;
+
+ // XXXX: there is a possible problem in the case of multiple
+ // renderers (i.e., multiple screens). Unless the
+ // MasterControl sends us a separate message for each
+ // renderer, we won't create a new display list for renderers
+ // other than the one passed into this method.
+
+ if (rdr == null) {
+ return;
+ }
+
+ if ((size = addDlist.size()) > 0) {
+ arr = new RenderAtomListInfo[size];
+ arr = addDlist.toArray(arr);
+ for (i = 0; i < size; i++) {
+ ra = arr[i];
+ GeometryArrayRetained geo = (GeometryArrayRetained)ra.geometry();
+
+ // First time thru this renderer or the context that
+ // it is built for no longer matches the context
+ // used in the renderer, create a dlist
+ sharedDList.add(ra);
+ geo.addDlistUser(this, ra);
+
+ if (((geo.resourceCreationMask & rdr.rendererBit) == 0) ||
+ (geo.getDlistTimeStamp(rdr.rendererBit) !=
+ rdr.sharedCtxTimeStamp)) {
+ geo.resourceCreationMask |= rdr.rendererBit;
+ dirtyList.add(ra);
+ }
+ }
+ }
+
+ if ((size = removeDlist.size()) > 0) {
+ arr = new RenderAtomListInfo[size];
+ arr = removeDlist.toArray(arr);
+ for (i = 0; i < size; i++) {
+ ra = arr[i];
+ sharedDList.remove(ra);
+
+ GeometryArrayRetained geo = (GeometryArrayRetained)ra.geometry();
+ geo.removeDlistUser(this, ra);
+ // System.err.println("========> geo.refcount = "+geo.refCount);
+ // add this geometry's dlist to be freed
+ if (geo.isDlistUserSetEmpty(this)) {
+ rdr.displayListResourceFreeList.add(geo.dlistObj);
+ geo.resourceCreationMask &= ~rdr.rendererBit;
+ // All Dlist on all renderer have been freed, then return dlistID
+ if (geo.resourceCreationMask == 0) {
+ geo.freeDlistId();
+ }
+ }
+ }
+ }
+ if ((size = dirtyList.size()) > 0) {
+ for (i = 0; i < size; i++) {
+ ra = dirtyList.get(i);
+ GeometryArrayRetained geo = (GeometryArrayRetained)ra.geometry();
+ if ( (geo.resourceCreationMask & rdr.rendererBit) != 0) {
+ rdr.dirtyRenderAtomList.add(ra);
+ }
+ }
+ rdr.dirtyDisplayList = true;
+ dirtyList.clear();
+ }
+ }
+
+ // Non-shared context case
+ void updateDlistCanvasResource(Canvas3D[] canvases) {
+ int i, j;
+ Canvas3D cv;
+ int size = 0;
+ RenderAtomListInfo arr[];
+ RenderAtomListInfo ra;
+
+ // Add the newly added dlist to the sharedList
+ if ((size = addDlist.size()) > 0) {
+ arr = new RenderAtomListInfo[size];
+ arr = addDlist.toArray(arr);
+ for (i = 0; i <size; i++) {
+ sharedDList.add(arr[i]);
+ // Fix for Issue 5: add the render atom to the list of users
+ // of its geometry for this RenderBin
+ GeometryArrayRetained geo = (GeometryArrayRetained) arr[i].geometry();
+ geo.addDlistUser(this, arr[i]);
+ }
+ }
+
+ // Remove the newly removed dlist from the sharedList
+ if ((size = removeDlist.size()) > 0) {
+ arr = new RenderAtomListInfo[size];
+ arr = removeDlist.toArray(arr);
+ for (i = 0; i < size; i++) {
+ sharedDList.remove(arr[i]);
+ // Fix for Issue 5: remove this render atom from the list of users
+ // of its geometry for this RenderBin
+ GeometryArrayRetained geo = (GeometryArrayRetained) arr[i].geometry();
+ geo.removeDlistUser(this, arr[i]);
+ }
+ }
+
+ // add to the dirty list per canvas
+ for (j = 0; j < canvases.length; j++) {
+ cv = canvases[j];
+
+ if ((size = addDlist.size()) > 0) {
+ arr = new RenderAtomListInfo[size];
+ arr = addDlist.toArray(arr);
+ for (i = 0; i <size; i++) {
+ ra = arr[i];
+ GeometryArrayRetained geo = (GeometryArrayRetained) ra.geometry();
+
+ if ((cv.ctx != null) &&
+ ((geo.resourceCreationMask & cv.canvasBit) == 0) ||
+ (geo.getDlistTimeStamp(cv.canvasBit) !=
+ cv.ctxTimeStamp)) {
+ geo.resourceCreationMask |= cv.canvasBit;
+ dirtyList.add(ra);
+ }
+ }
+ }
+ if ((size = removeDlist.size()) > 0) {
+ arr = new RenderAtomListInfo[size];
+ arr = removeDlist.toArray(arr);
+ for (i = 0; i < size; i++) {
+ GeometryArrayRetained geo =
+ (GeometryArrayRetained) arr[i].geometry();
+
+ // add this geometry's dlist to be freed
+ if (geo.isDlistUserSetEmpty(this)) {
+ if (cv.ctx != null) {
+ canvases[j].displayListResourceFreeList.add(geo.dlistObj);
+ }
+ geo.resourceCreationMask &= ~canvases[j].canvasBit;
+ // All Dlist on all canvases have been freed, then return dlistID
+ if (geo.resourceCreationMask == 0)
+ geo.freeDlistId();
+ }
+ }
+ }
+ if ((size = dirtyList.size()) > 0) {
+ for (i = 0; i <size; i++) {
+ ra = dirtyList.get(i);
+ GeometryArrayRetained geo = (GeometryArrayRetained)ra.geometry();
+ if ((geo.resourceCreationMask & cv.canvasBit) != 0) {
+ cv.dirtyRenderAtomList.add(ra);
+ }
+ }
+ cv.dirtyDisplayList = true;
+ dirtyList.clear();
+ }
+ }
+
+
+ }
+
+ void clearAllUpdateObjectState() {
+ localeChanged = false;
+ obList.clear();
+ rmUpdateList.clear();
+ ogCIOList.clear();
+ aBinUpdateList.clear();
+ sBinUpdateList.clear();
+ tbUpdateList.clear();
+ removeRenderAtomInRMList.clear();
+ addOpaqueBin = null;
+ bgAddOpaqueBin = null;
+ orderedBinsList.clear();
+ toBeAddedBinList.clear();
+ objUpdateList.clear();
+ raLocaleVwcBoundsUpdateList.clear();
+ displayListResourceFreeList.clear();
+ toBeAddedTextureResourceFreeList.clear();
+ dirtyRenderMoleculeList.clear();
+ dirtyReferenceGeomList.clear();
+ reEvaluateBg = false;
+ reloadBgTexture = false;
+ textureBinList.clear();
+ newNodeComponentList.clear();
+ removeNodeComponentList.clear();
+ dirtyNodeComponentList.clear();
+ reEvaluateClip = false;
+ vpcToVworldDirty = false;
+ offScreenMessage.clear();
+ addDlist.clear();
+ removeDlist.clear();
+ addDlistPerRinfo.clear();
+ removeDlistPerRinfo.clear();
+ clearDirtyOrientedRAs();
+ reEvaluateSortMode = false;
+ dirtyDepthSortRenderAtom.clear();
+ numDirtyTinfo = 0;
+ }
+
+ void updateRendererResource(Renderer rdr) {
+ RenderMolecule rm;
+ TextureRetained tex;
+ Integer texIdObj;
+
+ if (rdr == null)
+ return;
+
+ // Take care of display lists per Rinfo that should be rebuilt
+ int size = addDlistPerRinfo.size();
+
+ if (size > 0) {
+ for (int j = 0; j < size; j++) {
+ RenderAtomListInfo rinfo = addDlistPerRinfo.get(j);
+ if (rinfo.renderAtom.inRenderBin()) {
+ Object[] obj = new Object[2];
+ obj[0] = rinfo;
+ obj[1] = rinfo.renderAtom.renderMolecule;
+ rdr.dirtyDlistPerRinfoList.add(obj);
+ }
+ }
+ rdr.dirtyDisplayList = true;
+ }
+
+
+ // Take care of display lists that should be rebuilt
+ size = dirtyRenderMoleculeList.size();
+ if (size > 0) {
+ for (int j = 0; j < size; j++) {
+ rm = dirtyRenderMoleculeList.get(j);
+ rdr.dirtyRenderMoleculeList.add(rm);
+ }
+ rdr.dirtyDisplayList = true;
+ }
+
+ // Take care of texture that should be freed
+ size = toBeAddedTextureResourceFreeList.size();
+ int id;
+ for (int j=0; j < size; j++) {
+ tex = toBeAddedTextureResourceFreeList.get(j);
+ id = tex.objectId;
+ if ((id >= rdr.textureIDResourceTable.size()) ||
+ (id <= 0) ||
+ (rdr.textureIDResourceTable.get(id) != tex)) {
+ // tex.objectId may change by another Renderer thread,
+ // need find original texID from searching
+ // rdr.textureIdResourceTable
+ id = rdr.textureIDResourceTable.indexOf(tex);
+
+ if (id <= 0) {
+ continue;
+ }
+ }
+
+ // Since multiple renderBins (in the same screen)
+ // can share a texture object, make sure that
+ // we are not duplicating what has been added
+ // by a different renderBin in the same screen
+ if ((tex.resourceCreationMask & rdr.rendererBit) != 0) {
+ texIdObj = new Integer(id);
+ if (!rdr.textureIdResourceFreeList.contains(texIdObj)) {
+ rdr.textureIdResourceFreeList.add(texIdObj);
+ tex.resourceCreationMask &= ~rdr.rendererBit;
+ }
+ }
+ }
+
+ // Take care of display list that should be freed
+ size = displayListResourceFreeList.size();
+ Integer displayListIDObj;
+
+ for (int j=0; j <size; j++) {
+ displayListIDObj = displayListResourceFreeList.get(j);
+ // It doesn't harm to free the same ID twice, the
+ // underlying graphics library just ignore the second request
+ rdr.displayListResourceFreeList.add(displayListIDObj);
+ }
+ // Take care of display list that should be freed
+ size = removeDlistPerRinfo.size();
+ for (int j=0; j < size; j++) {
+ RenderAtomListInfo ra = removeDlistPerRinfo.get(j);
+ rdr.displayListResourceFreeList.add(new Integer(ra.renderAtom.dlistIds[ra.index]));
+ ra.groupType = 0;
+ ra.renderAtom.dlistIds[ra.index] = -1;
+ }
+ }
+
+ void updateCanvasResource(Canvas3D[] canvases) {
+ int i, j;
+ RenderMolecule rm;
+ TextureRetained tex;
+ Integer texIdObj;
+
+ // update dirtyRenderMoleculeList for each canvas
+ for (i = 0; i < canvases.length; i++) {
+ Canvas3D cv = canvases[i];
+
+ // Take care of display lists per Rinfo that should be rebuilt
+ int size = addDlistPerRinfo.size();
+ if (size > 0) {
+ for ( j = 0; j < size; j++) {
+ RenderAtomListInfo rinfo = addDlistPerRinfo.get(j);
+ if (rinfo.renderAtom.inRenderBin()) {
+ Object[] obj = new Object[2];
+ obj[0] = rinfo;
+ obj[1] = rinfo.renderAtom.renderMolecule;
+ cv.dirtyDlistPerRinfoList.add(obj);
+ }
+ }
+ cv.dirtyDisplayList = true;
+ }
+ // Take care of display lists that should be rebuilt
+ size = dirtyRenderMoleculeList.size();
+ if (size > 0) {
+ for (j = 0; j < size; j++) {
+ rm = dirtyRenderMoleculeList.get(j);
+ cv.dirtyRenderMoleculeList.add(rm);
+ }
+ cv.dirtyDisplayList = true;
+ }
+ // Take care of texture that should be freed
+ size = toBeAddedTextureResourceFreeList.size();
+ int id;
+ for (j=0; j < size; j++) {
+ tex = toBeAddedTextureResourceFreeList.get(j);
+ id = tex.objectId;
+ if ((id >= cv.textureIDResourceTable.size()) ||
+ (id <= 0) ||
+ (cv.textureIDResourceTable.get(id) != tex)) {
+ // tex.objectId may change by another Renderer thread,
+ // need find original texID from searching
+ // rdr.textureIdResourceTable
+ id = cv.textureIDResourceTable.indexOf(tex);
+
+ if (id <= 0) {
+ continue;
+ }
+ }
+
+ if ((tex.resourceCreationMask & cv.canvasBit) != 0) {
+ texIdObj = new Integer(id);
+ cv.textureIdResourceFreeList.add(texIdObj);
+ tex.resourceCreationMask &= ~cv.canvasBit;
+ }
+ }
+ // Take care of display list that should be freed
+ size = displayListResourceFreeList.size();
+ for (j=0; j < size; j++) {
+ cv.displayListResourceFreeList.add(displayListResourceFreeList.get(j));
+ }
+ // Take care of display list that should be freed
+ size = removeDlistPerRinfo.size();
+ for (j=0; j < size; j++) {
+ RenderAtomListInfo ra = removeDlistPerRinfo.get(j);
+ cv.displayListResourceFreeList.add(new Integer(ra.renderAtom.dlistIds[ra.index]));
+ ra.groupType = 0;
+ ra.renderAtom.dlistIds[ra.index] = -1;
+
+ }
+ }
+
+ }
+
+ @Override
+ void processMessages(long referenceTime) {
+ int i;
+ J3dMessage messages[], m;
+ int component;
+
+ messages = getMessages(referenceTime);
+ int nMsg = getNumMessage();
+
+ if (nMsg > 0) {
+ for (i=0; i < nMsg; i++) {
+ m = messages[i];
+ switch (m.type) {
+ case J3dMessage.INSERT_NODES:
+ insertNodes(m);
+ m.decRefcount();
+ break;
+ case J3dMessage.REMOVE_NODES:
+ removeNodes(m);
+ m.decRefcount();
+ break;
+ case J3dMessage.TRANSFORM_CHANGED:
+ transformMsg = true;
+ m.decRefcount();
+ break;
+ case J3dMessage.LIGHT_CHANGED:
+ // if none of the mirror lights are scoped to this view
+ // ignore this message
+ LightRetained[] mLts =(LightRetained[])m.args[3] ;
+ for (int k = 0; k < mLts.length; k++) {
+ if (universe.renderingEnvironmentStructure.isLightScopedToThisView(mLts[k], view)) {
+ lightMessageList.add(m);
+ break;
+ }
+
+ }
+ break;
+ case J3dMessage.SWITCH_CHANGED:
+ visGAIsDirty = true;
+ visQuery = true;
+ processSwitchChanged(m, referenceTime);
+ // may need to process dirty switched-on transform
+ if (universe.transformStructure.getLazyUpdate()) {
+ transformMsg = true;
+ }
+ m.decRefcount();
+ break;
+ case J3dMessage.BACKGROUND_CHANGED:
+ BackgroundRetained bg = (BackgroundRetained)m.args[0];
+ if (universe.renderingEnvironmentStructure.isBgScopedToThisView(bg, view)) {
+ reEvaluateBg = true;
+ reloadBgTexture = true;
+ }
+ m.decRefcount();
+ break;
+ case J3dMessage.CLIP_CHANGED:
+ ClipRetained c = (ClipRetained)m.args[0];
+ if (universe.renderingEnvironmentStructure.isClipScopedToThisView(c, view))
+ reEvaluateClip = true;
+ m.decRefcount();
+ break;
+ case J3dMessage.TRANSPARENCYATTRIBUTES_CHANGED:
+ {
+ NodeComponentRetained nc = (NodeComponentRetained) m.args[0];
+ GeometryAtom[] gaArr = (GeometryAtom[])m.args[3];
+ RenderAtom ra = null;
+ int start = -1;
+
+ // Get the first ra that is visible
+ for (int k = 0; (k < gaArr.length && (start < 0)); k++) {
+ ra = gaArr[k].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+ else {
+ start = k;
+ }
+ }
+
+ if (start >= 0) {
+ boolean restructure = (nc.mirror.changedFrequent == 0 ||
+ ra.renderMolecule.definingTransparency != nc.mirror);
+ processRenderMoleculeNodeComponentChanged(m.args,
+ RenderMolecule.TRANSPARENCY_DIRTY,
+ start, restructure);
+ }
+ m.decRefcount();
+ break;
+ }
+ case J3dMessage.POLYGONATTRIBUTES_CHANGED:
+ {
+ NodeComponentRetained nc = (NodeComponentRetained) m.args[0];
+ GeometryAtom[] gaArr = (GeometryAtom[])m.args[3];
+ RenderAtom ra = null;
+ int start = -1;
+
+ // Get the first ra that is visible
+ // Get the first ra that is visible
+ for (int k = 0; (k < gaArr.length && (start < 0)); k++) {
+ ra = gaArr[k].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+ else {
+ start = k;
+ }
+ }
+
+ if (start >= 0) {
+ boolean restructure = (nc.mirror.changedFrequent == 0 ||
+ ra.renderMolecule.definingPolygonAttributes != nc.mirror);
+ processRenderMoleculeNodeComponentChanged(m.args,
+ RenderMolecule.POLYGONATTRS_DIRTY,
+ start, restructure);
+ }
+ m.decRefcount();
+ break;
+ }
+ case J3dMessage.LINEATTRIBUTES_CHANGED:
+ {
+ NodeComponentRetained nc = (NodeComponentRetained) m.args[0];
+ GeometryAtom[] gaArr = (GeometryAtom[])m.args[3];
+ RenderAtom ra = null;
+ int start = -1;
+
+ // Get the first ra that is visible
+ // Get the first ra that is visible
+ for (int k = 0; (k < gaArr.length && (start < 0)); k++) {
+ ra = gaArr[k].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+ else {
+ start = k;
+ }
+ }
+
+ if (start >= 0) {
+ boolean restructure = (nc.mirror.changedFrequent == 0 ||
+ ra.renderMolecule.definingLineAttributes != nc.mirror);
+ processRenderMoleculeNodeComponentChanged(m.args,
+ RenderMolecule.LINEATTRS_DIRTY,
+ start, restructure);
+ }
+ m.decRefcount();
+ break;
+ }
+ case J3dMessage.POINTATTRIBUTES_CHANGED:
+ {
+ NodeComponentRetained nc = (NodeComponentRetained) m.args[0];
+ GeometryAtom[] gaArr = (GeometryAtom[])m.args[3];
+ RenderAtom ra = null;
+ int start = -1;
+ // Get the first ra that is visible
+ // Get the first ra that is visible
+ for (int k = 0; (k < gaArr.length && (start < 0)); k++) {
+ ra = gaArr[k].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+ else {
+ start = k;
+ }
+ }
+
+ if (start >= 0) {
+ boolean restructure = (nc.mirror.changedFrequent == 0 ||
+ ra.renderMolecule.definingPointAttributes != nc.mirror);
+
+ processRenderMoleculeNodeComponentChanged(m.args,
+ RenderMolecule.POINTATTRS_DIRTY,
+ start, restructure);
+ }
+ m.decRefcount();
+ break;
+ }
+ case J3dMessage.MATERIAL_CHANGED:
+ {
+ NodeComponentRetained nc = (NodeComponentRetained) m.args[0];
+ GeometryAtom[] gaArr = (GeometryAtom[])m.args[3];
+ RenderAtom ra = null;
+ int start = -1;
+
+ // Get the first ra that is visible
+ // Get the first ra that is visible
+ for (int k = 0; (k < gaArr.length && (start < 0)); k++) {
+ ra = gaArr[k].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+ else {
+ start = k;
+ }
+ }
+
+ if (start >= 0) {
+ boolean restructure = (nc.mirror.changedFrequent == 0 ||
+ ra.renderMolecule.definingMaterial != nc.mirror);
+ processRenderMoleculeNodeComponentChanged(m.args,
+ RenderMolecule.MATERIAL_DIRTY,
+ start, restructure);
+ }
+ m.decRefcount();
+ break;
+ }
+ case J3dMessage.COLORINGATTRIBUTES_CHANGED:
+ {
+ NodeComponentRetained nc = (NodeComponentRetained) m.args[0];
+ GeometryAtom[] gaArr = (GeometryAtom[])m.args[3];
+ RenderAtom ra = null;
+ int start = -1;
+
+ // Get the first ra that is visible
+ // Get the first ra that is visible
+ for (int k = 0; (k < gaArr.length && (start < 0)); k++) {
+ ra = gaArr[k].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+ else {
+ start = k;
+ }
+ }
+
+ if (start >= 0) {
+ boolean restructure = (nc.mirror.changedFrequent == 0 ||
+ ra.renderMolecule.definingColoringAttributes != nc.mirror);
+ processRenderMoleculeNodeComponentChanged(m.args,
+ RenderMolecule.COLORINGATTRS_DIRTY,
+ start, restructure);
+ }
+ m.decRefcount();
+ break;
+ }
+ case J3dMessage.TEXTUREATTRIBUTES_CHANGED:
+ processTextureAttributesChanged(
+ (NodeComponentRetained) m.args[0],
+ (GeometryAtom[])m.args[3]);
+ m.decRefcount();
+ break;
+ case J3dMessage.IMAGE_COMPONENT_CHANGED:
+ addDirtyNodeComponent((NodeComponentRetained)m.args[0]);
+ m.decRefcount();
+ break;
+ case J3dMessage.TEXTURE_UNIT_STATE_CHANGED:
+ processTextureUnitStateChanged(
+ (NodeComponentRetained) m.args[0],
+ (GeometryAtom[])m.args[3]);
+ m.decRefcount();
+ break;
+ case J3dMessage.TEXCOORDGENERATION_CHANGED:
+ processTexCoordGenerationChanged( (NodeComponentRetained) m.args[0],
+ (GeometryAtom[])m.args[3]);
+ m.decRefcount();
+ break;
+ case J3dMessage.TEXTURE_CHANGED:
+ // Texture is always in a sole user position
+ processTextureChanged((NodeComponentRetained) m.args[0],
+ (GeometryAtom[])m.args[3],
+ m.args);
+ m.decRefcount();
+ break;
+ case J3dMessage.SHADER_APPEARANCE_CHANGED:
+ case J3dMessage.SHADER_ATTRIBUTE_SET_CHANGED:
+ case J3dMessage.SHADER_ATTRIBUTE_CHANGED:
+ processShaderComponentChanged(m.args);
+ m.decRefcount();
+ break;
+ case J3dMessage.RENDERINGATTRIBUTES_CHANGED:
+ processAttributeBinNodeComponentChanged(m.args);
+ component = ((Integer)m.args[1]).intValue();
+ if (component == RenderingAttributesRetained.VISIBLE) {
+ visGAIsDirty = true;
+ visQuery = true;
+ }
+ m.decRefcount();
+ break;
+ case J3dMessage.APPEARANCE_CHANGED:
+ processAppearanceChanged(m.args);
+ m.decRefcount();
+ break;
+ case J3dMessage.FOG_CHANGED:
+ FogRetained mfog = ((FogRetained)m.args[0]).mirrorFog;
+ if (universe.renderingEnvironmentStructure.isFogScopedToThisView(mfog, view)) {
+ processFogChanged(m.args);
+ }
+ m.decRefcount();
+ break;
+ case J3dMessage.ALTERNATEAPPEARANCE_CHANGED:
+ AlternateAppearanceRetained maltapp = ((AlternateAppearanceRetained)m.args[0]).mirrorAltApp;
+ if (universe.renderingEnvironmentStructure.isAltAppScopedToThisView(maltapp, view)) {
+ altAppearanceDirty = true;
+ }
+ m.decRefcount();
+ break;
+ case J3dMessage.MODELCLIP_CHANGED:
+ ModelClipRetained mc= ((ModelClipRetained)m.args[0]).mirrorModelClip;
+ if (universe.renderingEnvironmentStructure.isMclipScopedToThisView(mc, view)) {
+ processModelClipChanged(m.args);
+ }
+ m.decRefcount();
+ break;
+ case J3dMessage.BOUNDINGLEAF_CHANGED:
+ processBoundingLeafChanged(m.args,
+ referenceTime);
+ m.decRefcount();
+ break;
+ case J3dMessage.SHAPE3D_CHANGED:
+ processShapeChanged(m.args, referenceTime);
+ m.decRefcount();
+ break;
+ case J3dMessage.ORIENTEDSHAPE3D_CHANGED:
+ processOrientedShape3DChanged((Object[])m.args[0]);
+ m.decRefcount();
+ break;
+ case J3dMessage.MORPH_CHANGED:
+ processMorphChanged(m.args, referenceTime);
+ component = ((Integer)m.args[1]).intValue();
+ if ((component & MorphRetained.GEOMETRY_CHANGED) == 0) {
+ visGAIsDirty = true;
+ visQuery = true;
+ }
+ m.decRefcount();
+ break;
+ case J3dMessage.UPDATE_VIEW:
+ {
+ View v = (View)m.args[0];
+ ViewPlatform vp = v.getViewPlatform();
+ int comp = ((Integer)(m.args[2])).intValue();
+ int value = ((Integer)(m.args[3])).intValue();
+ if (comp == View.TRANSP_SORT_POLICY_CHANGED) {
+ if (value != transpSortMode) {
+ reEvaluateSortMode = true;
+ cachedTranspSortMode = value;
+ }
+ } else if (vp != null) {
+ if (value != transpSortMode) {
+ reEvaluateSortMode = true;
+ cachedTranspSortMode = value;
+ }
+ updateViewPlatform((ViewPlatformRetained)vp.retained,
+ ((Float)m.args[1]).floatValue());
+ visQuery = true;
+ // XXXX : Handle view.visibilityPolicy changed.
+ if(((View.VISIBILITY_POLICY_DIRTY != 0) &&
+ (View.VISIBILITY_DRAW_ALL != view.viewCache.visibilityPolicy)) ||
+ locale != ((ViewPlatformRetained) (vp.retained)).locale) {
+
+ for (int n = (renderAtoms.size() - 1); n>=0 ; n--) {
+ removeARenderAtom(renderAtoms.get(n));
+ }
+ renderAtoms.clear();
+ visGAIsDirty = true;
+ if (locale != ((ViewPlatformRetained) (vp.retained)).locale) {
+ locale = ((ViewPlatformRetained) (vp.retained)).locale;
+ localeChanged = true;
+ }
+ }
+ }
+ m.decRefcount();
+ }
+ break;
+ case J3dMessage.UPDATE_VIEWPLATFORM:
+ updateViewPlatform((ViewPlatformRetained) m.args[0],
+ ((Float)m.args[1]).floatValue());
+ m.decRefcount();
+ break;
+ case J3dMessage.TEXT3D_DATA_CHANGED:
+ processDataChanged((Object[])m.args[0],
+ (Object[])m.args[1],
+ referenceTime);
+ m.decRefcount();
+ break;
+ case J3dMessage.GEOMETRY_CHANGED:
+ processGeometryChanged(m.args);
+ visGAIsDirty = true;
+ visQuery = true;
+ m.decRefcount();
+ break;
+
+ case J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED:
+ case J3dMessage.REGION_BOUND_CHANGED:
+ processGeometryAtomsChanged((Object[])m.args[0]);
+ visGAIsDirty = true;
+ visQuery = true;
+ m.decRefcount();
+ break;
+ case J3dMessage.TEXT3D_TRANSFORM_CHANGED:
+ processText3DTransformChanged((Object[])m.args[0],
+ (Object[])m.args[1],
+ referenceTime);
+ visQuery = true;
+ m.decRefcount();
+ break;
+ case J3dMessage.ORDERED_GROUP_INSERTED:
+ processOrderedGroupInserted(m);
+ // Do not do decRefcount() here. We'll do it in updateObject().
+ ogCIOList.add(m);
+ break;
+ case J3dMessage.ORDERED_GROUP_REMOVED:
+ processOrderedGroupRemoved(m);
+ // Do not do decRefcount() here. We'll do it in updateObject().
+ ogCIOList.add(m);
+ break;
+ case J3dMessage.ORDERED_GROUP_TABLE_CHANGED:
+ // Do not do decRefcount() here. We'll do it in updateObject().
+ ogCIOList.add(m);
+ break;
+ case J3dMessage.RENDER_OFFSCREEN:
+ offScreenMessage.add(m);
+ break;
+ case J3dMessage.VIEWSPECIFICGROUP_CHANGED:
+ processViewSpecificGroupChanged(m);
+ visQuery = true;
+ m.decRefcount();
+ break;
+ default:
+ m.decRefcount();
+ }
+ }
+
+ if (transformMsg) {
+ processTransformChanged(referenceTime);
+ transformMsg = false;
+ }
+ if (lightMessageList.size() > 0) {
+ processLightChanged();
+ lightMessageList.clear();
+ }
+ VirtualUniverse.mc.addMirrorObject(this);
+
+ // clear the array to prevent memory leaks
+ Arrays.fill(messages, 0, nMsg, null);
+ }
+
+ if (reEvaluateBg) {
+ currentActiveBackground = universe.renderingEnvironmentStructure.
+ getApplicationBackground(vpSchedSphereInVworld, locale, view);
+ }
+
+
+ if (visQuery) {
+ GeometryAtom[] bgGeometryAtoms;
+ boolean allEnComp;
+
+ // computeViewFrustumBox in VisibilityStructure.
+ computeViewFrustumBBox(viewFrustumBBox);
+ // System.err.println("viewFrustumBBox = " + this);
+
+ ViewPlatform vp = view.getViewPlatform();
+ if (vp != null) {
+ allEnComp = universe.geometryStructure.
+ getVisibleBHTrees(this, viewFrustumBBox,
+ locale, referenceTime,
+ visGAIsDirty || reactivateView || localeChanged ||
+ ((view.viewCache.vcDirtyMask &
+ View.VISIBILITY_POLICY_DIRTY) != 0),
+ view.viewCache.visibilityPolicy);
+
+ reactivateView = false;
+ // process background geometry atoms
+ if (currentActiveBackground != null &&
+ currentActiveBackground.geometryBranch != null) {
+ bgGeometryAtoms =
+ currentActiveBackground.getBackgroundGeometryAtoms();
+ if (bgGeometryAtoms != null) {
+ processBgGeometryAtoms(bgGeometryAtoms, referenceTime);
+ }
+ }
+
+ if(!allEnComp) {
+ // Increment the framecount for compaction ...
+ frameCount++;
+ if (frameCount > frameCountCutoff) {
+ frameCount = 0;
+ checkForCompaction();
+ }
+ else if (frameCount == notVisibleCount) {
+ removeCutoffTime = referenceTime;
+ }
+ }
+ }
+ // Reset dirty bits.
+ visGAIsDirty = false;
+ visQuery = false;
+
+ }
+ // Two environments are dirty
+ // If lights, fog or model clip have been added/removed, then
+ // reEvaluate RenderAtoms and mark the lightbin and
+ // env set dirty if applicable
+ if (envDirty == REEVALUATE_ALL_ENV || envDirty == 3 ||
+ envDirty > 4) {
+ reEvaluateEnv(changedLts, changedFogs, changedModelClips, true,
+ altAppearanceDirty);
+ }
+ else if (envDirty == 0 && altAppearanceDirty) {
+ reEvaluateAlternateAppearance();
+ }
+ else {
+ if ((envDirty & REEVALUATE_LIGHTS) != 0) {
+ reEvaluateLights(altAppearanceDirty);
+ }
+ else if ((envDirty & REEVALUATE_FOG) != 0)
+ reEvaluateFog(changedFogs, (changedFogs.size() > 0), altAppearanceDirty);
+ else if ((envDirty & REEVALUATE_MCLIP) != 0)
+ reEvaluateModelClip(changedModelClips, (changedModelClips.size() > 0), altAppearanceDirty);
+ }
+
+
+
+ // do any pre-update node component screening
+
+ if (updateCheckList.size() > 0) {
+ int size = updateCheckList.size();
+ for (int k = 0; k < size; k++) {
+ updateCheckList.get(k).updateNodeComponentCheck();
+ }
+ updateCheckList.clear();
+ }
+
+
+ changedLts.clear();
+ changedFogs.clear();
+ changedModelClips.clear();
+ envDirty = 0;
+ altAppearanceDirty = false;
+
+ view.renderBinReady = true;
+
+ VirtualUniverse.mc.sendRunMessage(view,
+ J3dThread.RENDER_THREAD);
+ }
+
+
+ void processSwitchChanged(J3dMessage m, long refTime) {
+ int i;
+ UnorderList arrList;
+ int size;
+ Object[] nodes, nodesArr;
+
+ RenderingEnvironmentStructure rdrEnvStr =
+ universe.renderingEnvironmentStructure;
+
+ UpdateTargets targets = (UpdateTargets)m.args[0];
+ arrList = targets.targetList[Targets.ENV_TARGETS];
+
+ if (arrList != null) {
+ size = arrList.size();
+ nodesArr = arrList.toArray(false);
+
+ for (int h=0; h<size; h++) {
+ nodes = (Object[])nodesArr[h];
+ for (i=0; i<nodes.length; i++) {
+
+ if (nodes[i] instanceof LightRetained &&
+ rdrEnvStr.isLightScopedToThisView(nodes[i], view)) {
+ envDirty |= REEVALUATE_LIGHTS;
+ } else if (nodes[i] instanceof FogRetained &&
+ rdrEnvStr.isFogScopedToThisView(nodes[i], view)) {
+ envDirty |= REEVALUATE_FOG;
+ } else if (nodes[i] instanceof ModelClipRetained &&
+ rdrEnvStr.isMclipScopedToThisView(nodes[i], view)) {
+ envDirty |= REEVALUATE_MCLIP;
+ } else if (nodes[i] instanceof BackgroundRetained &&
+ rdrEnvStr.isBgScopedToThisView(nodes[i], view)) {
+ reEvaluateBg = true;
+ } else if (nodes[i] instanceof ClipRetained &&
+ rdrEnvStr.isClipScopedToThisView(nodes[i], view)) {
+ reEvaluateClip = true;
+ } else if (nodes[i] instanceof AlternateAppearanceRetained &&
+ rdrEnvStr.isAltAppScopedToThisView(nodes[i], view)) {
+ altAppearanceDirty = true;
+ }
+ }
+ }
+ }
+
+ arrList = targets.targetList[Targets.BLN_TARGETS];
+ if (arrList != null) {
+ size = arrList.size();
+ nodesArr = arrList.toArray(false);
+ Object[] objArr = (Object[])m.args[1];
+ Object[] obj, users;
+
+ for (int h=0; h<size; h++) {
+ nodes = (Object[])nodesArr[h];
+ obj = (Object[])objArr[h];
+ for (i=0; i<nodes.length; i++) {
+
+ users = (Object[])obj[i];
+ // BoundingLeafRetained mbleaf = (BoundingLeafRetained) nodes[i];
+ for (int j = 0; j < users.length; j++) {
+
+ if (users[j] instanceof FogRetained &&
+ rdrEnvStr.isFogScopedToThisView(users[j], view)) {
+ envDirty |= REEVALUATE_FOG;
+ } else if (users[j] instanceof LightRetained &&
+ rdrEnvStr.isLightScopedToThisView(users[j], view)) {
+ envDirty |= REEVALUATE_LIGHTS;
+ } else if (users[j] instanceof ModelClipRetained &&
+ rdrEnvStr.isMclipScopedToThisView(users[j], view)) {
+ envDirty |= REEVALUATE_MCLIP;
+ } else if (users[j] instanceof
+ AlternateAppearanceRetained &&
+ rdrEnvStr.isAltAppScopedToThisView(users[j], view)) {
+ altAppearanceDirty = true;
+ } else if (users[j] instanceof BackgroundRetained &&
+ rdrEnvStr.isBgScopedToThisView(users[j], view)) {
+ reEvaluateBg = true;
+ } else if (users[j] instanceof ClipRetained &&
+ rdrEnvStr.isClipScopedToThisView(users[j], view)) {
+ reEvaluateClip = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Transparency/Line/point/Poly attributes is different from other renderMolecule
+ * attributes since the renderatom could move from opaque bin
+ * to transparent bin
+ */
+ void processPossibleBinChanged(Object[] args) {
+ int i;
+ GeometryAtom[] gaArr = (GeometryAtom[])args[3];
+ for (i = 0; i < gaArr.length; i++) {
+ RenderAtom ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+ // If renderAtom is in orderedGroup or with this
+ // change continues to be in the same higher level
+ // lightBin(transparent or opaque) then reInsert at
+ // the textureBin level, other Insert at the lightBin
+ // level
+ TextureBin tb = ra.renderMolecule.textureBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertRenderAtom(tb, ra);
+ }
+ }
+
+
+ /**
+ * This processes a materiala and other rendermolecule node comp change.
+ */
+ void processRenderMoleculeNodeComponentChanged(Object[] args, int mask, int start,
+ boolean restructure) {
+ int i;
+ // NodeComponentRetained nc = (NodeComponentRetained) args[0];
+ GeometryAtom[] gaArr = (GeometryAtom[])args[3];
+ for (i = start; i < gaArr.length; i++) {
+ RenderAtom ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+ // Check if the changed renderAtom is already in
+ // a separate bin - this is to handle the case
+ // when it has been changed to frequent, then to
+ // infrequent and then to frequent again!
+ // If the bin is in soleUser case and one of the components
+ // has been changed to frequent then remove the clone
+ // and point to the mirror
+ // System.err.println("restructure = "+restructure+" ra.renderMolecule.soleUser ="+ra.renderMolecule.soleUser);
+ if (restructure && !ra.renderMolecule.soleUser) {
+ TextureBin tb = ra.renderMolecule.textureBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertRenderAtom(tb, ra);
+ /*
+ if (nc.mirror.changedFrequent != 0) {
+ if ((ra.renderMolecule.soleUserCompDirty& RenderMolecule.ALL_DIRTY_BITS) == 0 ) {
+ rmUpdateList.add(ra.renderMolecule);
+ }
+ ra.renderMolecule.soleUserCompDirty |= mask;
+ }
+ */
+ }
+ else {
+ if ((ra.renderMolecule.soleUserCompDirty& RenderMolecule.ALL_DIRTY_BITS) == 0 ) {
+ rmUpdateList.add(ra.renderMolecule);
+ }
+ ra.renderMolecule.soleUserCompDirty |= mask;
+ }
+ }
+
+ }
+
+
+ void processTextureAttributesChanged(NodeComponentRetained nc,
+ GeometryAtom[] gaArr) {
+
+ RenderAtom ra = null;
+ TextureBin tb;
+ ShaderBin sb;
+ boolean reInsertNeeded = false;
+
+ if (nc.mirror.changedFrequent == 0) {
+ reInsertNeeded = true;
+ }
+
+ for (int k = 0; k < gaArr.length; k++) {
+ ra = gaArr[k].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+
+ tb = ra.renderMolecule.textureBin;
+
+ if (!reInsertNeeded) {
+
+ // if changedFrequent is not zero, then need
+ // to check if the node component is currently
+ // in an equivalent bin or not. If it is in an
+ // equivalent bin, then the affected ra needs to
+ // be reinserted to a bin with a soleUser
+ // TextureAttributes
+
+ for (int t = 0; t < tb.texUnitState.length; t++) {
+
+ if (tb.texUnitState[t] == null) {
+ continue;
+
+ } else if (tb.texUnitState[t].texAttrs == nc.mirror) {
+ // the TextureAttributes is already in
+ // a sole user position, no need to do anything;
+ // can bail out now
+ return;
+ }
+ }
+ }
+
+ if ((tb.tbFlag & TextureBin.SOLE_USER) != 0) {
+
+ // if the TextureBin is a sole user, then
+ // no need to reInsert, just simply update the
+ // TextureAttributes references @update
+
+ if (tb.soleUserCompDirty == 0) {
+ tbUpdateList.add(tb);
+ }
+
+ tb.soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TA;
+
+ } else {
+ sb= ra.renderMolecule.textureBin.shaderBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertTextureBin(sb, ra);
+ }
+ }
+ }
+
+ void processTexCoordGenerationChanged(NodeComponentRetained nc,
+ GeometryAtom[] gaArr) {
+
+ RenderAtom ra = null;
+ TextureBin tb;
+ ShaderBin sb;
+ boolean reInsertNeeded = false;
+
+ if (nc.mirror.changedFrequent == 0) {
+ reInsertNeeded = true;
+ }
+
+ for (int k = 0; k < gaArr.length; k++) {
+ ra = gaArr[k].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+
+ tb = ra.renderMolecule.textureBin;
+
+ if (!reInsertNeeded) {
+
+ // if changedFrequent is not zero, then need
+ // to check if the node component is currently
+ // in an equivalent bin or not. If it is in an
+ // equivalent bin, then the affected ra needs to
+ // be reinserted to a bin with a soleUser
+ // TexCoordGeneration
+
+ for (int t = 0; t < tb.texUnitState.length; t++) {
+
+ if (tb.texUnitState[t] == null) {
+ continue;
+
+ } else if (tb.texUnitState[t].texGen == nc.mirror) {
+ // the TexCoordGeneration is already in
+ // a sole user position, no need to do anything;
+ // can bail out now
+ return;
+ }
+ }
+ }
+
+ if ((tb.tbFlag & TextureBin.SOLE_USER) != 0) {
+
+ // if the TextureBin is a sole user, then
+ // no need to reInsert, just simply update the
+ // TexCoordGeneration references @update
+
+ if (tb.soleUserCompDirty == 0) {
+ tbUpdateList.add(tb);
+ }
+
+ tb.soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TC;
+
+ } else {
+ sb= ra.renderMolecule.textureBin.shaderBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertTextureBin(sb, ra);
+ }
+ }
+ }
+
+
+ void processTextureChanged(NodeComponentRetained nc,
+ GeometryAtom[] gaArr,
+ Object args[]) {
+
+ RenderAtom ra = null;
+ TextureBin tb;
+ int command = ((Integer)args[1]).intValue();
+
+ switch (command) {
+ case TextureRetained.ENABLE_CHANGED: {
+ for (int i = 0; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ tb = ra.renderMolecule.textureBin;
+
+ if (tb.soleUserCompDirty == 0) {
+ // put this texture unit state on the sole user
+ // update list if it's not already there
+ tbUpdateList.add(tb);
+ }
+
+ tb.soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TEXTURE;
+ }
+ break;
+ }
+ case TextureRetained.IMAGE_CHANGED: {
+
+ TextureRetained texture = (TextureRetained)nc.mirror;
+ Object imgChangedArgs[] = (Object[])args[2];
+ int level = ((Integer)imgChangedArgs[0]).intValue();
+ int face = ((Integer)imgChangedArgs[2]).intValue();
+ ImageComponent newImage = (ImageComponent)imgChangedArgs[1];
+ ImageComponentRetained oldImage;
+
+ // first remove the old image from the RenderBin's
+ // node component list if necessary.
+ // Note: image reference in the texture mirror object
+ // is not updated yet, so it's ok to reference
+ // the mirror object for the old image reference
+
+ oldImage = texture.images[face][level];
+
+ // it is possible that oldImage.source == null because
+ // the mipmap could have been created by the library, and
+ // hence don't have source
+
+ if (oldImage != null) {
+ this.removeNodeComponent(oldImage);
+ }
+
+ // then add the new one to the list if it is byReference or
+ // modifiable.
+
+ if (newImage != null ) {
+ this.addNodeComponent(newImage.retained);
+ }
+ break;
+ }
+ case TextureRetained.IMAGES_CHANGED: {
+ Object imgChangedArgs[] = (Object [])args[2];
+ ImageComponent images[] = (ImageComponent [])imgChangedArgs[0];
+ int face = ((Integer)imgChangedArgs[1]).intValue();
+ TextureRetained texture = (TextureRetained)nc.mirror;
+ ImageComponentRetained oldImage;
+
+ for (int i = 0; i < texture.maxLevels; i++) {
+
+ // first remove the old image from the RenderBin's
+ // node component list if necessary.
+ // Note: image reference in the texture mirror object
+ // is not updated yet, so it's ok to reference
+ // the mirror object for the old image reference
+
+ oldImage = texture.images[face][i];
+
+ // it is possible that oldImage.source == null because
+ // the mipmap could have been created by the library, and
+ // hence don't have source
+
+ if (oldImage != null) {
+ this.removeNodeComponent(oldImage);
+ }
+
+ // then add the new one to the list if it is byReference
+ if (images[i] != null ) {
+ this.addNodeComponent((images[i]).retained);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+
+ void processTextureUnitStateChanged(NodeComponentRetained nc,
+ GeometryAtom[] gaArr) {
+ RenderAtom ra = null;
+ TextureBin tb;
+ ShaderBin sb;
+ boolean mirrorSet = false;
+ boolean firstTextureBin = true;
+
+ for (int k = 0; k < gaArr.length; k++) {
+ ra = gaArr[k].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+
+ tb = ra.renderMolecule.textureBin;
+
+ if (firstTextureBin) {
+
+ for (int t = 0;
+ t < tb.texUnitState.length && !mirrorSet;
+ t++) {
+
+ if (tb.texUnitState[t] == null) {
+ continue;
+
+ } else if (tb.texUnitState[t].mirror == nc.mirror) {
+ mirrorSet = true;
+ firstTextureBin = false;
+ }
+ }
+ firstTextureBin = false;
+ }
+
+ if (mirrorSet) {
+
+ if (tb.soleUserCompDirty == 0) {
+ tbUpdateList.add(tb);
+ }
+
+ tb.soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TUS;
+
+ } else {
+ sb = ra.renderMolecule.textureBin.shaderBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertTextureBin(sb, ra);
+ }
+ }
+ }
+
+
+ /**
+ * This processes a rendering attribute change.
+ */
+
+ void processAttributeBinNodeComponentChanged(Object[] args) {
+ int i;
+ GeometryAtom[] gaArr = (GeometryAtom[])args[3];
+ int component = ((Integer)args[1]).intValue();
+ NodeComponentRetained nc = (NodeComponentRetained) args[0];
+
+ RenderAtom ra = null;
+ int start = -1;
+
+ // Get the first ra that is visible
+ for (i = 0; (i < gaArr.length && (start < 0)); i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+ else {
+ start = i;
+ }
+ }
+ if (start >= 0) {
+ // Force restucture, when changedFrequent is zero OR
+ // when it is changed to changedFrequent the first time OR
+ // when the ignoreVC changedFrequent flag is set for the first time
+ // when the last one is set for the first time, we need to force
+ // any separate dlist in RMs to go thru VA
+ boolean restructure = (nc.mirror.changedFrequent == 0 ||
+ ra.renderMolecule.textureBin.attributeBin.definingRenderingAttributes != nc.mirror);
+
+ if (component != RenderingAttributesRetained.VISIBLE) {
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+ if (restructure && !ra.renderMolecule.textureBin.attributeBin.soleUser) {
+ EnvironmentSet e= ra.renderMolecule.textureBin.environmentSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ /*
+ // If changed Frequent the first time,
+ // then the cached value
+ // may not be up-to-date since the nc is
+ // updated in updateObject
+ // So, add it to the list so that the cached value can
+ // be updated
+ if (nc.mirror.changedFrequent != 0) {
+ AttributeBin aBin = ra.renderMolecule.textureBin.attributeBin;
+ if ((aBin.onUpdateList & AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST) == 0 ) {
+ aBinUpdateList.add(aBin);
+ aBin.onUpdateList |= AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST;
+ }
+ }
+ */
+ }
+ else {
+ AttributeBin aBin = ra.renderMolecule.textureBin.attributeBin;
+ if ((aBin.onUpdateList & AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST) == 0 ) {
+ aBinUpdateList.add(aBin);
+ aBin.onUpdateList |= AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST;
+ }
+ }
+ }
+ }
+ else {
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+
+ if (ra== null || !ra.inRenderBin())
+ continue;
+ renderAtoms.remove(renderAtoms.indexOf(ra));
+ removeARenderAtom(ra);
+ }
+ }
+ }
+ }
+
+ /**
+ * This processes a shader component change.
+ */
+ void processShaderComponentChanged(Object[] args) {
+
+ // System.err.println("RenderBin : processShaderComponentChanged");
+
+ int component = ((Integer)args[1]).intValue();
+ int i;
+ GeometryAtom[] gaArr = (GeometryAtom[] )args[3];
+ RenderAtom ra = null;
+ /* TODO : JADA - Sole user logic is incomplete. Will disable for JavaOne */
+ // Note : args[0] may be a ShaderAppearanceRetained or ShaderAttributeSetRetained
+ //ShaderAppearanceRetained sApp = (ShaderAppearanceRetained) args[0];
+ int start = -1;
+
+
+ // Get the first ra that is visible
+ for (i = 0; (i < gaArr.length && (start < 0)); i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+ else {
+ start = i;
+ }
+ }
+ if (start >= 0) {
+
+ // Issue 471 - Don't check ATTRIBUTE_VALUE_UPDATE, there is no need
+ // to do anything to the shader bins when a value changes.
+ boolean spUpdate =
+ ((component & ShaderAppearanceRetained.SHADER_PROGRAM) != 0);
+ boolean sasUpdate =
+ (((component & ShaderAppearanceRetained.SHADER_ATTRIBUTE_SET) != 0) ||
+ ((component & ShaderConstants.ATTRIBUTE_SET_PUT) != 0) ||
+ ((component & ShaderConstants.ATTRIBUTE_SET_REMOVE) != 0) ||
+ ((component & ShaderConstants.ATTRIBUTE_SET_CLEAR) != 0));
+
+ if (spUpdate) {
+ /* TODO : JADA - Sole user logic is incomplete. Will disable for JavaOne */
+ //if (false && (sApp.mirror.changedFrequent & component) != 0) {
+ if(false) {
+ /*
+ System.err.println("RenderBin : Shader sole user (SHADER_PROGRAM)" +
+ ra.renderMolecule.textureBin.shaderBin);
+ */
+
+ ShaderBin sBin;
+
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ sBin = ra.renderMolecule.textureBin.shaderBin;
+
+ if (sBin.componentDirty == 0) {
+ sBinUpdateList.add(sBin);
+ sBin.componentDirty |= ShaderBin.SHADER_PROGRAM_DIRTY;
+ }
+ }
+ } else {
+ /*
+ System.err.println("RenderBin : not soleUser (SHADER_PROGRAM)" +
+ ra.renderMolecule.textureBin.shaderBin);
+ */
+
+ for (i = 0; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ AttributeBin attrBin = ra.renderMolecule.textureBin.attributeBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertShaderBin(attrBin, ra);
+ }
+ }
+ } else if (sasUpdate) {
+ /* TODO : JADA - Sole user logic is incomplete. Will disable for JavaOne */
+ //if (false && (sApp.mirror.changedFrequent & component) != 0) {
+ if(false) {
+ /*
+ System.err.println("RenderBin : sole user (SHADER_ATTRIBUTE_SET)" +
+ ra.renderMolecule.textureBin.shaderBin);
+ */
+
+ ShaderBin sBin;
+
+ for (i = 0; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+
+ sBin = ra.renderMolecule.textureBin.shaderBin;
+
+ if (sBin.componentDirty == 0) {
+ sBinUpdateList.add(sBin);
+ sBin.componentDirty |= ShaderBin.SHADER_ATTRIBUTE_SET_DIRTY;
+ }
+ }
+ } else {
+ /*
+ System.err.println("RenderBin :not soleUser (SHADER_ATTRIBUTE_SET) " +
+ ra.renderMolecule.textureBin.shaderBin);
+ */
+
+ for (i = 0; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ AttributeBin attrBin = ra.renderMolecule.textureBin.attributeBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertShaderBin(attrBin, ra);
+ }
+ }
+ }
+ }
+
+ }
+
+
+ void processFogChanged(Object[] args) {
+ FogRetained fog = (FogRetained)args[0];
+ EnvironmentSet e;
+ int component = ((Integer)args[1]).intValue();
+
+ if ((component &(FogRetained.SCOPE_CHANGED |
+ FogRetained.BOUNDS_CHANGED |
+ FogRetained.BOUNDINGLEAF_CHANGED)) != 0){
+ envDirty |= REEVALUATE_FOG;
+ }
+ else {
+ UnorderList list = fog.mirrorFog.environmentSets;
+ synchronized (list) {
+ EnvironmentSet envsets[] = (EnvironmentSet []) list.toArray(false);
+ int size = list.size();
+ for (int i = 0; i < size; i++) {
+ e = envsets[i];
+ e.canvasDirty |= Canvas3D.FOG_DIRTY;
+ if (!e.onUpdateList) {
+ objUpdateList.add(e);
+ e.onUpdateList = true;
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This routine get called whenever a component of the appearance
+ * changes
+ */
+ void processAppearanceChanged(Object[] args){
+ int component = ((Integer)args[1]).intValue();
+ int i;
+ GeometryAtom[] gaArr = (GeometryAtom[] )args[3];
+ RenderAtom ra = null;
+ AppearanceRetained app = (AppearanceRetained) args[0];
+ int TEXTURE_STATE_CHANGED =
+ AppearanceRetained.TEXTURE_UNIT_STATE |
+ AppearanceRetained.TEXTURE |
+ AppearanceRetained.TEXTURE_ATTR |
+ AppearanceRetained.TEXCOORD_GEN ;
+
+ int start = -1;
+
+ // Get the first ra that is visible
+ for (i = 0; (i < gaArr.length && (start < 0)); i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin()) {
+ continue;
+ }
+ else {
+ start = i;
+ }
+ }
+
+ if (start >= 0) {
+
+ if ((component & TEXTURE_STATE_CHANGED) != 0) {
+
+
+ if (((app.mirror.changedFrequent & TEXTURE_STATE_CHANGED) != 0) &&
+ ((ra.renderMolecule.textureBin.tbFlag &
+ TextureBin.SOLE_USER) != 0)) {
+
+/*
+System.err.println("renderbin. texture state changed tb sole user " +
+ ra.renderMolecule.textureBin + " tb.tbFlag= " +
+ ra.renderMolecule.textureBin.tbFlag);
+*/
+
+ TextureBin tb;
+
+
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ tb = ra.renderMolecule.textureBin;
+ if (tb.soleUserCompDirty == 0) {
+ tbUpdateList.add(tb);
+ }
+
+ // mark that the texture unit state ref is changed
+ // also mark that the TextureBin needs to reevaluate
+ // number of active textures
+ tb.soleUserCompDirty |=
+ TextureBin.SOLE_USER_DIRTY_REF;
+ }
+ } else {
+/*
+System.err.println("renderbin. texture state changed tb not sole user " +
+ ra.renderMolecule.textureBin + " tb.tbFlag= " +
+ ra.renderMolecule.textureBin.tbFlag);
+
+System.err.println("......tb.soleUser= " +
+ ((ra.renderMolecule.textureBin.tbFlag & TextureBin.SOLE_USER) != 0) +
+ " app.mirror.changedFrequent= " +
+ ((app.mirror.changedFrequent & TEXTURE_STATE_CHANGED) != 0));
+
+*/
+
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+ ShaderBin sb = ra.renderMolecule.textureBin.shaderBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertTextureBin(sb, ra);
+ }
+ }
+ } else if ((component & AppearanceRetained.RENDERING) != 0) {
+ boolean visible = ((Boolean)args[4]).booleanValue();
+ visGAIsDirty = true;
+ visQuery = true;
+ if (!visible) {
+ // remove all gaAttrs
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+
+ if (ra== null || !ra.inRenderBin())
+ continue;
+ renderAtoms.remove(renderAtoms.indexOf(ra));
+ removeARenderAtom(ra);
+ }
+ }
+ else {
+ if ((app.mirror.changedFrequent & component) != 0 &&
+ ra.renderMolecule.textureBin.attributeBin.soleUser) {
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ AttributeBin aBin = ra.renderMolecule.textureBin.attributeBin;
+ if ((aBin.onUpdateList & AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST) == 0 ) {
+ aBinUpdateList.add(aBin);
+ aBin.onUpdateList |= AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST;
+ }
+
+ }
+ }
+ else {
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+ EnvironmentSet e = ra.renderMolecule.textureBin.environmentSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+ }
+ }
+ }
+
+ else if ((component & (AppearanceRetained.COLOR |
+ AppearanceRetained.MATERIAL|
+ AppearanceRetained.TRANSPARENCY|
+ AppearanceRetained.POLYGON |
+ AppearanceRetained.LINE|
+ AppearanceRetained.POINT)) != 0) {
+ // System.err.println("AppearanceRetained.POINT = "+AppearanceRetained.POINT);
+ // System.err.println("(app.mirror.changedFrequent & component) != 0 "+app.mirror.changedFrequent );
+ // System.err.println("ra.renderMolecule.soleUser "+ra.renderMolecule.soleUser);
+ if ((app.mirror.changedFrequent & component) != 0 &&
+ ra.renderMolecule.soleUser) {
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ if ((ra.renderMolecule.soleUserCompDirty& RenderMolecule.ALL_DIRTY_BITS) == 0 ) {
+ rmUpdateList.add(ra.renderMolecule);
+ }
+ ra.renderMolecule.soleUserCompDirty |= component;
+
+ }
+
+ }
+ else {
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+ TextureBin tb = ra.renderMolecule.textureBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertRenderAtom(tb, ra);
+
+ }
+ }
+ }
+ } else {
+ // Nothing is visible
+ if ((component & AppearanceRetained.RENDERING) != 0) {
+ // Rendering attributes change
+ visGAIsDirty = true;
+ visQuery = true;
+ }
+ }
+ }
+
+
+
+
+ void processModelClipChanged(Object[] args) {
+ ModelClipRetained modelClip =
+ (ModelClipRetained)args[0];
+ EnvironmentSet e;
+ int component = ((Integer)args[1]).intValue();
+
+ if ((component & (ModelClipRetained.SCOPE_CHANGED |
+ ModelClipRetained.BOUNDS_CHANGED |
+ ModelClipRetained.BOUNDINGLEAF_CHANGED)) != 0){
+ envDirty |= REEVALUATE_MCLIP;
+
+ } else if ((component & (ModelClipRetained.ENABLE_CHANGED |
+ ModelClipRetained.ENABLES_CHANGED)) != 0) {
+ // need to render modelclip
+ if (!changedModelClips.contains(modelClip.mirrorModelClip))
+ changedModelClips.add(modelClip.mirrorModelClip);
+
+ // need to reevaluate envset
+ envDirty |= REEVALUATE_MCLIP;
+
+ } else {
+ UnorderList list = modelClip.mirrorModelClip.environmentSets;
+ synchronized (list) {
+ EnvironmentSet envsets[] = (EnvironmentSet []) list.toArray(false);
+ int size = list.size();
+ for (int i = 0; i < size; i++) {
+ e = envsets[i];
+ e.canvasDirty |= Canvas3D.MODELCLIP_DIRTY;
+ if (!e.onUpdateList) {
+ objUpdateList.add(e);
+ e.onUpdateList = true;
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This routine get called whenever a region of the boundingleaf
+ * changes
+ */
+ void processBoundingLeafChanged(Object[] args, long refTime){
+ // Notify all users of this bounding leaf, it may
+ // result in the re-evaluation of the lights/fogs/backgrounds
+ Object[] users = (Object[])(args[3]);
+ int i;
+
+ // XXXX: Handle other object affected by bounding leaf changes
+ for (i = 0; i < users.length; i++) {
+ LeafRetained leaf = (LeafRetained)users[i];
+ switch(leaf.nodeType) {
+ case NodeRetained.AMBIENTLIGHT:
+ case NodeRetained.POINTLIGHT:
+ case NodeRetained.SPOTLIGHT:
+ case NodeRetained.DIRECTIONALLIGHT:
+ if (universe.renderingEnvironmentStructure.isLightScopedToThisView(leaf, view))
+ envDirty |= REEVALUATE_LIGHTS;
+ break;
+ case NodeRetained.LINEARFOG:
+ case NodeRetained.EXPONENTIALFOG:
+ if (universe.renderingEnvironmentStructure.isFogScopedToThisView(leaf, view))
+ envDirty |= REEVALUATE_FOG;
+ break;
+ case NodeRetained.BACKGROUND:
+ if (universe.renderingEnvironmentStructure.isBgScopedToThisView(leaf, view))
+ reEvaluateBg = true;
+ break;
+ case NodeRetained.CLIP:
+ if (universe.renderingEnvironmentStructure.isClipScopedToThisView(leaf, view))
+ reEvaluateClip = true;
+ break;
+ case NodeRetained.MODELCLIP:
+ if (universe.renderingEnvironmentStructure.isMclipScopedToThisView(leaf, view))
+ envDirty |= REEVALUATE_MCLIP;
+ break;
+ case NodeRetained.ALTERNATEAPPEARANCE:
+ if (universe.renderingEnvironmentStructure.isAltAppScopedToThisView(leaf, view)) altAppearanceDirty = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+
+ void processOrientedShape3DChanged(Object[] gaArr) {
+
+ RenderAtom ra;
+ for (int i = 0; i < gaArr.length; i++) {
+ ra = ((GeometryAtom)gaArr[i]).getRenderAtom(view);
+ if (ra!= null && ra.inRenderBin() && !ra.inDirtyOrientedRAs()) {
+ dirtyOrientedRAs.add(ra);
+ ra.dirtyMask |= RenderAtom.IN_DIRTY_ORIENTED_RAs;
+ }
+ }
+ }
+
+
+ void processShapeChanged(Object[] args, long refTime) {
+
+ int component = ((Integer)args[1]).intValue();
+ int i;
+ RenderAtom ra;
+ EnvironmentSet e;
+ if ((component & Shape3DRetained.APPEARANCE_CHANGED) != 0) {
+ GeometryAtom[] gaArr = (GeometryAtom[])args[4];
+ if (gaArr.length > 0) {
+ if (!gaArr[0].source.appearanceOverrideEnable) {
+ for (i =0; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra == null || !ra.inRenderBin()) {
+ continue;
+ }
+ ra.app = ra.geometryAtom.source.appearance;
+ e = ra.renderMolecule.textureBin.environmentSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+ }
+ else {
+ for (i =0; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra == null || !ra.inRenderBin()) {
+ continue;
+ }
+ // if its using the alternate appearance continue ..
+ if (ra.app == ra.geometryAtom.source.otherAppearance)
+ continue;
+ ra.app = ra.geometryAtom.source.appearance;
+ e = ra.renderMolecule.textureBin.environmentSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+ }
+ }
+ }
+ else if ((component & Shape3DRetained.GEOMETRY_CHANGED) != 0) {
+ processDataChanged((Object[])args[2], (Object[])args[3], refTime);
+ }
+ else if ((component & Shape3DRetained.APPEARANCEOVERRIDE_CHANGED) != 0) {
+ AppearanceRetained app, saveApp = null;
+ Shape3DRetained saveShape = null;
+ GeometryAtom[] gaArr = (GeometryAtom[])args[4];
+ Object[] retVal;
+ for (i =0; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra == null || !ra.inRenderBin())
+ continue;
+ // Once shape could have many geometryAtoms, add the
+ // mirrorShape as a user of an appearance only once
+
+ if (saveShape != ra.geometryAtom.source) {
+ saveShape = ra.geometryAtom.source;
+ if (ra.geometryAtom.source.appearanceOverrideEnable) {
+ retVal =universe.renderingEnvironmentStructure.getInfluencingAppearance(ra, view);
+ saveShape.otherAppearance = (AppearanceRetained)retVal[1];
+ if (retVal[0] == Boolean.TRUE) {
+ app = (AppearanceRetained)retVal[1];
+ if (app != null) {
+ app.sgApp.addAMirrorUser(saveShape);
+ }
+ }
+ else {// use the default
+ app = ra.geometryAtom.source.appearance;
+ }
+ }
+ else {
+ // If it were using the alternate appearance
+ // remove itself as the user
+ if (ra.app == saveShape.otherAppearance &&
+ ra.app != null) {
+ ra.app.sgApp.removeAMirrorUser(saveShape);
+ }
+ app = ra.geometryAtom.source.appearance;
+ saveShape.otherAppearance = null;
+ }
+ saveApp = app;
+ }
+ else {
+ app = saveApp;
+ }
+ ra.app = app;
+ e = ra.renderMolecule.textureBin.environmentSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+ }
+
+ }
+
+
+ /**
+ * Process a Text3D data change. This involves removing all the
+ * old geometry atoms in the list, and the creating new ones.
+ */
+ void processDataChanged(Object[] oldGaList,
+ Object[] newGaList, long referenceTime) {
+ RenderAtom ra;
+ int i;
+ GeometryRetained geo;
+ GeometryAtom ga;
+
+ for (i=0; i<oldGaList.length; i++) {
+ ga = ((GeometryAtom)oldGaList[i]);
+
+ // Make sure that there is atleast one geo that is non-null
+ geo = null;
+ for (int k = 0; (k < ga.geometryArray.length && geo == null); k++) {
+ geo = ga.geometryArray[k];
+ }
+ if (geo == null)
+ continue;
+
+
+ ra = ga.getRenderAtom(view);
+
+ if (ra != null && ra.inRenderBin()) {
+ renderAtoms.remove(renderAtoms.indexOf(ra));
+ removeARenderAtom(ra);
+ }
+ }
+
+ visQuery = true;
+ visGAIsDirty = true;
+ }
+
+
+ void processMorphChanged(Object[] args, long refTime) {
+
+ int component = ((Integer)args[1]).intValue();
+ int i;
+ RenderAtom ra;
+ EnvironmentSet e;
+ if ((component & MorphRetained.APPEARANCE_CHANGED) != 0) {
+ GeometryAtom[] gaArr = (GeometryAtom[])args[4];
+ if (gaArr.length > 0) {
+ if (!gaArr[0].source.appearanceOverrideEnable) {
+ for (i =0; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra == null || !ra.inRenderBin()) {
+ continue;
+ }
+ ra.app = ra.geometryAtom.source.appearance;
+ e = ra.renderMolecule.textureBin.environmentSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+ }
+ else {
+ for (i =0; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra == null || !ra.inRenderBin())
+ continue;
+
+ // if its using the alternate appearance continue ..
+ if (ra.app == ra.geometryAtom.source.otherAppearance)
+ continue;
+ ra.app = ra.geometryAtom.source.appearance;
+ e = ra.renderMolecule.textureBin.environmentSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+ }
+ }
+ }
+ else if ((component & MorphRetained.APPEARANCEOVERRIDE_CHANGED) != 0) {
+ AppearanceRetained app, saveApp = null;
+ Shape3DRetained saveShape = null;
+ GeometryAtom[] gaArr = (GeometryAtom[])args[4];
+ Object[] retVal;
+
+ for (i =0; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra == null || !ra.inRenderBin())
+ continue;
+ // Once shape could have many geometryAtoms, add the
+ // mirrorShape as a user of an appearance only once
+
+ if (saveShape != ra.geometryAtom.source) {
+ saveShape = ra.geometryAtom.source;
+ if (ra.geometryAtom.source.appearanceOverrideEnable) {
+ retVal =universe.renderingEnvironmentStructure.getInfluencingAppearance(ra, view);
+ saveShape.otherAppearance = (AppearanceRetained)retVal[1];
+ if (retVal[0] == Boolean.TRUE) {
+ app = (AppearanceRetained)retVal[1];
+ if (app != null) {
+ app.sgApp.addAMirrorUser(saveShape);
+ }
+ }
+ else {// use the default
+ app = ra.geometryAtom.source.appearance;
+ }
+ }
+ else {
+ // If it were using the alternate appearance
+ // remove itself as the user
+ if (ra.app == saveShape.otherAppearance &&
+ ra.app != null) {
+ ra.app.sgApp.removeAMirrorUser(saveShape);
+ }
+ app = ra.geometryAtom.source.appearance;
+ saveShape.otherAppearance = null;
+ }
+ saveApp = app;
+ }
+ else {
+ app = saveApp;
+ }
+ ra.app = app;
+ e = ra.renderMolecule.textureBin.environmentSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+ }
+
+ }
+
+
+
+ /**
+ * This routine gets called whenever the position of the view platform
+ * has changed.
+ */
+ void updateViewPlatform(ViewPlatformRetained vp, float radius) {
+ ViewPlatform viewP = view.getViewPlatform();
+ if (viewP != null && (ViewPlatformRetained)viewP.retained == vp) {
+ vpcToVworld = vp.getCurrentLocalToVworld(null);
+ vpcToVworldDirty = true;
+ synchronized(vp) {
+ vp.vprDirtyMask |= View.VPR_VIEWPLATFORM_DIRTY;
+ }
+
+ // vp schedSphere is already set and transform in
+ // BehaviorStructure thread which is run before
+ // RenderBin using vp.updateActivationRadius()
+ vpSchedSphereInVworld = vp.schedSphere;
+ reEvaluateBg = true;
+ reEvaluateClip = true;
+ }
+
+ }
+
+
+
+ /**
+ * This routine removes the GeometryAtoms from RenderBin
+ */
+ void processGeometryAtomsChanged(Object[] gaArr) {
+ int i;
+ RenderAtom ra;
+
+ for (i = 0; i < gaArr.length; i++) {
+ ra = ((GeometryAtom)gaArr[i]).getRenderAtom(view);
+ if (ra != null && ra.inRenderBin()) {
+ renderAtoms.remove(renderAtoms.indexOf(ra));
+ removeARenderAtom(ra);
+ }
+ }
+ }
+
+ /**
+ * process Geometry changed, mark the display list
+ * in which renderMolecule is as dirty
+ */
+ void processGeometryChanged(Object[] args) {
+
+ Object[] gaList = (Object[]) args[0];
+
+ GeometryRetained g = (GeometryRetained)args[1];
+ GeometryAtom ga;
+
+ int i;
+
+ for (i = 0; i < gaList.length; i++) {
+ ga = ((GeometryAtom)gaList[i]);
+ RenderAtom renderAtom = ga.getRenderAtom(view);
+ if (renderAtom == null || !renderAtom.inRenderBin()) {
+ continue;
+ }
+
+
+ // Add the renderMolecule to the dirty list so that
+ // display list will be recreated
+ int j = 0;
+ for ( j = 0; j < renderAtom.rListInfo.length; j++) {
+ if (g == renderAtom.rListInfo[j].geometry())
+ break;
+ }
+ RenderAtomListInfo ra = renderAtom.rListInfo[j];
+ if ((ra.groupType & RenderAtom.DLIST) != 0)
+ addDirtyRenderMolecule(ra.renderAtom.renderMolecule);
+
+ if ((ra.groupType & RenderAtom.SEPARATE_DLIST_PER_RINFO) != 0) {
+ addDlistPerRinfo.add(ra);
+ }
+
+ if ((ra.groupType & RenderAtom.SEPARATE_DLIST_PER_GEO) != 0)
+ addGeometryDlist(ra);
+
+ // Raster send this message only for setImage()
+ if (g instanceof RasterRetained) {
+ Object[] objs = (Object[]) args[2];
+ Texture2DRetained oldTex = (Texture2DRetained) objs[0];
+ Texture2DRetained newTex = (Texture2DRetained) objs[1];
+
+ RasterRetained geo = (RasterRetained)ra.geometry();
+ if (oldTex != null) {
+ addTextureResourceFreeList(oldTex);
+ ImageComponentRetained oldImage = oldTex.images[0][0];
+ if (oldImage != null) {
+ removeNodeComponent(oldImage);
+ }
+ }
+ if (newTex != null) {
+ ImageComponentRetained newImage = newTex.images[0][0];
+ if (newImage != null) {
+ addNodeComponent(newImage);
+ }
+ }
+ }
+
+ }
+
+ }
+
+void addTextureBin(TextureBin tb) {
+ textureBinList.add(tb);
+}
+
+void removeTextureBin(TextureBin tb) {
+ textureBinList.remove(tb);
+}
+
+ void addDirtyRenderMolecule(RenderMolecule rm) {
+
+ if ((rm.onUpdateList & RenderMolecule.IN_DIRTY_RENDERMOLECULE_LIST) == 0) {
+ if (rm.onUpdateList == 0) {
+ objUpdateList.add(rm);
+ }
+ rm.onUpdateList |= RenderMolecule.IN_DIRTY_RENDERMOLECULE_LIST;
+ dirtyRenderMoleculeList.add(rm);
+ }
+ }
+
+
+
+ void removeDirtyRenderMolecule(RenderMolecule rm) {
+ if ((rm.onUpdateList & RenderMolecule.IN_DIRTY_RENDERMOLECULE_LIST) != 0) {
+ rm.onUpdateList &= ~RenderMolecule.IN_DIRTY_RENDERMOLECULE_LIST;
+ if (rm.onUpdateList == 0) {
+ objUpdateList.remove(rm);
+ }
+ dirtyRenderMoleculeList.remove(dirtyRenderMoleculeList.indexOf(rm));
+ }
+ }
+
+ void updateDirtyDisplayLists(Canvas3D cv,
+ ArrayList<RenderMolecule> rmList, ArrayList<Object[]> dlistPerRinfoList,
+ ArrayList<RenderAtomListInfo> raList, boolean useSharedCtx ) {
+ int size, i, bitMask;
+ Context ctx;
+ long timeStamp;
+
+ if (useSharedCtx) {
+ ctx = cv.screen.renderer.sharedCtx;
+ cv.makeCtxCurrent(ctx);
+ bitMask = cv.screen.renderer.rendererBit;
+ timeStamp = cv.screen.renderer.sharedCtxTimeStamp;
+ } else {
+ ctx = cv.ctx;
+ bitMask = cv.canvasBit;
+ timeStamp = cv.ctxTimeStamp;
+ }
+
+ size = rmList.size();
+
+ if (size > 0) {
+ for (i = size-1; i >= 0; i--) {
+ RenderMolecule rm = rmList.get(i);
+ rm.updateDisplayList(cv);
+ }
+ rmList.clear();
+ }
+
+ size = dlistPerRinfoList.size();
+
+ if (size > 0) {
+ for (i = size-1; i >= 0 ; i--) {
+ Object[] obj = dlistPerRinfoList.get(i);
+ dlistRenderMethod.buildDlistPerRinfo((RenderAtomListInfo)obj[0], (RenderMolecule)obj[1], cv);
+ }
+ dlistPerRinfoList.clear();
+ }
+
+ size = raList.size();
+ if (size > 0) {
+ RenderAtomListInfo ra;
+ GeometryArrayRetained geo;
+
+ for (i = size-1; i >= 0; i--) {
+ ra = raList.get(i);
+ geo = (GeometryArrayRetained) ra.geometry();
+ geo.resourceCreationMask &= ~bitMask;
+ }
+
+ for (i = size-1; i >= 0; i--) {
+ ra = raList.get(i);
+ geo = (GeometryArrayRetained) ra.geometry();
+ if ((geo.resourceCreationMask & bitMask) == 0) {
+ dlistRenderMethod.buildIndividualDisplayList(ra, cv, ctx);
+ geo.resourceCreationMask |= bitMask;
+ geo.setDlistTimeStamp(bitMask, timeStamp);
+ }
+ }
+ raList.clear();
+ }
+
+ if (useSharedCtx) {
+ cv.makeCtxCurrent(cv.ctx);
+ }
+ }
+
+ void removeRenderMolecule(RenderMolecule rm) {
+
+ if ((rm.primaryMoleculeType &(RenderMolecule.DLIST_MOLECULE|RenderMolecule.SEPARATE_DLIST_PER_RINFO_MOLECULE)) != 0)
+ renderMoleculeList.remove(rm);
+ }
+
+ void updateAllRenderMolecule(Canvas3D cv) {
+ int i;
+ int size = renderMoleculeList.size();
+
+ if (size > 0) {
+ RenderMolecule[] rmArr = (RenderMolecule[])
+ renderMoleculeList.toArray(false);
+ for (i = size-1 ; i >= 0; i--) {
+ rmArr[i].updateAllPrimaryDisplayLists(cv);
+ }
+ }
+
+ size = sharedDList.size();
+ if (size > 0) {
+ RenderAtomListInfo ra;
+ GeometryArrayRetained geo;
+ RenderAtomListInfo arr[] = new RenderAtomListInfo[size];
+ arr = sharedDList.toArray(arr);
+ int bitMask = cv.canvasBit;
+
+ // We need two passes to avoid extra buildDisplayList
+ // when geo are the same. The first pass clean the
+ // rendererBit. Note that we can't rely on
+ // resourceCreation since it is a force recreate.
+
+ for (i = size-1; i >= 0; i--) {
+ geo = (GeometryArrayRetained) arr[i].geometry();
+ geo.resourceCreationMask &= ~bitMask;
+ }
+
+ for (i = size-1; i >= 0; i--) {
+ ra = arr[i];
+ geo = (GeometryArrayRetained) ra.geometry();
+ if ((geo.resourceCreationMask & bitMask) == 0) {
+ dlistRenderMethod.buildIndividualDisplayList(ra, cv, cv.ctx);
+ geo.resourceCreationMask |= bitMask;
+ geo.setDlistTimeStamp(bitMask, cv.ctxTimeStamp);
+ }
+ }
+ }
+ }
+
+ /**
+ * This method is called to update all renderMolecule
+ * for a shared context of a renderer
+ */
+ void updateAllRenderMolecule(Renderer rdr, Canvas3D cv) {
+ int i;
+ boolean setCtx = false;
+ GeometryArrayRetained geo;
+ int size = renderMoleculeList.size();
+
+ if (size > 0) {
+ RenderMolecule[] rmArr = (RenderMolecule[])
+ renderMoleculeList.toArray(false);
+
+ cv.makeCtxCurrent(rdr.sharedCtx);
+ setCtx = true;
+ for (i = size-1 ; i >= 0; i--) {
+ rmArr[i].updateAllPrimaryDisplayLists(cv);
+ }
+ }
+
+ size = sharedDList.size();
+ if (size > 0) {
+ RenderAtomListInfo arr[] = new RenderAtomListInfo[size];
+ arr = sharedDList.toArray(arr);
+ RenderAtomListInfo ra;
+
+ if (!setCtx) {
+ cv.makeCtxCurrent(rdr.sharedCtx);
+ setCtx = true;
+ }
+
+ // We need two passes to avoid extra buildDisplayList
+ // when geo are the same. The first pass clean the
+ // rendererBit.
+ int bitMask = cv.screen.renderer.rendererBit;
+ long timeStamp = cv.screen.renderer.sharedCtxTimeStamp;
+
+ for (i = size-1; i >= 0; i--) {
+ geo = (GeometryArrayRetained) arr[i].geometry();
+ geo.resourceCreationMask &= ~bitMask;
+ }
+
+ for (i = size-1; i >= 0; i--) {
+ ra = arr[i];
+ geo = (GeometryArrayRetained) ra.geometry();
+ if ((geo.resourceCreationMask & bitMask) == 0) {
+ dlistRenderMethod.buildIndividualDisplayList(ra, cv,
+ rdr.sharedCtx);
+ geo.resourceCreationMask |= bitMask;
+ geo.setDlistTimeStamp(bitMask, timeStamp);
+ }
+ }
+ }
+ if (setCtx) {
+ cv.makeCtxCurrent(cv.ctx);
+ }
+ }
+
+ private void processText3DTransformChanged(Object[] list,
+ Object[] transforms,
+ long referenceTime) {
+ int i, j, numShapes;
+ GeometryAtom ga;
+ RenderMolecule rm;
+ RenderAtom ra;
+
+ if (transforms.length != 0) {
+ numShapes = list.length;
+ for (i=0; i<numShapes; i++) {
+
+ ga = (GeometryAtom)list[i];
+ ra = ga.getRenderAtom(view);
+ if (ra == null || !ra.inRenderBin()) {
+ continue;
+ }
+ /*
+ System.err.println("numShapes is " + numShapes +
+ " transforms.length is " + transforms.length);
+ */
+ for (j=0; j<transforms.length; j++) {
+
+ ga.lastLocalTransformArray[j] = (Transform3D)transforms[j];
+
+
+
+
+ for(int k = 0; k < ra.rListInfo.length; k++) {
+ if (ra.rListInfo[k].localToVworld == null) {
+ ra.rListInfo[k].localToVworld = new Transform3D();
+ }
+ }
+
+ if (ra.isOriented() && !ra.inDirtyOrientedRAs()) {
+ dirtyOrientedRAs.add(ra);
+ ra.dirtyMask |= RenderAtom.IN_DIRTY_ORIENTED_RAs;
+ } else if (!ra.onUpdateList()) {
+ ra.dirtyMask |= RenderAtom.ON_UPDATELIST;
+ objUpdateList.add(ra);
+ }
+ }
+ }
+ }
+ }
+
+
+private void processOrderedGroupRemoved(J3dMessage m) {
+ int n;
+ Object[] ogList = (Object[])m.args[0];
+ Object[] ogChildIdList = (Object[])m.args[1];
+
+ /*
+ System.err.println("RB : processOrderedGroupRemoved message " + m);
+ System.err.println("RB : processOrderedGroupRemoved - ogList.length is " +
+ ogList.length);
+ System.err.println("RB : processOrderedGroupRemoved - obList " +
+ obList);
+ */
+ for (n = 0; n < ogList.length; n++) {
+ OrderedGroupRetained og = (OrderedGroupRetained)ogList[n];
+ OrderedBin ob = og.getOrderedBin(view.viewIndex);
+ if (ob == null)
+ continue;
+
+ // System.err.println("Removed, index = "+index+" ob = "+ob);
+ // Add at the end of the childInfo, for remove we don't care about
+ // the childId
+ int index = ((Integer)ogChildIdList[n]).intValue();
+ OrderedChildInfo cinfo = new OrderedChildInfo(OrderedChildInfo.REMOVE, index, -1, null);
+ ob.addChildInfo(cinfo);
+
+ if (!ob.onUpdateList) {
+ obList.add(ob);
+ ob.onUpdateList = true;
+ }
+ }
+}
+
+private void processOrderedGroupInserted(J3dMessage m) {
+ Object[] ogList = (Object[])m.args[0];
+ Object[] ogChildIdList = (Object[])m.args[1];
+ Object[] ogOrderedIdList = (Object[])m.args[2];
+
+ // System.err.println("Inserted OG, index = "+index+" orderedId = "+orderedId+" og = "+og+" og.orderedBin = "+og.orderedBin);
+ // System.err.println("Inserted OG, orderedId = "+orderedId);
+ // System.err.println("Inserted, index = "+index+" oid = "+orderedId+" ob = "+ob);
+
+ if (ogList == null)
+ return;
+
+ for (int n = 0; n < ogList.length; n++) {
+ OrderedGroupRetained og = (OrderedGroupRetained)ogList[n];
+ OrderedBin ob = og.getOrderedBin(view.viewIndex);
+ if (ob == null)
+ continue;
+
+ // Add at the end of the childInfo
+ int index = ((Integer)ogChildIdList[n]).intValue();
+ int orderedId = ((Integer)ogOrderedIdList[n]).intValue();
+ OrderedChildInfo cinfo = new OrderedChildInfo(OrderedChildInfo.ADD, index, orderedId, null);
+ ob.addChildInfo(cinfo);
+
+ if (!ob.onUpdateList) {
+ obList.add(ob);
+ ob.onUpdateList = true;
+ }
+ }
+}
+
+ private void processTransformChanged(long referenceTime) {
+ int i, j, n;
+ RenderMolecule rm;
+ RenderAtom ra;
+ LightRetained[] lights;
+ FogRetained fog;
+ ModelClipRetained modelClip;
+ AppearanceRetained app;
+ Object[] list, nodesArr;
+ UnorderList arrList;
+ int size;
+
+ targets = universe.transformStructure.getTargetList();
+
+ // process geometry atoms
+ arrList = targets.targetList[Targets.GEO_TARGETS];
+ if (arrList != null) {
+ Object[] retVal;
+ size = arrList.size();
+ nodesArr = arrList.toArray(false);
+
+ //System.err.println("GS:");
+ for (n = 0; n < size; n++) {
+ list = (Object[])nodesArr[n];
+
+ for (i=0; i<list.length; i++) {
+
+ GeometryAtom ga = (GeometryAtom) list[i];
+ //System.err.println(" ga " + ga);
+ ra = ga.getRenderAtom(view);
+ if (ra == null || !ra.inRenderBin())
+ continue;
+
+ rm = ra.renderMolecule;
+
+ if (rm != null && rm.renderBin == this) {
+
+ if (ga.source.inBackgroundGroup && (rm.onUpdateList &
+ RenderMolecule.UPDATE_BACKGROUND_TRANSFORM) == 0) {
+ if (rm.onUpdateList == 0) {
+ objUpdateList.add(rm);
+ }
+ rm.onUpdateList |=
+ RenderMolecule.UPDATE_BACKGROUND_TRANSFORM;
+ }
+
+ lights = universe.renderingEnvironmentStructure.
+ getInfluencingLights(ra, view);
+ fog = universe.renderingEnvironmentStructure.
+ getInfluencingFog(ra, view);
+ modelClip = universe.renderingEnvironmentStructure.
+ getInfluencingModelClip(ra, view);
+
+ if (ra.geometryAtom.source.appearanceOverrideEnable) {
+ retVal = universe.renderingEnvironmentStructure.getInfluencingAppearance(ra, view);
+ if (retVal[0] == Boolean.TRUE) {
+ app = (AppearanceRetained)retVal[1];
+ }
+ else {
+ app = ra.geometryAtom.source.appearance;
+ }
+ }
+ else {
+ app = ra.geometryAtom.source.appearance;
+ }
+ // XXXX: Should we do a more extensive equals app?
+ if (ra.envSet.equals(ra, lights, fog, modelClip) &&
+ app == ra.app) {
+
+ if (ra.hasSeparateLocaleVwcBounds()
+ && !ra.onLocaleVwcBoundsUpdateList()) {
+ ra.dirtyMask |= RenderAtom.ON_LOCALE_VWC_BOUNDS_UPDATELIST;
+ raLocaleVwcBoundsUpdateList.add(ra);
+ }
+
+ // If the locale are different and the xform has changed
+ // then we need to translate the rm's localToVworld by
+ // the locale differences
+ if (locale != ga.source.locale) {
+ if (rm.onUpdateList == 0) {
+ objUpdateList.add(rm);
+ }
+ rm.onUpdateList |= RenderMolecule.LOCALE_TRANSLATION;
+
+ }
+ if ((rm.primaryMoleculeType & RenderMolecule.DLIST_MOLECULE) != 0) {
+ if (rm.onUpdateList == 0) {
+ objUpdateList.add(rm);
+ }
+ rm.onUpdateList |= RenderMolecule.BOUNDS_RECOMPUTE_UPDATE;
+
+ }
+ // Note that the rm LOCALE Translation update should ocuur
+ // Before the ra is added to the object update list
+ // It is a Text3D Molecule
+ else if ((rm.primaryMoleculeType & RenderMolecule.TEXT3D_MOLECULE) != 0){
+
+ if (!ra.onUpdateList()) {
+ ra.dirtyMask |= RenderAtom.ON_UPDATELIST;
+ objUpdateList.add(ra);
+ }
+ }
+ if (ra.isOriented() && !ra.inDirtyOrientedRAs()) {
+ dirtyOrientedRAs.add(ra);
+ ra.dirtyMask |= RenderAtom.IN_DIRTY_ORIENTED_RAs;
+
+ }
+ // If not opaque or in OG or is not a transparent bg geometry
+ // and transp sort mode is sort_geometry, then ..
+ if (!ra.renderMolecule.isOpaqueOrInOG && ra.geometryAtom.source.geometryBackground == null && transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY && !ra.inDepthSortList()) {
+ // Do the updating of the centroid
+ // when the render is running
+ ra.geometryAtom.updateCentroid();
+ // System.err.println("========> adding to the dirty list .., transpSortMode = "+transpSortMode);
+ if (dirtyDepthSortRenderAtom.add(ra)) {
+ numDirtyTinfo += ra.rListInfo.length;
+ }
+ /*
+ else {
+ System.err.println("processTransformChanged: attempt to add RenderAtom already in dirty list");
+ }
+ */
+ ra.dirtyMask |= RenderAtom.IN_SORTED_POS_DIRTY_TRANSP_LIST;
+
+ }
+ continue;
+ }
+ // If the appearance has changed ..
+ if (ra.app != app) {
+ if (ra.geometryAtom.source.appearanceOverrideEnable) {
+ // If it was using the alternate appearance, then ..
+ if (ra.app == ra.geometryAtom.source.otherAppearance) {
+ if (ra.app != null) {
+ // remove this mirror shape from the user list
+ ra.geometryAtom.source.otherAppearance.sgApp.removeAMirrorUser(ra.geometryAtom.source);
+ ra.geometryAtom.source.otherAppearance = null;
+ }
+ }
+ // if we are using the alternate app, add the mirror
+ // shape to the userlist
+ if (app != ra.geometryAtom.source.appearance) {
+ // Second check is needed to prevent,
+ // the mirror shape
+ // that has multiple ra's to be added more than
+ // once
+ if (app != null && app != ra.geometryAtom.source.otherAppearance) {
+ app.sgApp.addAMirrorUser(ra.geometryAtom.source);
+ ra.geometryAtom.source.otherAppearance = app;
+ }
+ }
+
+ }
+ }
+
+
+ // Remove the renderAtom from the current
+ // renderMolecule and reinsert
+ getNewEnvironment(ra, lights, fog, modelClip, app);
+ }
+ }
+ }
+ }
+
+ // process misc environment nodes
+ arrList = targets.targetList[Targets.ENV_TARGETS];
+ if (arrList != null) {
+ size = arrList.size();
+ nodesArr = arrList.toArray(false);
+ for (n = 0; n < size; n++) {
+ list = (Object[])nodesArr[n];
+ for (i=0; i<list.length; i++) {
+
+ if (list[i] instanceof LightRetained && universe.renderingEnvironmentStructure.isLightScopedToThisView(list[i], view)) {
+ if (!changedLts.contains(list[i]) )
+ changedLts.add((LightRetained)list[i]);
+ envDirty |= REEVALUATE_LIGHTS; // mark the canvas as dirty as well
+ }
+ else if (list[i] instanceof ModelClipRetained && universe.renderingEnvironmentStructure.isMclipScopedToThisView(list[i], view)) {
+ if (!changedModelClips.contains(list[i]))
+ changedModelClips.add((ModelClipRetained)list[i]);
+ envDirty |= REEVALUATE_MCLIP; // mark the canvas as dirty as well
+ }
+ else if (list[i] instanceof FogRetained && universe.renderingEnvironmentStructure.isFogScopedToThisView(list[i], view)) {
+ if (!changedFogs.contains(list[i]))
+ changedFogs.add((FogRetained)list[i]);
+ envDirty |= REEVALUATE_FOG; // mark the canvas as dirty as well
+ }
+ else if (list[i] instanceof AlternateAppearanceRetained && universe.renderingEnvironmentStructure.isAltAppScopedToThisView(list[i], view)) {
+ altAppearanceDirty = true;
+ }
+ }
+ }
+ }
+
+ // process ViewPlatform nodes
+ arrList = targets.targetList[Targets.VPF_TARGETS];
+ if (arrList != null) {
+ size = arrList.size();
+ nodesArr = arrList.toArray(false);
+ for (n = 0; n < size; n++) {
+ list = (Object[])nodesArr[n];
+ for (i=0; i<list.length; i++) {
+ float radius;
+ synchronized(list[i]) {
+ radius = (float)((ViewPlatformRetained)list[i]).sphere.radius;
+ }
+ updateViewPlatform((ViewPlatformRetained)list[i], radius);
+ }
+ }
+ }
+
+ targets = null;
+
+ blUsers = universe.transformStructure.getBlUsers();
+ if (blUsers != null) {
+ size = blUsers.size();
+ for (j = 0; j < size; j++) {
+ LeafRetained mLeaf = (LeafRetained)blUsers.get(j);
+ if (mLeaf instanceof LightRetained && universe.renderingEnvironmentStructure.isLightScopedToThisView(mLeaf, view)) {
+ envDirty |= REEVALUATE_LIGHTS;
+ }
+ else if (mLeaf instanceof FogRetained && universe.renderingEnvironmentStructure.isFogScopedToThisView(mLeaf, view)) {
+ envDirty |= REEVALUATE_FOG;
+ }
+ else if (mLeaf instanceof ModelClipRetained && universe.renderingEnvironmentStructure.isMclipScopedToThisView(mLeaf, view)) {
+ envDirty |= REEVALUATE_MCLIP;
+ }
+ else if (mLeaf instanceof AlternateAppearanceRetained && universe.renderingEnvironmentStructure.isAltAppScopedToThisView(mLeaf, view)) {
+ altAppearanceDirty = true;
+ }
+ }
+ blUsers = null;
+ }
+
+ visQuery = true;
+
+ }
+
+
+
+ /**
+ * This processes a LIGHT change.
+ */
+ private void processLightChanged() {
+ int i, j, k, n;
+ LightRetained lt;
+ EnvironmentSet e;
+ Object[] args;
+ LightRetained[] mLts;
+ int component;
+ int lightSize = lightMessageList.size();
+
+ for (n = 0; n < lightSize; n++) {
+ J3dMessage msg = lightMessageList.get(n);
+ args = msg.args;
+ mLts = (LightRetained[])args[3];
+ component = ((Integer)args[1]).intValue();
+ lt = (LightRetained) args[0];
+
+
+ if ((component &(LightRetained.SCOPE_CHANGED |
+ LightRetained.BOUNDS_CHANGED |
+ LightRetained.BOUNDINGLEAF_CHANGED)) != 0){
+ envDirty |= REEVALUATE_LIGHTS;
+ component &= ~(LightRetained.SCOPE_CHANGED |
+ LightRetained.BOUNDS_CHANGED |
+ LightRetained.BOUNDINGLEAF_CHANGED);
+ }
+ // This is a light that is not a part of any
+ // environment set, first check if it is enabled
+ // if it is then reEvaluate all renderAtoms in the
+ // scene, otherwise do nothing
+ if (component != 0) {
+ if (lt.nodeType == LightRetained.AMBIENTLIGHT) {
+ UnorderList list;
+ EnvironmentSet envsets[];
+ for (i = 0; i < mLts.length; i++) {
+ LightRetained lti = mLts[i];
+ list = lti.environmentSets;
+ synchronized (list) {
+ int size = list.size();
+ if (size > 0) {
+ envsets = (EnvironmentSet []) list.toArray(false);
+ for (j = 0; j < size; j++) {
+ e = envsets[j];
+ e.canvasDirty |= Canvas3D.AMBIENTLIGHT_DIRTY;
+ if (!e.onUpdateList) {
+ objUpdateList.add(e);
+ e.onUpdateList = true;
+ }
+ }
+ } else {
+ if ((component & LightRetained.ENABLE_CHANGED) != 0) {
+ boolean value = lti.lightOn;
+ if (value) {
+ if (!changedLts.contains(lti))
+ changedLts.add(lti);
+ envDirty |= REEVALUATE_LIGHTS;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < mLts.length; i++) {
+ LightRetained lti = mLts[i];
+ if ((component & LightRetained.ENABLE_CHANGED) != 0) {
+ boolean value = ((Boolean)args[4]).booleanValue();
+ if (value) {
+ if (!changedLts.contains(lti))
+ changedLts.add(lti);
+
+ envDirty |= REEVALUATE_LIGHTS;
+ }
+ }
+ UnorderList list = lti.environmentSets;
+ EnvironmentSet envsets[];
+ synchronized (list) {
+ int size = list.size();
+ int lsize;
+ if (size > 0) {
+ envsets = (EnvironmentSet []) list.toArray(false);
+ if ((component & LightRetained.ENABLE_CHANGED) != 0) {
+ boolean value = ((Boolean)args[4]).booleanValue();
+ for (j = 0; j <size; j++) {
+ e = envsets[j];
+ lsize = e.lights.size();
+ for (k = 0; k < lsize; k++) {
+ if (e.lights.get(k) == lti) {
+ if (value == true)
+ e.enableMaskCache |= (1 << e.ltPos[k]);
+ else
+ e.enableMaskCache &= ~(1 << e.ltPos[k]);
+ break;
+ }
+ }
+ e.canvasDirty |= Canvas3D.LIGHTENABLES_DIRTY;
+ if (!e.onUpdateList) {
+ objUpdateList.add(e);
+ e.onUpdateList = true;
+ }
+ }
+ } else {
+ for (j = 0; j < size; j++) {
+ e = envsets[j];
+ lsize = e.lights.size();
+ for (k = 0; k < lsize; k++) {
+ if (e.lights.get(k) == lti) {
+ e.lightBin.canvasDirty |= Canvas3D.LIGHTBIN_DIRTY;
+ e.lightBin.lightDirtyMaskCache |= (1 << e.ltPos[k]);
+ if (!e.lightBin.onUpdateList) {
+ e.lightBin.onUpdateList = true;
+ objUpdateList.add(e.lightBin);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ } // end sync.
+ }
+ }
+ }
+ msg.decRefcount();
+ }
+
+ }
+
+ void processGeometryAtom(GeometryAtom ga, long referenceTime) {
+ RenderAtom renderAtom;
+ RenderMolecule rm;
+
+ // System.err.println("+");
+
+
+ GeometryRetained geo = null;
+ for (int k = 0; (k < ga.geometryArray.length && geo == null); k++) {
+ geo = ga.geometryArray[k];
+ }
+ if (geo == null)
+ return;
+
+
+ renderAtom = ga.getRenderAtom(view);
+
+ if (renderAtom != null) {
+ renderAtom.lastVisibleTime = referenceTime;
+ }
+
+ if (renderAtom == null || renderAtom.inRenderBin()) {
+ return;
+ }
+
+
+ // If the geometry is all null , don't insert
+ // Make sure that there is atleast one geo that is non-null
+
+ if (renderAtom.geometryAtom.source.viewList != null) {
+ if (renderAtom.geometryAtom.source.viewList.contains(view)) {
+ // System.err.println("Inserting RenderAtom, ra = "+renderAtom);
+ // System.err.println("ga = "+renderAtom.geometryAtom+" renderAtom.geometryAtom.source.viewList = "+renderAtom.geometryAtom.source.viewList);
+ rm = insertRenderAtom(renderAtom);
+ }
+ }
+ // No view specific scpoing
+ else {
+ rm = insertRenderAtom(renderAtom);
+ }
+
+ }
+
+
+
+ private void processBgGeometryAtoms(GeometryAtom[] nodes, long referenceTime) {
+ int i;
+ GeometryAtom ga;
+ RenderAtom renderAtom;
+ RenderAtomListInfo ra;
+ GeometryRetained geo;
+
+ for (i=0; i<nodes.length; i++) {
+ ga = nodes[i];
+
+ // Make sure that there is atleast one geo that is non-null
+ geo = null;
+ for (int k = 0; (k < ga.geometryArray.length && geo == null); k++) {
+ geo = ga.geometryArray[k];
+ }
+ if (geo == null)
+ continue;
+
+
+ renderAtom = ga.getRenderAtom(view);
+ if (renderAtom == null)
+ return;
+
+ renderAtom.lastVisibleTime = referenceTime;
+ if (renderAtom.inRenderBin()) {
+ continue;
+ }
+
+
+ // This means that the renderAtom was not visible in the last
+ // frame ,so , no contention with the renderer ...
+ RenderMolecule rm = insertRenderAtom(renderAtom);
+ }
+
+ }
+
+ /**
+ * This method looks through the list of RenderAtoms to see if
+ * compaction is needed.
+ */
+ private void checkForCompaction() {
+ int i, numRas;
+ int numDead = 0;
+ int numAlive = 0;
+ RenderAtom ra;
+
+ if (!VirtualUniverse.mc.doCompaction) {
+ return;
+ }
+
+ numRas = renderAtoms.size();
+ for (i=0; i<numRas; i++) {
+ ra = renderAtoms.get(i);
+ // If the renderatom has not been visible for "notVisibleCount" then
+ // add it to the deadlist
+ if (ra.lastVisibleTime < removeCutoffTime) {
+ numDead++;
+ }
+
+ }
+ numAlive = numRas - numDead;
+ if (numAlive*2 < numDead) {
+ compact();
+ }
+ }
+
+ /**
+ * This sets the number of frames to render before changing the
+ * removeCutoffTime
+ */
+ void setFrameCountCutoff(int cutoff) {
+ frameCountCutoff = cutoff;
+ }
+
+ /**
+ * This method stores the timestamp of the frame frameCountCuttoff
+ * frames ago. It also does compaction if it is needed.
+ */
+ void compact() {
+ for (int i=0; i < renderAtoms.size();) {
+ RenderAtom ra = renderAtoms.get(i);
+ if (ra.lastVisibleTime < removeCutoffTime) {
+ renderAtoms.remove(i);
+ removeARenderAtom(ra);
+ continue;
+ }
+ i++;
+ }
+
+ }
+
+ private void reEvaluateAlternateAppearance() {
+ AppearanceRetained app;
+ EnvironmentSet e;
+ Object[] retVal;
+ int sz = renderAtoms.size();
+
+ for (int n = 0; n < sz; n++) {
+ RenderAtom ra = renderAtoms.get(n);
+ if (!ra.inRenderBin() || !ra.geometryAtom.source.appearanceOverrideEnable)
+ continue;
+
+ retVal = universe.renderingEnvironmentStructure.getInfluencingAppearance(ra, view);
+
+ if (retVal[0] == Boolean.TRUE) {
+ app = (AppearanceRetained)retVal[1];
+ }
+ else {
+ app = ra.geometryAtom.source.appearance;
+ }
+
+ if (app == ra.app)
+ continue;
+
+ if (ra.geometryAtom.source.otherAppearance != app) {
+ if (ra.geometryAtom.source.otherAppearance != null) {
+ ra.geometryAtom.source.otherAppearance.sgApp.removeAMirrorUser(ra.geometryAtom.source);
+ }
+ if (app != ra.geometryAtom.source.appearance) {
+ if (app != null) {
+ app.sgApp.addAMirrorUser(ra.geometryAtom.source);
+ }
+ ra.geometryAtom.source.otherAppearance = app;
+ }
+ else {
+ ra.geometryAtom.source.otherAppearance = null;
+ }
+ }
+ ra.app = app;
+ e = ra.envSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+
+ }
+
+ private void reEvaluateAllRenderAtoms(boolean altAppDirty) {
+
+ int sz = renderAtoms.size();
+
+ for (int n = 0; n < sz; n++) {
+ LightRetained[] lights;
+ FogRetained newfog;
+ ModelClipRetained newModelClip;
+ AppearanceRetained app;
+ RenderAtom ra = renderAtoms.get(n);
+ Object[] retVal;
+
+ if (!ra.inRenderBin())
+ continue;
+
+ lights = universe.renderingEnvironmentStructure.getInfluencingLights(ra, view);
+ newfog = universe.renderingEnvironmentStructure.getInfluencingFog(ra, view);
+ newModelClip = universe.renderingEnvironmentStructure.getInfluencingModelClip(ra, view);
+
+
+ if (altAppDirty) {
+ if (ra.geometryAtom.source.appearanceOverrideEnable) {
+ retVal = universe.renderingEnvironmentStructure.getInfluencingAppearance(ra, view);
+ if (retVal[0] == Boolean.TRUE) {
+ app = (AppearanceRetained)retVal[1];
+ }
+ else {
+ app = ra.geometryAtom.source.appearance;
+ }
+
+ }
+ else {
+ app = ra.geometryAtom.source.appearance;
+ }
+ }
+ else {
+ app = ra.app;
+ }
+
+ // If the lights/fog/model_clip of the render atom is the same
+ // as the old set of lights/fog/model_clip, then move on to the
+ // next renderAtom
+ // XXXX: Should app test for equivalent?
+ if (ra.envSet.equals(ra, lights, newfog, newModelClip) &&
+ app == ra.app)
+ continue;
+
+ if (altAppDirty && ra.geometryAtom.source.appearanceOverrideEnable) {
+ if (app != ra.app) {
+ if (ra.geometryAtom.source.otherAppearance != app) {
+ if (ra.geometryAtom.source.otherAppearance != null)
+ ra.geometryAtom.source.otherAppearance.sgApp.removeAMirrorUser(ra.geometryAtom.source);
+ // If it is not the default appearance
+ if (app != ra.geometryAtom.source.appearance) {
+ if (app != null) {
+ app.sgApp.addAMirrorUser(ra.geometryAtom.source);
+ }
+ ra.geometryAtom.source.otherAppearance = app;
+ }
+ else {
+ ra.geometryAtom.source.otherAppearance = null;
+ }
+ }
+ }
+ }
+ getNewEnvironment(ra, lights, newfog, newModelClip, app);
+
+ }
+ }
+
+
+
+ private void getNewEnvironment(RenderAtom ra, LightRetained[] lights,
+ FogRetained fog, ModelClipRetained modelClip,
+ AppearanceRetained app) {
+
+ LightBin currentBin, lightBin;
+ EnvironmentSet currentEnvSet, newBin;
+ EnvironmentSet eNew = null;
+ LightBin addBin;
+ OrderedCollection oc = null;
+ int i;
+
+ // Remove this renderAtom from this render Molecule
+ ra.renderMolecule.removeRenderAtom(ra);
+
+ eNew = null;
+ if (ra.geometryAtom.source.geometryBackground == null) {
+ if (ra.geometryAtom.source.orderedPath != null) {
+ oc = findOrderedCollection(ra.geometryAtom, false);
+ currentBin = oc.nextFrameLightBin;
+ addBin = oc.addLightBins;
+ } else {
+ addBin = addOpaqueBin;
+ currentBin= opaqueBin;
+ }
+ } else {
+ if (ra.geometryAtom.source.orderedPath != null) {
+ oc = findOrderedCollection(ra.geometryAtom, true);
+ currentBin = oc.nextFrameLightBin;
+ addBin = oc.addLightBins;
+ } else {
+ addBin = bgAddOpaqueBin;
+ currentBin= bgOpaqueBin;
+ }
+ }
+ lightBin = currentBin;
+
+ while (currentBin != null && eNew == null) {
+
+ // this test is always true for non-backgroundGeo bins
+ if (currentBin.geometryBackground ==
+ ra.geometryAtom.source.geometryBackground) {
+
+ currentEnvSet = currentBin.environmentSetList;
+ while (currentEnvSet != null) {
+ if (currentEnvSet.equals(ra, lights, fog, modelClip)) {
+ eNew = currentEnvSet;
+ break;
+ }
+ currentEnvSet = currentEnvSet.next;
+ }
+ // If envSet set is not found
+ // Check the "to-be-added" list of environmentSets for a match
+ if (eNew == null) {
+ int size = currentBin.insertEnvSet.size();
+ for (i = 0; i < size; i++) {
+ newBin = currentBin.insertEnvSet.get(i);
+ if (newBin.equals(ra, lights, fog, modelClip)) {
+ eNew = newBin;
+ break;
+ }
+ }
+ }
+ }
+ currentBin = currentBin.next;
+ }
+
+ // Now check the to-be added lightbins
+ if (eNew == null) {
+ currentBin = addBin;
+ while (currentBin != null) {
+
+ // this test is always true for non-backgroundGeo bins
+ if (currentBin.geometryBackground ==
+ ra.geometryAtom.source.geometryBackground) {
+
+ // Check the "to-be-added" list of environmentSets for a match
+ int size = currentBin.insertEnvSet.size();
+ for (i = 0; i < size; i++) {
+ newBin = currentBin.insertEnvSet.get(i);
+ if (newBin.equals(ra, lights, fog, modelClip)) {
+ eNew = newBin;
+ break;
+ }
+ }
+ }
+ currentBin = currentBin.next;
+ }
+ }
+
+
+ if (eNew == null) {
+ // Need a new one
+ currentEnvSet = getEnvironmentSet(ra, lights, fog, modelClip);
+ // Find a lightbin that envSet fits into
+ currentBin = lightBin;
+ while (currentBin != null) {
+
+ // the first test is always true for non-backgroundGeo bins
+ if (currentBin.geometryBackground ==
+ ra.geometryAtom.source.geometryBackground &&
+ currentBin.willEnvironmentSetFit(currentEnvSet)) {
+
+ // there may be new lights define which needs to
+ // call native updateLight().
+ // When using existing lightBin we have to force
+ // reevaluate Light.
+ for (i=0; i < lights.length; i++) {
+ if (!changedLts.contains(lights[i]))
+ changedLts.add(lights[i]);
+ envDirty |= REEVALUATE_LIGHTS;
+
+ }
+ break;
+ }
+ currentBin = currentBin.next;
+ }
+
+ // Now check the to-be added lightbins
+ if (currentBin == null) {
+ currentBin = addBin;
+ while (currentBin != null) {
+
+ // the first test is always true for non-backgroundGeo bins
+ if (currentBin.geometryBackground ==
+ ra.geometryAtom.source.geometryBackground &&
+ currentBin.willEnvironmentSetFit(currentEnvSet)) {
+
+ // there may be new lights define which needs to
+ // call native updateLight().
+ // When using existing lightBin we have to force
+ // reevaluate Light.
+ for (i=0; i < lights.length; i++) {
+ if (!changedLts.contains(lights[i]))
+ changedLts.add(lights[i]);
+ envDirty |= REEVALUATE_LIGHTS;
+
+ }
+ break;
+ }
+ currentBin = currentBin.next;
+ }
+ }
+
+ if (currentBin == null) {
+ // Need a new lightbin
+ currentBin = getLightBin(maxLights,
+ ra.geometryAtom.source.geometryBackground, false);
+ if (addBin != null) {
+ currentBin.next = addBin;
+ addBin.prev = currentBin;
+ }
+ if (ra.geometryAtom.source.orderedPath != null) {
+ if (!oc.onUpdateList) {
+ objUpdateList.add(oc);
+ oc.onUpdateList = true;
+ }
+ oc.addLightBins = currentBin;
+ } else {
+ if (ra.geometryAtom.source.geometryBackground == null)
+ addOpaqueBin = currentBin;
+ else
+ bgAddOpaqueBin = currentBin;
+ }
+
+ }
+ eNew = currentEnvSet;
+ currentBin.addEnvironmentSet(eNew, this);
+
+ }
+ ra.fog = fog;
+ ra.lights = lights;
+ ra.modelClip = modelClip;
+ ra.app = app;
+ reInsertAttributeBin(eNew, ra);
+
+ }
+
+ private void reInsertAttributeBin(EnvironmentSet e, RenderAtom ra) {
+ AttributeBin ab;
+ // Just go up to the environment and re-insert
+ ab = findAttributeBin(e, ra);
+ reInsertShaderBin(ab, ra);
+ }
+
+ private void reInsertShaderBin(AttributeBin ab, RenderAtom ra) {
+ ShaderBin sb;
+
+ // System.err.println("RenderBin.reInsertShaderBin() ra= " + ra);
+ sb = findShaderBin(ab, ra);
+ reInsertTextureBin(sb, ra);
+ }
+
+ private void reInsertTextureBin(ShaderBin sb, RenderAtom ra) {
+ TextureBin tb;
+
+ tb = findTextureBin(sb, ra);
+ reInsertRenderAtom(tb, ra);
+ }
+
+ private void reInsertRenderAtom(TextureBin tb, RenderAtom ra) {
+ RenderMolecule newRm;
+ // Just go up to the texture bin and re-insert
+ newRm = findRenderMolecule(tb, ra);
+ }
+
+ private void computeViewFrustumBBox(BoundingBox viewFrustumBBox) {
+ //Initial view frustumBBox BBox
+ viewFrustumBBox.lower.x = Float.POSITIVE_INFINITY;
+ viewFrustumBBox.lower.y = Float.POSITIVE_INFINITY;
+ viewFrustumBBox.lower.z = Float.POSITIVE_INFINITY;
+ viewFrustumBBox.upper.x = Float.NEGATIVE_INFINITY;
+ viewFrustumBBox.upper.y = Float.NEGATIVE_INFINITY;
+ viewFrustumBBox.upper.z = Float.NEGATIVE_INFINITY;
+
+ Canvas3D canvases[] = view.getCanvases();
+ for (int i=0; i< canvases.length; i++) {
+ Canvas3D canvas = canvases[i];
+
+ //Initial view frustumBBox BBox
+ canvasFrustumBBox.lower.x = Float.POSITIVE_INFINITY;
+ canvasFrustumBBox.lower.y = Float.POSITIVE_INFINITY;
+ canvasFrustumBBox.lower.z = Float.POSITIVE_INFINITY;
+ canvasFrustumBBox.upper.x = Float.NEGATIVE_INFINITY;
+ canvasFrustumBBox.upper.y = Float.NEGATIVE_INFINITY;
+ canvasFrustumBBox.upper.z = Float.NEGATIVE_INFINITY;
+
+ canvas.updateViewCache(true, null, canvasFrustumBBox, false);
+
+ if(viewFrustumBBox.lower.x > canvasFrustumBBox.lower.x)
+ viewFrustumBBox.lower.x = canvasFrustumBBox.lower.x;
+ if(viewFrustumBBox.lower.y > canvasFrustumBBox.lower.y)
+ viewFrustumBBox.lower.y = canvasFrustumBBox.lower.y;
+ if(viewFrustumBBox.lower.z > canvasFrustumBBox.lower.z)
+ viewFrustumBBox.lower.z = canvasFrustumBBox.lower.z;
+
+ if(viewFrustumBBox.upper.x < canvasFrustumBBox.upper.x)
+ viewFrustumBBox.upper.x = canvasFrustumBBox.upper.x;
+ if(viewFrustumBBox.upper.y < canvasFrustumBBox.upper.y)
+ viewFrustumBBox.upper.y = canvasFrustumBBox.upper.y;
+ if(viewFrustumBBox.upper.z < canvasFrustumBBox.upper.z)
+ viewFrustumBBox.upper.z = canvasFrustumBBox.upper.z;
+ }
+ }
+
+
+
+ /**
+ * This inserts a RenderAtom into the appropriate bin.
+ */
+ private RenderMolecule insertRenderAtom(RenderAtom ra) {
+ EnvironmentSet environmentSet;
+ AttributeBin attributeBin;
+ ShaderBin shaderBin;
+ TextureBin textureBin;
+ RenderMolecule renderMolecule;
+ AppearanceRetained app;
+ Object[] retVal;
+ GeometryAtom ga = ra.geometryAtom;
+
+ // System.err.println("insertRenderAtom ga " + ra.geometryAtom);
+ // determine if a separate copy of localeVwcBounds is needed
+ // based on the locale info
+
+ if (ra.localeVwcBounds == null) {
+ // Handle multiple locales
+ if (!locale.hiRes.equals(ga.source.locale.hiRes)) {
+ ga.source.locale.hiRes.difference(locale.hiRes,
+ localeTranslation);
+ ra.localeVwcBounds = new BoundingBox();
+ ra.localeVwcBounds.translate(ga.source.vwcBounds,
+ localeTranslation);
+ ra.dirtyMask |= RenderAtom.HAS_SEPARATE_LOCALE_VWC_BOUNDS;
+ }
+ else {
+ ra.dirtyMask &= ~RenderAtom.HAS_SEPARATE_LOCALE_VWC_BOUNDS;
+ ra.localeVwcBounds = ga.source.vwcBounds;
+ }
+ }
+
+
+ // If the appearance is overrideable, then get the
+ // applicable appearance
+ if (ga.source.appearanceOverrideEnable) {
+ retVal = universe.renderingEnvironmentStructure.getInfluencingAppearance(ra, view);
+ // If its a valid alternate appaearance
+ if (retVal[0] == Boolean.TRUE) {
+ app = (AppearanceRetained)retVal[1];
+ ra.app = app;
+ if (ga.source.otherAppearance != app) {
+ if (ga.source.otherAppearance != null)
+ ga.source.otherAppearance.sgApp.
+ removeAMirrorUser(ga.source);
+ ga.source.otherAppearance = app;
+ if (app != null)
+ ra.app.sgApp.addAMirrorUser(ga.source);
+ }
+ }
+ else {
+ ra.app = ga.source.appearance;
+
+ }
+ } else {
+ ra.app = ga.source.appearance;
+ }
+ // Call environment set, only after the appearance has been
+ // determined
+ environmentSet = findEnvironmentSet(ra);
+ attributeBin = findAttributeBin(environmentSet, ra);
+
+ // System.err.println("RenderBin : findShaderBin()");
+ shaderBin = findShaderBin(attributeBin, ra);
+
+ textureBin = findTextureBin(shaderBin, ra);
+ renderMolecule = findRenderMolecule(textureBin, ra);
+ ra.setRenderBin(true);
+ renderAtoms.add(ra);
+
+ if (ga.source instanceof OrientedShape3DRetained) {
+ // dirty initially
+ dirtyOrientedRAs.add(ra);
+ ra.dirtyMask |= RenderAtom.IN_DIRTY_ORIENTED_RAs;
+ ra.dirtyMask |= RenderAtom.IS_ORIENTED;
+ for(int k = 0; k < ra.rListInfo.length; k++) {
+ if (ra.rListInfo[k].localToVworld == null) {
+ ra.rListInfo[k].localToVworld = new Transform3D();
+ }
+ }
+ }
+
+ if (renderMolecule.primaryMoleculeType ==
+ RenderMolecule.TEXT3D_MOLECULE) {
+ if (!ra.onUpdateList()) {
+ ra.dirtyMask |= RenderAtom.ON_UPDATELIST;
+ objUpdateList.add(ra);
+ }
+ }
+
+ // ra.needSeparateLocaleVwcBounds flag is determined in
+ // RenderMolecule.addRenderAtom based on the render method type.
+ // That's why the localeVwcBounds has to be reevaluated here again
+ // If after compaction being added in, then we just need to
+ // set the updated vwcBounds, there is no need to allocate
+ if (ra.needSeparateLocaleVwcBounds()) {
+ if (!ra.hasSeparateLocaleVwcBounds()) {
+ ra.dirtyMask |= RenderAtom.HAS_SEPARATE_LOCALE_VWC_BOUNDS;
+ ra.localeVwcBounds = new BoundingBox(ga.source.vwcBounds);
+ ra.dirtyMask |= RenderAtom.ON_LOCALE_VWC_BOUNDS_UPDATELIST;
+ raLocaleVwcBoundsUpdateList.add(ra);
+ }
+ else {
+ ra.localeVwcBounds.set(ga.source.vwcBounds);
+ ra.dirtyMask |= RenderAtom.ON_LOCALE_VWC_BOUNDS_UPDATELIST;
+ raLocaleVwcBoundsUpdateList.add(ra);
+ }
+ }
+ return (renderMolecule);
+ }
+
+ private OrderedCollection findOrderedCollection(GeometryAtom ga,
+ boolean doBackground) {
+ int i, n;
+ int oi; // an id which identifies a children of the orderedGroup
+ int ci; // child index of the ordered group
+ int val;
+
+ OrderedGroupRetained og;
+ OrderedCollection oc = null;
+ ArrayList<OrderedCollection> ocs;
+ ArrayList<OrderedBin> parentChildOrderedBins;
+ OrderedBin parentOrderedBin;
+ int parentOrderedChildId;
+
+ // Since the table has been incremented, in response to OG addition,
+ // but the ordered collecyions has not been added yet, we need to
+ // check what the original index into the ordered collection
+ // should be
+ int adjustment;
+
+ if (doBackground) {
+ parentChildOrderedBins = bgOrderedBins;
+ } else {
+ parentChildOrderedBins = orderedBins;
+ }
+
+ parentOrderedBin = null;
+ parentOrderedChildId = -1;
+
+ for (i=0; i<ga.source.orderedPath.pathElements.size(); i++) {
+ OrderedPathElement ope = ga.source.orderedPath.pathElements.get(i);
+ og = ope.orderedGroup;
+ oi = ope.childId.intValue();
+
+ OrderedBin ob = og.getOrderedBin(view.viewIndex);
+ if (ob == null) {
+ // create ordered bin tree
+ ob = new OrderedBin(og.childCount, og);
+ og.setOrderedBin(ob, view.viewIndex);
+
+ int index = -1;
+ for (n = 0; n < orderedBinsList.size(); n++) {
+ if (parentChildOrderedBins == orderedBinsList.get(n)) {
+ index = n;
+ break;
+ }
+ }
+ if (index == -1) {
+ orderedBinsList.add(parentChildOrderedBins);
+ ArrayList<OrderedBin> list = new ArrayList<OrderedBin>(5);
+ list.add(ob);
+ toBeAddedBinList.add(list);
+ }
+ else {
+ ArrayList<OrderedBin> list = toBeAddedBinList.get(index);
+ list.add(ob);
+ }
+ }
+ ocs = ob.orderedCollections;
+ OrderedChildInfo cinfo = ob.lastChildInfo;
+ boolean found = false;
+ // Check if a oc is already creates for this oi
+ // Start from the last child that was added and work backwards,
+ // in case the child
+ // was added and removed and then added back the same frame, we get the
+ // correct oc
+ while (cinfo != null && !found) {
+ if (cinfo.type == OrderedChildInfo.ADD) {
+ if (cinfo.orderedId == oi) {
+ oc = cinfo.value;
+ if (oc == null) {
+ oc = new OrderedCollection();
+ cinfo.value = oc;
+ }
+ found = true;
+ }
+ }
+ cinfo = cinfo.prev;
+ }
+ // If we are in the update_view case then check the oi
+ // exists in the setOCForOI list ..
+ for (n = 0; n < ob.setOCForOI.size(); n++) {
+ val = ob.setOCForOI.get(n).intValue();
+ if (oi == val) {
+ oc = ob.valueOfSetOCForOI.get(n);
+ found = true;
+ }
+ }
+ // The list is not going to be modified by any additions
+ // that have happened ...
+ // Then this child must exists from the previous frame, so
+ // get the location
+ if (!found) {
+ // The case below happens when there have been some insert
+ // ordered nodes, but update_view happens later and
+ // so the earlier insert ordered nodes are not
+ // seen by renderBin!
+ if (og.orderedChildIdTable == null || oi >= og.orderedChildIdTable.length) {
+ // Create a new category that adds Info based only on oi
+ // which will be added to the orderedBin after the
+ // idTable reflects the correct childId for the next frame
+ ob.setOCForOI.add(new Integer(oi));
+ oc = new OrderedCollection();
+ ob.valueOfSetOCForOI.add(oc);
+ if (!ob.onUpdateList) {
+ obList.add(ob);
+ ob.onUpdateList = true;
+ }
+ }
+ else {
+ ci = og.orderedChildIdTable[oi];
+
+ for (n = 0; n < ob.setOCForCI.size(); n++) {
+ val = ob.setOCForCI.get(n).intValue();
+ if (val == ci) {
+
+ oc = ob.valueOfSetOCForCI.get(n);
+ if (oc == null) {
+ oc = new OrderedCollection();
+ ob.valueOfSetOCForCI.set(n, oc);
+ }
+
+ break;
+ }
+ }
+ if (n == ob.setOCForCI.size()) {
+ oc = ocs.get(ci);
+ if (oc == null) {
+ oc = new OrderedCollection();
+ ob.setOCForCI.add(new Integer(ci));
+ ob.valueOfSetOCForCI.add(oc);
+ if (!ob.onUpdateList) {
+ obList.add(ob);
+ ob.onUpdateList = true;
+ }
+ }
+ }
+ }
+ }
+ if (oc.nextFrameLightBin == null) {
+ oc.nextFrameLightBin = getLightBin(maxLights,
+ ga.source.geometryBackground, false);
+ oc.nextFrameLightBin.setOrderedInfo(oc);
+
+ if (!oc.onUpdateList) {
+ objUpdateList.add(oc);
+ oc.onUpdateList = true;
+ }
+ }
+
+ parentChildOrderedBins = oc.childOrderedBins;
+ parentOrderedBin = ob;
+ parentOrderedChildId = oi;
+ }
+ return (oc);
+ }
+
+ private void removeOrderedHeadLightBin(LightBin lightBin) {
+ OrderedCollection oc;
+
+ oc = lightBin.orderedCollection;
+
+ oc.lightBin = lightBin.next;
+ oc.nextFrameLightBin = oc.lightBin;
+
+
+
+ if (oc.lightBin != null) {
+ // Make this lightBin the head of the lightBin;
+ oc.lightBin.prev = null;
+ oc.lightBin.orderedCollection = oc;
+ }
+
+
+ }
+
+
+ /**
+ * This gets a new EnviornmentSet. It creates one if there are none
+ * on the freelist.
+ */
+ private EnvironmentSet getEnvironmentSet(RenderAtom ra, LightRetained[] lights,
+ FogRetained fog, ModelClipRetained modelClip) {
+ EnvironmentSet envSet;
+
+ envSet = new EnvironmentSet(ra, lights, fog, modelClip, this);
+ return (envSet);
+ }
+
+ /**
+ * This finds or creates an AttributeBin for a given RenderAtom.
+ */
+ private AttributeBin findAttributeBin(EnvironmentSet envSet, RenderAtom ra) {
+ int i;
+ AttributeBin currentBin;
+ RenderingAttributesRetained renderingAttributes;
+ if (ra.app == null) {
+ renderingAttributes = null;
+ } else {
+ renderingAttributes = ra.app.renderingAttributes;
+ }
+
+ currentBin = envSet.attributeBinList;
+ while (currentBin != null) {
+ if (currentBin.equals(renderingAttributes, ra)) {
+ return(currentBin);
+ }
+ currentBin = currentBin.next;
+ }
+ // Check the "to-be-added" list of attributeBins for a match
+ for (i = 0; i < envSet.addAttributeBins.size(); i++) {
+ currentBin = envSet.addAttributeBins.get(i);
+ if (currentBin.equals(renderingAttributes, ra)) {
+ return(currentBin);
+ }
+ }
+ currentBin = getAttributeBin(ra.app, renderingAttributes);
+ envSet.addAttributeBin(currentBin, this);
+ return(currentBin);
+ }
+
+ /**
+ * This finds or creates an ShaderBin for a given RenderAtom.
+ */
+ private ShaderBin findShaderBin(AttributeBin attributeBin, RenderAtom ra) {
+ int i, size;
+ ShaderBin currentBin;
+ ShaderAppearanceRetained sApp;
+
+ if((ra != null) && (ra.app instanceof ShaderAppearanceRetained))
+ sApp = (ShaderAppearanceRetained)ra.app;
+ else
+ sApp = null;
+
+ currentBin = attributeBin.shaderBinList;
+ while (currentBin != null) {
+ if (currentBin.equals(sApp)) {
+ return currentBin;
+ }
+ currentBin = currentBin.next;
+ }
+
+ // Check the "to-be-added" list of shaderBins for a match
+ size = attributeBin.addShaderBins.size();
+ for (i = 0; i < size; i++) {
+ currentBin = attributeBin.addShaderBins.get(i);
+ if (currentBin.equals(sApp)) {
+ return currentBin;
+ }
+ }
+
+ currentBin = getShaderBin(sApp);
+ attributeBin.addShaderBin(currentBin, this, sApp);
+ return currentBin;
+ }
+
+ /**
+ * This finds or creates a TextureBin for a given RenderAtom.
+ */
+ private TextureBin findTextureBin(ShaderBin shaderBin, RenderAtom ra) {
+ int i, size;
+ TextureBin currentBin;
+ TextureUnitStateRetained texUnitState[];
+
+ if (ra.app == null) {
+ texUnitState = null;
+ } else {
+ texUnitState = ra.app.texUnitState;
+ }
+
+ currentBin = shaderBin.textureBinList;
+ while (currentBin != null) {
+ if (currentBin.equals(texUnitState, ra)) {
+ //System.err.println("1: Equal");
+ return(currentBin);
+ }
+ currentBin = currentBin.next;
+ }
+ // Check the "to-be-added" list of TextureBins for a match
+ size = shaderBin.addTextureBins.size();
+ for (i = 0; i < size; i++) {
+ currentBin = shaderBin.addTextureBins.get(i);
+ if (currentBin.equals(texUnitState, ra)) {
+ //System.err.println("2: Equal");
+ return(currentBin);
+ }
+ }
+ // get a new texture bin for this texture unit state
+ currentBin = getTextureBin(texUnitState, ra.app);
+ shaderBin.addTextureBin(currentBin, this, ra);
+ return(currentBin);
+ }
+
+ /**
+ * This finds or creates a RenderMolecule for a given RenderAtom.
+ */
+ private RenderMolecule findRenderMolecule(TextureBin textureBin,
+ RenderAtom ra) {
+
+ RenderMolecule currentBin;
+ PolygonAttributesRetained polygonAttributes;
+ LineAttributesRetained lineAttributes;
+ PointAttributesRetained pointAttributes;
+ MaterialRetained material;
+ ColoringAttributesRetained coloringAttributes;
+ TransparencyAttributesRetained transparencyAttributes;
+ int i;
+ TextureUnitStateRetained texUnitState[];
+ RenderingAttributesRetained renderingAttributes;
+
+ if (ra.app == null) {
+ polygonAttributes = null;
+ lineAttributes = null;
+ pointAttributes = null;
+ material = null;
+ coloringAttributes = null;
+ transparencyAttributes = null;
+ renderingAttributes = null;
+ texUnitState = null;
+ } else {
+ polygonAttributes = ra.app.polygonAttributes;
+ lineAttributes = ra.app.lineAttributes;
+ pointAttributes = ra.app.pointAttributes;
+ material = ra.app.material;
+ coloringAttributes = ra.app.coloringAttributes;
+ transparencyAttributes = ra.app.transparencyAttributes;
+ renderingAttributes = ra.app.renderingAttributes;
+ texUnitState = ra.app.texUnitState;
+ }
+
+ // Get the renderMoleculelist for this xform
+ HashMap<Transform3D[], RenderMolecule> rmap = null;
+ HashMap<Transform3D[], ArrayList<RenderMolecule>> addmap = null;
+ if (ra.isOpaque()) {
+ rmap = textureBin.opaqueRenderMoleculeMap;
+ addmap = textureBin.addOpaqueRMs;
+ }
+ else {
+ rmap = textureBin.transparentRenderMoleculeMap;
+ addmap = textureBin.addTransparentRMs;
+ }
+ currentBin = rmap.get(ra.geometryAtom.source.localToVworld[0]);
+
+ while (currentBin != null) {
+ if (currentBin.equals(ra,
+ polygonAttributes, lineAttributes,
+ pointAttributes, material,
+ coloringAttributes,
+ transparencyAttributes,
+ ra.geometryAtom.source.localToVworld[0])) {
+
+ currentBin.addRenderAtom(ra, this);
+ ra.envSet = ra.renderMolecule.textureBin.environmentSet;
+ // If the locale has changed for an existing renderMolecule
+ // handle the RmlocaleToVworld
+ return(currentBin);
+ }
+ currentBin = currentBin.next;
+ }
+ // Check the "to-be-added" list of renderMolecules for a match
+ ArrayList<RenderMolecule> list = addmap.get(ra.geometryAtom.source.localToVworld[0]);
+ if (list != null) {
+ for (i = 0; i < list.size(); i++) {
+ currentBin = list.get(i);
+ if (currentBin.equals(ra,
+ polygonAttributes, lineAttributes,
+ pointAttributes, material,
+ coloringAttributes,
+ transparencyAttributes,
+ ra.geometryAtom.source.localToVworld[0])) {
+ currentBin.addRenderAtom(ra, this);
+ return(currentBin);
+ }
+ }
+ }
+
+
+ currentBin = getRenderMolecule(ra.geometryAtom,
+ polygonAttributes,
+ lineAttributes,
+ pointAttributes,
+ material,
+ coloringAttributes,
+ transparencyAttributes,
+ renderingAttributes,
+ texUnitState,
+ ra.geometryAtom.source.localToVworld[0],
+ ra.geometryAtom.source.localToVworldIndex[0]);
+ textureBin.addRenderMolecule(currentBin, this);
+ currentBin.addRenderAtom(ra, this);
+ return(currentBin);
+ }
+
+ /**
+ * This gets a new ShaderBin. It creates one if there are none
+ * on the freelist.
+ */
+ private ShaderBin getShaderBin(ShaderAppearanceRetained sApp) {
+ return new ShaderBin( sApp, this);
+ }
+
+ /**
+ * This gets a new AttributeBin. It creates one if there are none
+ * on the freelist.
+ */
+ private AttributeBin getAttributeBin(AppearanceRetained app, RenderingAttributesRetained ra) {
+ return new AttributeBin(app, ra, this);
+ }
+
+ /**
+ * This gets a new LightBin. It creates one if there are none
+ * on the freelist.
+ */
+ private LightBin getLightBin(int maxLights, BackgroundRetained bg, boolean inOpaque) {
+ LightBin lightBin;
+
+ lightBin = new LightBin(maxLights, this, inOpaque);
+
+ lightBin.geometryBackground = bg;
+ return (lightBin);
+ }
+
+ /**
+ * This gets a new TextureBin. It creates one if there are none
+ * on the freelist.
+ */
+ private TextureBin getTextureBin(TextureUnitStateRetained texUnitState[],
+ AppearanceRetained app) {
+ return new TextureBin(texUnitState, app, this);
+ }
+
+ /**
+ * This gets a new RenderMolecule. It creates one if there are none
+ * on the freelist.
+ */
+ private RenderMolecule getRenderMolecule(GeometryAtom ga,
+ PolygonAttributesRetained polya,
+ LineAttributesRetained linea,
+ PointAttributesRetained pointa,
+ MaterialRetained material,
+ ColoringAttributesRetained cola,
+ TransparencyAttributesRetained transa,
+ RenderingAttributesRetained ra,
+ TextureUnitStateRetained[] texUnits,
+ Transform3D[] transform,
+ int[] transformIndex) {
+
+ return new RenderMolecule(ga, polya, linea, pointa,
+ material, cola, transa, ra,
+ texUnits,
+ transform, transformIndex, this);
+ }
+
+
+ /**
+ * This finds or creates an EnviornmentSet for a given RenderAtom.
+ * This also deals with empty LightBin lists.
+ */
+ private EnvironmentSet findEnvironmentSet(RenderAtom ra) {
+ LightBin currentBin, lightBin ;
+ EnvironmentSet currentEnvSet, newBin;
+ int i;
+ LightBin addBin = null;
+ OrderedCollection oc = null;
+
+ if (ra.geometryAtom.source.geometryBackground == null) {
+ if (ra.geometryAtom.source.orderedPath != null) {
+ oc = findOrderedCollection(ra.geometryAtom, false);
+ currentBin = oc.nextFrameLightBin;
+ addBin = oc.addLightBins;
+ } else {
+ currentBin = opaqueBin;
+ addBin = addOpaqueBin;
+ }
+ } else {
+ if (ra.geometryAtom.source.orderedPath != null) {
+ oc = findOrderedCollection(ra.geometryAtom, true);
+ currentBin = oc.nextFrameLightBin;
+ addBin = oc.addLightBins;
+ } else {
+ currentBin = bgOpaqueBin;
+ addBin = bgAddOpaqueBin;
+
+ }
+ }
+ lightBin = currentBin;
+
+
+ ra.lights = universe.renderingEnvironmentStructure.
+ getInfluencingLights(ra, view);
+ ra.fog = universe.renderingEnvironmentStructure.
+ getInfluencingFog(ra, view);
+ ra.modelClip = universe.renderingEnvironmentStructure.
+ getInfluencingModelClip(ra, view);
+
+ while (currentBin != null) {
+ // this test is always true for non-backgroundGeo bins
+ if (currentBin.geometryBackground ==
+ ra.geometryAtom.source.geometryBackground) {
+
+ currentEnvSet = currentBin.environmentSetList;
+ while (currentEnvSet != null) {
+ if (currentEnvSet.equals(ra, ra.lights, ra.fog, ra.modelClip)) {
+ return(currentEnvSet);
+ }
+ currentEnvSet = currentEnvSet.next;
+ }
+ // Check the "to-be-added" list of environmentSets for a match
+ for (i = 0; i < currentBin.insertEnvSet.size(); i++) {
+ newBin = currentBin.insertEnvSet.get(i);
+ if (newBin.equals(ra, ra.lights, ra.fog, ra.modelClip)) {
+ return(newBin);
+ }
+ }
+ }
+ currentBin = currentBin.next;
+ }
+
+ // Now check the to-be added lightbins
+ currentBin = addBin;
+ while (currentBin != null) {
+
+ // this following test is always true for non-backgroundGeo bins
+ if (currentBin.geometryBackground ==
+ ra.geometryAtom.source.geometryBackground) {
+
+ // Check the "to-be-added" list of environmentSets for a match
+ for (i = 0; i < currentBin.insertEnvSet.size(); i++) {
+ newBin = currentBin.insertEnvSet.get(i);
+ if (newBin.equals(ra, ra.lights, ra.fog, ra.modelClip)) {
+ return(newBin);
+ }
+ }
+ }
+ currentBin = currentBin.next;
+ }
+
+
+ // Need a new one
+ currentEnvSet = getEnvironmentSet(ra, ra.lights, ra.fog, ra.modelClip);
+ currentBin = lightBin;
+
+ // Find a lightbin that envSet fits into
+ while (currentBin != null) {
+
+ // the first test is always true for non-backgroundGeo bins
+ if (currentBin.geometryBackground ==
+ ra.geometryAtom.source.geometryBackground &&
+ currentBin.willEnvironmentSetFit(currentEnvSet)) {
+ break;
+ }
+ currentBin = currentBin.next;
+ }
+
+ // Now check the to-be added lightbins
+ if (currentBin == null) {
+ currentBin = addBin;
+ while (currentBin != null) {
+
+ // the first test is always true for non-backgroundGeo bins
+ if (currentBin.geometryBackground ==
+ ra.geometryAtom.source.geometryBackground &&
+ currentBin.willEnvironmentSetFit(currentEnvSet)) {
+
+ break;
+ }
+ currentBin = currentBin.next;
+ }
+ }
+
+ if (currentBin == null) {
+ // Need a new lightbin
+ currentBin = getLightBin(maxLights,
+ ra.geometryAtom.source.geometryBackground, false);
+ if (addBin != null) {
+ currentBin.next = addBin;
+ addBin.prev = currentBin;
+ }
+ if (ra.geometryAtom.source.orderedPath != null) {
+ if (!oc.onUpdateList) {
+ objUpdateList.add(oc);
+ oc.onUpdateList = true;
+ }
+ oc.addLightBins = currentBin;
+ } else {
+ if (ra.geometryAtom.source.geometryBackground == null)
+ addOpaqueBin = currentBin;
+ else
+ bgAddOpaqueBin = currentBin;
+ }
+ }
+
+ currentBin.addEnvironmentSet(currentEnvSet, this);
+ return (currentEnvSet);
+ }
+
+ void removeLightBin(LightBin lbin) {
+ if (lbin.prev == null) { // At the head of the list
+
+ if (lbin.orderedCollection != null)
+ removeOrderedHeadLightBin(lbin);
+
+ if (lbin.geometryBackground == null) {
+ if (opaqueBin == lbin) {
+ opaqueBin = lbin.next;
+ }
+ } else {
+ if (bgOpaqueBin == lbin) {
+ bgOpaqueBin = lbin.next;
+ }
+ }
+ if (lbin.next != null) {
+ lbin.next.prev = null;
+ }
+ } else { // In the middle or at the end.
+ lbin.prev.next = lbin.next;
+ if (lbin.next != null) {
+ lbin.next.prev = lbin.prev;
+ }
+ }
+ Canvas3D canvases[] = view.getCanvases();
+ for (int i = 0; i < canvases.length; i++) {
+ // Mark the environmentSet cached by all the canvases as null
+ // to force to reEvaluate when it comes back from the freelist
+ // During LightBin::render(), we only check for the pointers not
+ // being the same, so we need to take care of the env set
+ // gotten from the freelist from one frame to another
+ canvases[i].lightBin = null;
+ }
+ lbin.prev = null;
+ lbin.next = null;
+ }
+
+ void addDisplayListResourceFreeList(RenderMolecule rm) {
+ displayListResourceFreeList.add(rm.displayListIdObj);
+ }
+
+ /**
+ * This renders the background scene graph.
+ */
+ void renderBackground(Canvas3D cv) {
+ LightBin currentBin;
+ boolean savedDepthBufferWriteEnable;
+
+ cv.setDepthBufferWriteEnableOverride(true);
+ savedDepthBufferWriteEnable = cv.depthBufferWriteEnable;
+ cv.setDepthBufferWriteEnable(false);
+ // render background opaque
+ currentBin = bgOpaqueBin;
+ while (currentBin != null) {
+ if (currentBin.geometryBackground == geometryBackground)
+ currentBin.render(cv);
+ currentBin = currentBin.next;
+ }
+
+ // render background ordered
+ if (bgOrderedBins.size() > 0) {
+ renderOrderedBins(cv, bgOrderedBins, true);
+ }
+
+ TransparentRenderingInfo tinfo = bgTransparentInfo;
+ while (tinfo != null) {
+ tinfo.render(cv);
+ tinfo = tinfo.next;
+ }
+ cv.setDepthBufferWriteEnableOverride(false);
+ cv.setDepthBufferWriteEnable(savedDepthBufferWriteEnable);
+ }
+
+ /**
+ * This renders the opaque objects
+ */
+ void renderOpaque(Canvas3D cv) {
+ LightBin currentBin = opaqueBin;
+ //System.err.println("========> renderOpaque");
+ while (currentBin != null) {
+ //System.err.println("====> rendering Opaque Bin ");
+ currentBin.render(cv);
+ currentBin = currentBin.next;
+ }
+
+ }
+
+ /**
+ * This renders the transparent objects
+ */
+ void renderTransparent(Canvas3D cv) {
+ boolean savedDepthBufferWriteEnable = true;
+
+ //System.err.println("====> renderTransparent");
+ TransparentRenderingInfo tinfo = transparentInfo;
+ if (tinfo != null) {
+ //System.err.println("====> rendering transparent Bin");
+
+ if (cv.view.depthBufferFreezeTransparent) {
+ cv.setDepthBufferWriteEnableOverride(true);
+ savedDepthBufferWriteEnable = cv.depthBufferWriteEnable;
+ cv.setDepthBufferWriteEnable(false);
+ }
+
+ if (transpSortMode == View.TRANSPARENCY_SORT_NONE) {
+ while (tinfo != null) {
+ tinfo.render(cv);
+ tinfo = tinfo.next;
+ }
+ }
+ else if (transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY) {
+ while (tinfo != null ) {
+ tinfo.sortRender(cv);
+ tinfo = tinfo.next;
+ }
+ }
+ if (cv.view.depthBufferFreezeTransparent) {
+ cv.setDepthBufferWriteEnableOverride(false);
+ cv.setDepthBufferWriteEnable(savedDepthBufferWriteEnable);
+ }
+ }
+ }
+
+ /**
+ * This renders the ordered objects
+ */
+ void renderOrdered(Canvas3D cv) {
+ // System.err.println("******renderOrdered, orderedBins.size() = "+orderedBins.size()+" RenderBin = "+this);
+ if (orderedBins.size() > 0)
+ renderOrderedBins(cv, orderedBins, false);
+ }
+
+void renderOrderedBins(Canvas3D cv, ArrayList<OrderedBin> bins, boolean doInfinite) {
+ int sz = bins.size();
+
+ for (int i = 0; i < sz; i++) {
+ renderOrderedBin(cv, bins.get(i), doInfinite);
+ }
+}
+
+ void renderOrderedBin(Canvas3D cv, OrderedBin orderedBin,
+ boolean doInfinite) {
+ int i, index;
+ LightBin currentBin;
+ OrderedCollection oc;
+ boolean depthBufferEnable = true;
+ OrderedGroupRetained og = orderedBin.source;
+ boolean isDecal = (og instanceof DecalGroupRetained) && cv.systemStencilAvailable;
+ int size = orderedBin.orderedCollections.size();
+
+ // System.err.println("RB : orderedBin.orderedCollections.size() " + size);
+ for (i=0; i<size; i++) {
+ if((og != null) && (og.childIndexOrder != null)) {
+ index = og.childIndexOrder[i];
+ }
+ else {
+ index = i;
+ }
+ oc = orderedBin.orderedCollections.get(index);
+ if (isDecal) {
+ if (index==0) { // first child
+ cv.setDepthBufferEnableOverride(true);
+ depthBufferEnable = cv.decal1stChildSetup(cv.ctx);
+ } else if (index==1) { // second child
+ // decalNthChildSetup will disable depth test
+ cv.decalNthChildSetup(cv.ctx);
+ }
+ }
+ if (oc != null) {
+ currentBin = oc.lightBin;
+ while (currentBin != null) {
+ if (!doInfinite ||
+ currentBin.geometryBackground == geometryBackground) {
+ currentBin.render(cv);
+ }
+ currentBin = currentBin.next;
+ }
+ renderOrderedBins(cv, oc.childOrderedBins, doInfinite);
+ }
+ }
+ if (isDecal) { // reset
+ cv.decalReset(cv.ctx, depthBufferEnable);
+ cv.setDepthBufferEnableOverride(false);
+ }
+ }
+
+
+ /**
+ * Sets the new background color.
+ */
+ void setBackground(BackgroundRetained back) {
+
+ boolean cvDirty = false;
+ BackgroundRetained oldGeomBack = geometryBackground;
+ geometryBackground = null;
+
+ if (back != null) {
+ background.initColor(back.color);
+ background.initImageScaleMode(back.imageScaleMode);
+ background.geometryBranch = back.geometryBranch;
+ if (background.geometryBranch != null) {
+ geometryBackground = back;
+ }
+ // Release resources associated with old BG and initialize new BG
+ // if the old and new BG images are different or if the
+ // reloadBgTexture flag is set.
+ if (background.image != back.image || reloadBgTexture) {
+ if (background.image != null) {
+ assert background.texture != null;
+ addTextureResourceFreeList(background.texture);
+ removeNodeComponent(background.image);
+ }
+ if (back.image != null) {
+ // May need to optimize later
+ background.initImage((ImageComponent2D)back.image.source);
+ addNodeComponent(back.image);
+ } else {
+ background.initImage(null);
+ }
+ }
+ if (oldGeomBack == null) {
+ cvDirty = true;
+ }
+ } else {
+ background.initColor(black);
+ background.geometryBranch = null;
+ if (background.image != null) {
+ assert background.texture != null;
+ addTextureResourceFreeList(background.texture);
+ removeNodeComponent(background.image);
+ }
+ background.initImage(null);
+ if (oldGeomBack != null) {
+ cvDirty = true;
+ }
+ }
+
+ // Need to reEvaluate View cache since doInfinite
+ // flag is changed in Renderer.updateViewCache()
+ Canvas3D canvases[] = view.getCanvases();
+ for (int i=0; i< canvases.length; i++) {
+ Canvas3D canvas = canvases[i];
+ synchronized (canvas.dirtyMaskLock) {
+ if(cvDirty) {
+ canvas.cvDirtyMask[0] |= Canvas3D.BACKGROUND_DIRTY;
+ canvas.cvDirtyMask[1] |= Canvas3D.BACKGROUND_DIRTY;
+ }
+ canvas.cvDirtyMask[0] |= Canvas3D.BACKGROUND_IMAGE_DIRTY;
+ canvas.cvDirtyMask[1] |= Canvas3D.BACKGROUND_IMAGE_DIRTY;
+ }
+ }
+ }
+
+
+ void reEvaluateFog(ArrayList<FogRetained> fogs, boolean updateDirty,
+ boolean altAppDirty) {
+ EnvironmentSet e;
+ FogRetained newfog;
+ int i;
+ AppearanceRetained app;
+ Object[] retVal;
+
+ int sz = renderAtoms.size();
+ for (i = 0; i < sz; i++) {
+ RenderAtom ra = renderAtoms.get(i);
+ if (!ra.inRenderBin())
+ continue;
+
+ newfog = universe.renderingEnvironmentStructure.getInfluencingFog(ra, view);
+ // If the fog of the render atom is the same
+ // as the old fog, then move on to the
+ // next renderAtom
+ if (altAppDirty&&ra.geometryAtom.source.appearanceOverrideEnable) {
+ retVal = universe.renderingEnvironmentStructure.getInfluencingAppearance(ra, view);
+ if (retVal[0] == Boolean.TRUE) {
+ app = (AppearanceRetained)retVal[1];
+ }
+ else {
+ app = ra.geometryAtom.source.appearance;
+ }
+
+ if (app == ra.app) {
+ if (ra.envSet.fog == newfog)
+ continue;
+ else {
+ getNewEnvironment(ra, ra.lights, newfog, ra.modelClip, ra.app);
+ }
+ }
+ else {
+ if (ra.geometryAtom.source.otherAppearance != app) {
+ if (ra.geometryAtom.source.otherAppearance != null)
+ ra.geometryAtom.source.otherAppearance.sgApp.removeAMirrorUser(ra.geometryAtom.source);
+ if (app != ra.geometryAtom.source.appearance) {
+ if (app != null) {
+ app.sgApp.addAMirrorUser(ra.geometryAtom.source);
+ }
+ ra.geometryAtom.source.otherAppearance = app;
+ }
+ else {
+ ra.geometryAtom.source.otherAppearance = null;
+ }
+ }
+
+ if (ra.envSet.fog == newfog) {
+ ra.app = app;
+ e = ra.envSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+ else {
+ getNewEnvironment(ra, ra.lights, newfog, ra.modelClip,
+ app);
+ }
+ }
+ }
+ else {
+ if (ra.envSet.fog == newfog)
+ continue;
+ getNewEnvironment(ra, ra.lights, newfog, ra.modelClip, ra.app);
+ };
+ }
+
+ // Only done for new fogs added to the system
+ if (updateDirty)
+ updateCanvasForDirtyFog(fogs);
+ }
+
+
+void updateCanvasForDirtyFog(ArrayList<FogRetained> fogs) {
+ int i, j;
+ EnvironmentSet e;
+ UnorderList list;
+ EnvironmentSet envsets[];
+ int envsize;
+ int sz = fogs.size();
+
+ for (i = 0; i < sz; i++) {
+ FogRetained fog = fogs.get(i);
+ list = fog.environmentSets;
+ synchronized (list) {
+ envsize = list.size();
+ envsets = (EnvironmentSet []) list.toArray(false);
+ for (j = 0; j < envsize; j++) {
+ e = envsets[j];
+ e.canvasDirty |= Canvas3D.FOG_DIRTY;
+ if (!e.onUpdateList) {
+ objUpdateList.add(e);
+ e.onUpdateList = true;
+ }
+ }
+ }
+ }
+ }
+
+ void reEvaluateModelClip(ArrayList<ModelClipRetained> modelClips,
+ boolean updateDirty,
+ boolean altAppDirty) {
+ EnvironmentSet e;
+ ModelClipRetained newModelClip;
+ int i;
+ AppearanceRetained app;
+ Object[] retVal;
+ int sz = renderAtoms.size();
+ for (i = 0; i < sz; i++) {
+ RenderAtom ra = renderAtoms.get(i);
+ if (!ra.inRenderBin())
+ continue;
+
+ newModelClip =
+ universe.renderingEnvironmentStructure.getInfluencingModelClip(ra, view);
+
+ // If the model clip of the render atom is the same
+ // as the old model clip, then move on to the
+ // next renderAtom
+ if (altAppDirty&&ra.geometryAtom.source.appearanceOverrideEnable) {
+ retVal = universe.renderingEnvironmentStructure.getInfluencingAppearance(ra, view);
+ if (retVal[0] == Boolean.TRUE) {
+ app = (AppearanceRetained)retVal[1];
+ }
+ else {
+ app = ra.geometryAtom.source.appearance;
+ }
+
+ if (app == ra.app) {
+ if (ra.envSet.modelClip == newModelClip)
+ continue;
+ else {
+ getNewEnvironment(ra, ra.lights, ra.fog,
+ ra.envSet.modelClip, ra.app);
+ }
+ }
+ else {
+ if (ra.geometryAtom.source.otherAppearance != app) {
+ if (ra.geometryAtom.source.otherAppearance != null)
+ ra.geometryAtom.source.otherAppearance.sgApp.removeAMirrorUser(ra.geometryAtom.source);
+ if (app != ra.geometryAtom.source.appearance) {
+ if (app != null) {
+ app.sgApp.addAMirrorUser(ra.geometryAtom.source);
+ }
+ ra.geometryAtom.source.otherAppearance = app;
+ }
+ else {
+ ra.geometryAtom.source.otherAppearance = null;
+ }
+ }
+ if (ra.envSet.modelClip == newModelClip) {
+ ra.app = app;
+ e = ra.envSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+ else {
+
+ getNewEnvironment(ra, ra.lights, ra.fog, newModelClip,
+ app);
+ }
+ }
+ }
+ else {
+ if (ra.envSet.modelClip == newModelClip)
+ continue;
+ getNewEnvironment(ra, ra.lights, ra.fog, newModelClip, ra.app);
+ };
+ }
+
+ // Only done for new modelClip added to the system
+ if (updateDirty)
+ updateCanvasForDirtyModelClip(modelClips);
+ }
+
+
+ void updateCanvasForDirtyModelClip(ArrayList<ModelClipRetained> modelClips) {
+ int i, j;
+ EnvironmentSet e;
+ int enableMCMaskCache = 0;
+ UnorderList list;
+ EnvironmentSet envsets[];
+ int sz = modelClips.size();
+ int envsize;
+
+ for (i = 0; i < sz; i++) {
+ ModelClipRetained modelClip = modelClips.get(i);
+
+ // evaluate the modelClip enable mask
+ enableMCMaskCache = 0;
+ for (j = 0; j < 6; j++) {
+ if (modelClip.enables[j])
+ enableMCMaskCache |= 1 << j;
+ }
+ list = modelClip.environmentSets;
+ synchronized (list) {
+ envsize = list.size();
+ envsets = (EnvironmentSet []) list.toArray(false);
+ for (j = 0; j < envsize; j++) {
+ e = envsets[j];
+ e.canvasDirty |= Canvas3D.MODELCLIP_DIRTY;
+ e.enableMCMaskCache = enableMCMaskCache;
+ if (!e.onUpdateList) {
+ objUpdateList.add(e);
+ e.onUpdateList = true;
+ }
+ }
+ }
+ }
+ }
+
+ void reEvaluateLights(boolean altAppDirty) {
+ EnvironmentSet e;
+ LightRetained[] lights;
+ int i;
+ AppearanceRetained app;
+ Object[] retVal;
+ int sz = renderAtoms.size();
+ for (i = 0; i < sz; i++) {
+ RenderAtom ra = renderAtoms.get(i);
+ if (!ra.inRenderBin())
+ continue;
+
+ lights = universe.renderingEnvironmentStructure.getInfluencingLights(ra, view);
+ // If the lights of the render atom is the same
+ // as the old set of lights, then move on to the
+ // next renderAtom
+ if (altAppDirty&&ra.geometryAtom.source.appearanceOverrideEnable) {
+ retVal = universe.renderingEnvironmentStructure.getInfluencingAppearance(ra, view);
+ if (retVal[0] == Boolean.TRUE) {
+ app = (AppearanceRetained)retVal[1];
+ }
+ else {
+ app = ra.geometryAtom.source.appearance;
+ }
+
+ if (app == ra.app) {
+ if (ra.lights == lights || ra.envSet.equalLights(lights))
+ continue;
+ else {
+ getNewEnvironment(ra, lights, ra.fog, ra.modelClip, ra.app);
+ }
+ }
+ else {
+ if (ra.geometryAtom.source.otherAppearance != app) {
+ if (ra.geometryAtom.source.otherAppearance != null)
+ ra.geometryAtom.source.otherAppearance.sgApp.removeAMirrorUser(ra.geometryAtom.source);
+ if (app != ra.geometryAtom.source.appearance) {
+ if (app != null) {
+ app.sgApp.addAMirrorUser(ra.geometryAtom.source);
+ }
+ ra.geometryAtom.source.otherAppearance = app;
+ }
+ else {
+ ra.geometryAtom.source.otherAppearance = null;
+ }
+ }
+ if (ra.lights == lights || ra.envSet.equalLights(lights)) {
+ ra.app = app;
+ e = ra.envSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+ else {
+ getNewEnvironment(ra, lights, ra.fog, ra.modelClip, app);
+ }
+ }
+ }
+ else {
+ if (ra.lights == lights || ra.envSet.equalLights(lights))
+ continue;
+ getNewEnvironment(ra, lights, ra.fog, ra.modelClip, ra.app);
+ }
+ }
+ // Only done for new lights added to the system
+ if (changedLts.size() > 0)
+ updateCanvasForDirtyLights(changedLts);
+
+ }
+
+ void updateCanvasForDirtyLights(ArrayList<LightRetained> mLts) {
+ int n, i, j, lmask;
+ EnvironmentSet e;
+ UnorderList list;
+ EnvironmentSet envsets[];
+ int sz = mLts.size();
+ int envsize;
+ int ltsize;
+
+ for (n = 0; n < sz; n++) {
+ LightRetained lt = mLts.get(n);
+ list = lt.environmentSets;
+ synchronized (list) {
+ envsets = (EnvironmentSet []) list.toArray(false);
+ envsize = list.size();
+
+ if (lt.nodeType == LightRetained.AMBIENTLIGHT) {
+ for (i = 0; i < envsize; i++) {
+ e = envsets[i];
+ e.canvasDirty |= Canvas3D.AMBIENTLIGHT_DIRTY;
+ if (!e.onUpdateList) {
+ objUpdateList.add(e);
+ e.onUpdateList = true;
+ }
+ }
+ } else {
+ for (i = 0; i < envsize; i++) {
+ e = envsets[i];
+ lmask = 0;
+ ltsize = e.lights.size();
+ for (j = 0; j < ltsize; j++) {
+ LightRetained curLt = e.lights.get(j);
+ if (lt == curLt) {
+ lmask = (1 << e.ltPos[j]);
+ if (curLt.lightOn == true) {
+ e.enableMaskCache |= (1 << e.ltPos[j]);
+ }
+ else {
+ e.enableMaskCache &= (1 << e.ltPos[j]);
+ }
+ break;
+ }
+ }
+ e.canvasDirty |= Canvas3D.LIGHTENABLES_DIRTY;
+ if (!e.onUpdateList) {
+ objUpdateList.add(e);
+ e.onUpdateList = true;
+ }
+ if(e.lightBin != null) {
+ e.lightBin.canvasDirty |= Canvas3D.LIGHTBIN_DIRTY;
+ e.lightBin.lightDirtyMaskCache |= lmask;
+ if (!e.lightBin.onUpdateList) {
+ e.lightBin.onUpdateList = true;
+ objUpdateList.add(e.lightBin);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void addTextureResourceFreeList(TextureRetained tex) {
+ toBeAddedTextureResourceFreeList.add(tex);
+ }
+
+
+void reEvaluateEnv(ArrayList<LightRetained> mLts, ArrayList<FogRetained> fogs,
+ ArrayList<ModelClipRetained> modelClips,
+ boolean updateDirty, boolean altAppDirty) {
+
+ reEvaluateAllRenderAtoms(altAppDirty);
+
+ // Done only for xform changes, not for bounding leaf change
+ if (updateDirty) {
+ // Update canvases for dirty lights and fog
+ if (mLts.size()> 0)
+ updateCanvasForDirtyLights(mLts);
+ if (fogs.size() > 0)
+ updateCanvasForDirtyFog(fogs);
+ if (modelClips.size() > 0)
+ updateCanvasForDirtyModelClip(modelClips);
+ }
+
+ }
+
+ void updateInfVworldToVpc() {
+ vworldToVpc.getRotation(infVworldToVpc);
+ }
+
+
+ // Lock all geometry before rendering into the any canvas
+ // in the case of display list, for each renderer,
+ // release after building the display list (which happens
+ // for the first canvas rendered)
+ void lockGeometry() {
+ int size;
+
+
+ // Vertex array is locked for every time renderer is run
+ size = lockGeometryList.size();
+ for (int i = 0; i < size; i++) {
+ GeometryRetained geo = lockGeometryList.get(i);
+ geo.geomLock.getLock();
+ }
+
+ // dlist is locked only when they are rebuilt
+ size = dlistLockList.size();
+ for (int i = 0; i < size ; i++) {
+ GeometryRetained geo = (GeometryRetained) dlistLockList.get(i);
+ geo.geomLock.getLock();
+
+ }
+
+ // Lock all the by reference image components
+ size = nodeComponentList.size();
+ for (int i = 0; i < size; i++) {
+ ImageComponentRetained nc = (ImageComponentRetained)nodeComponentList.get(i);
+ nc.geomLock.getLock();
+ }
+ }
+
+ // Release all geometry after rendering to the last canvas
+ void releaseGeometry() {
+ int size;
+
+ size = lockGeometryList.size();
+ for (int i = 0; i < size; i++) {
+ GeometryRetained geo = lockGeometryList.get(i);
+ geo.geomLock.unLock();
+ }
+
+ size = dlistLockList.size();
+ for (int i = 0; i < size; i++) {
+ GeometryRetained geo = (GeometryRetained) dlistLockList.get(i);
+ geo.geomLock.unLock();
+ }
+ // Clear the display list clear list
+ dlistLockList.clear();
+ // Lock all the by reference image components
+ size = nodeComponentList.size();
+ for (int i = 0; i < size; i++) {
+ ImageComponentRetained nc = (ImageComponentRetained)nodeComponentList.get(i);
+ nc.geomLock.unLock();
+ }
+ }
+
+ void addGeometryToLockList(GeometryRetained geo) {
+ // just add it to the list, if its a shared geometry
+ // it may be added more than once, thats OK since we
+ // now have nested locks!
+ lockGeometryList.add(geo);
+ }
+
+ void removeGeometryFromLockList(GeometryRetained geo) {
+ lockGeometryList.remove(geo);
+
+ }
+
+
+void addDirtyReferenceGeometry(GeometryArrayRetained geo) {
+ // just add it to the list, if its a shared geometry
+ // it may be added more than once, thats OK since we
+ // now have nested locks!
+ dirtyReferenceGeomList.add(geo);
+}
+
+
+ void addNodeComponent(Object nc) {
+ newNodeComponentList.add(nc);
+ }
+
+ void removeNodeComponent (Object nc) {
+ removeNodeComponentList.add(nc);
+ }
+
+ void addDirtyNodeComponent(NodeComponentRetained nc) {
+ dirtyNodeComponentList.add(nc);
+ }
+
+
+ void clearDirtyOrientedRAs() {
+ int i, nRAs;
+ RenderAtom ra;
+ nRAs = dirtyOrientedRAs.size();
+
+ // clear the dirtyMask
+ for(i=0; i<nRAs; i++) {
+ ra = dirtyOrientedRAs.get(i);
+ ra.dirtyMask &= ~RenderAtom.IN_DIRTY_ORIENTED_RAs;
+ }
+ dirtyOrientedRAs.clear();
+ }
+
+ // Called from MasterControl when viewCache changes or if there are
+ // dirtyOrientedShapes
+ void updateOrientedRAs() {
+ int i, nRAs;
+ Canvas3D cv = null;
+ RenderAtom ra;
+ OrientedShape3DRetained os;
+
+ // Issue 562 : use cached list of canvases to avoid index OOB exception
+ Canvas3D[] canvases = view.getCanvases();
+ if (canvases.length > 0) {
+ cv = canvases[0];
+ }
+
+ if (cv != null) {
+ if (view.viewCache.vcDirtyMask != 0) {
+ nRAs = orientedRAs.size();
+
+ // Update ra's localToVworld given orientedTransform
+ // Mark Oriented shape as dirty, since multiple ra could point
+ // to the same OrientShape3D, compute the xform only once
+ for(i=0; i<nRAs; i++) {
+ ra = orientedRAs.get(i);
+ os = (OrientedShape3DRetained)ra.geometryAtom.source;
+ os.orientedTransformDirty = true;
+ }
+ // Update ra's localToVworld given orientedTransform
+ for(i=0; i<nRAs; i++) {
+ ra = orientedRAs.get(i);
+ os = (OrientedShape3DRetained)ra.geometryAtom.source;
+ if (os.orientedTransformDirty) {
+ os.updateOrientedTransform(cv, view.viewIndex);
+ os.orientedTransformDirty = false;
+ }
+ ra.updateOrientedTransform();
+ }
+ } else {
+ nRAs = cachedDirtyOrientedRAs.size();
+ // Update ra's localToVworld given orientedTransform
+ // Mark Oriented shape as dirty, since multiple ra could point
+ // to the same OrientShape3D, compute the xform only once
+ for(i=0; i<nRAs; i++) {
+ ra = cachedDirtyOrientedRAs.get(i);
+ os = (OrientedShape3DRetained)ra.geometryAtom.source;
+ os.orientedTransformDirty = true;
+ }
+ // Update ra's localToVworld given orientedTransform
+ for(i=0; i<nRAs; i++) {
+ ra = cachedDirtyOrientedRAs.get(i);
+ os = (OrientedShape3DRetained)ra.geometryAtom.source;
+ if (os.orientedTransformDirty) {
+ os.updateOrientedTransform(cv, view.viewIndex);
+ os.orientedTransformDirty = false;
+
+ }
+ ra.updateOrientedTransform();
+ }
+ }
+ }
+ cachedDirtyOrientedRAs.clear();
+
+ }
+
+
+ // This removes a renderAtom and also does the necessary changes
+ // for a orientShape3D
+ void removeARenderAtom(RenderAtom ra) {
+ // System.err.println("===> remove ga = "+ra.geometryAtom);
+ ra.setRenderBin(false);
+ ra.renderMolecule.removeRenderAtom(ra);
+ if (ra.inDirtyOrientedRAs()) {
+ dirtyOrientedRAs.remove(ra);
+ ra.dirtyMask &= ~RenderAtom.IN_DIRTY_ORIENTED_RAs;
+ }
+ if (ra.inDepthSortList()) {
+ dirtyDepthSortRenderAtom.remove(ra);
+ ra.dirtyMask &= ~RenderAtom.IN_SORTED_POS_DIRTY_TRANSP_LIST;
+ numDirtyTinfo -= ra.rListInfo.length;
+ }
+
+ // Assertion check in debug mode
+ if (VersionInfo.isDebug && dirtyDepthSortRenderAtom.contains(ra)) {
+ System.err.println("removeARenderAtom: ERROR: RenderAtom not removed from dirty list");
+ }
+ }
+
+ void removeAllRenderAtoms() {
+ int i;
+ RenderMolecule rm;
+ int sz = renderAtoms.size();
+
+ for (i = 0; i < sz; i++) {
+ RenderAtom ra = renderAtoms.get(i);
+ rm = ra.renderMolecule;
+ removeARenderAtom(ra);
+ rm.updateRemoveRenderAtoms();
+ }
+ renderAtoms.clear();
+
+ clearAllUpdateObjectState();
+
+ // Clear the arrayList that are kept from one frame to another
+ renderMoleculeList.clear();
+ sharedDList.clear();
+ lockGeometryList.clear();
+ // clear out this orderedBin's entry in the orderedGroup
+ for (i = 0; i < orderedBins.size(); i++) {
+ removeOrderedBin(orderedBins.get(i));
+ }
+ orderedBins.clear();
+ bgOrderedBins.clear();
+ nodeComponentList.clear();
+ orientedRAs.clear();
+
+ // clean up any messages that are queued up, since they are
+ // irrelevant
+ // clearMessages();
+ geometryBackground = null;
+ }
+
+ void removeOrderedBin(OrderedBin ob) {
+ int i, k;
+ for (i = 0; i < ob.orderedCollections.size(); i++) {
+ OrderedCollection oc = ob.orderedCollections.get(i);
+ if (oc == null)
+ continue;
+
+ for (k = 0; k < oc.childOrderedBins.size(); k++) {
+ removeOrderedBin(oc.childOrderedBins.get(k));
+ }
+ }
+ if (ob.source != null) {
+ ob.source.setOrderedBin(null, view.viewIndex);
+ ob.source = null;
+ }
+ }
+
+
+void removeGeometryDlist(RenderAtomListInfo ra) {
+ removeDlist.add(ra);
+}
+
+void addGeometryDlist(RenderAtomListInfo ra) {
+ addDlist.add(ra);
+}
+
+ void dumpBin(LightBin bin) {
+ LightBin obin = bin;
+ while (obin != null) {
+ System.err.println("LightBin = "+obin);
+ EnvironmentSet envSet = obin.environmentSetList;
+ while (envSet != null) {
+ System.err.println(" EnvSet = "+envSet);
+ AttributeBin abin = envSet.attributeBinList;
+ while (abin != null) {
+ System.err.println(" ABin = "+abin);
+ ShaderBin sbin = abin.shaderBinList;
+ while (sbin != null) {
+ System.err.println(" SBin = "+sbin);
+ TextureBin tbin = sbin.textureBinList;
+ while (tbin != null) {
+ System.err.println(" Tbin = "+tbin);
+ RenderMolecule rm = tbin.opaqueRMList;
+ System.err.println("===> Begin Dumping OpaqueBin");
+ dumpRM(rm);
+ System.err.println("===> End Dumping OpaqueBin");
+ rm = tbin.transparentRMList;
+ System.err.println("===> Begin Dumping transparentBin");
+ dumpRM(rm);
+ System.err.println("===> End Dumping transparentBin");
+ tbin = tbin.next;
+ }
+ sbin = sbin.next;
+ }
+ abin = abin.next;
+ }
+ envSet = envSet.next;
+ }
+ obin = obin.next;
+ }
+
+ }
+
+ void dumpRM(RenderMolecule rm) {
+ while (rm != null) {
+ System.err.println(" rm = "+rm+" numRAs = "+rm.numRenderAtoms);
+ System.err.println(" primaryRenderAtomList = "+
+ rm.primaryRenderAtomList);
+ RenderAtomListInfo rinfo = rm.primaryRenderAtomList;
+ while (rinfo != null) {
+ System.err.println(" rinfo = "+rinfo);
+ System.err.println(" rinfo.ra.localeVwcBounds = "
+ + rinfo.renderAtom.localeVwcBounds);
+ System.err.println(" rinfo.ra.ga.so.vwcBounds = "
+ + rinfo.renderAtom.geometryAtom.source.vwcBounds);
+ System.err.println(" geometry = "+rinfo.geometry());
+
+ rinfo = rinfo.next;
+ }
+ System.err.println(" separateDlistRenderAtomList = "+
+ rm.separateDlistRenderAtomList);
+ rinfo = rm.separateDlistRenderAtomList;
+ while (rinfo != null) {
+ System.err.println(" rinfo = "+rinfo);
+ System.err.println(" rinfo.ra.localeVwcBounds = "
+ + rinfo.renderAtom.localeVwcBounds);
+ System.err.println(" rinfo.ra.ga.so.vwcBounds = "
+ + rinfo.renderAtom.geometryAtom.source.vwcBounds);
+ System.err.println(" geometry = "+rinfo.geometry());
+ rinfo = rinfo.next;
+ }
+ System.err.println(" vertexArrayRenderAtomList = "+
+ rm.vertexArrayRenderAtomList);
+ if (rm.next == null) {
+ rm= rm.nextMap;
+ }
+ else {
+ rm = rm.next;
+ }
+ }
+ }
+
+ void removeTransparentObject (Object obj) {
+ // System.err.println("&&&&&&&&&&&&removeTransparentObject r = "+obj);
+ if (obj instanceof TextureBin) {
+ TextureBin tb = (TextureBin) obj;
+ if (tb.environmentSet.lightBin.geometryBackground != null) {
+ TransparentRenderingInfo t = tb.parentTInfo;
+
+ // Remove the element from the transparentInfo struct
+ if (t == bgTransparentInfo) {
+ bgTransparentInfo = bgTransparentInfo.next;
+ if (bgTransparentInfo != null)
+ bgTransparentInfo.prev = null;
+ }
+ else {
+ t.prev.next = t.next;
+ if (t.next != null)
+ t.next.prev = t.prev;
+ }
+ t.prev = null;
+ t.next = null;
+ tb.parentTInfo = null;
+ }
+ else {
+ int index = allTransparentObjects.indexOf(obj);
+ if (index == -1) {
+ // System.err.println("==> DEBUG1: Should never come here!");
+ return;
+ }
+ allTransparentObjects.remove(index);
+
+ TransparentRenderingInfo t = tb.parentTInfo;
+
+ // Remove the element from the transparentInfo struct
+ if (t == transparentInfo) {
+ transparentInfo = transparentInfo.next;
+ if (transparentInfo != null)
+ transparentInfo.prev = null;
+ }
+ else {
+ t.prev.next = t.next;
+ if (t.next != null)
+ t.next.prev = t.prev;
+ }
+ t.prev = null;
+ t.next = null;
+ tb.parentTInfo = null;
+ }
+
+ }
+ else {
+ int index = allTransparentObjects.indexOf(obj);
+ if (index == -1) {
+ // System.err.println("==> DEBUG2: Should never come here!");
+ return;
+ }
+
+ allTransparentObjects.remove(index);
+ RenderAtom r = (RenderAtom)obj;
+ for (int i = 0; i < r.parentTInfo.length; i++) {
+ // Remove the element from the transparentInfo struct
+ TransparentRenderingInfo t = r.parentTInfo[i];
+ // This corresponds to null geometry
+ if (t == null)
+ continue;
+
+ // Remove the element from the transparentInfo struct
+ if (t == transparentInfo) {
+ transparentInfo = transparentInfo.next;
+ if (transparentInfo != null)
+ transparentInfo.prev = null;
+ }
+ else {
+ t.prev.next = t.next;
+ if (t.next != null)
+ t.next.prev = t.prev;
+ }
+ t.prev = null;
+ t.next = null;
+ nElements--;
+ r.parentTInfo[i] = null;
+ }
+ }
+
+ }
+
+ void updateTransparentInfo(RenderAtom r) {
+ // System.err.println("===> update transparent Info");
+ for (int i = 0; i < r.parentTInfo.length; i++) {
+
+ if (r.parentTInfo[i] == null)
+ continue;
+ /*
+ r.parentTInfo[i].lightBin = r.envSet.lightBin;
+ r.parentTInfo[i].envSet = r.envSet;
+ r.parentTInfo[i].aBin = r.renderMolecule.textureBin.attributeBin;
+ */
+ r.parentTInfo[i].rm = r.renderMolecule;
+ }
+ }
+
+ void addTransparentObject (Object obj) {
+ // System.err.println("&&&&&&&&&&&&addTransparentObject r = "+obj);
+ if (obj instanceof TextureBin) {
+ TextureBin tb = (TextureBin) obj;
+ // Background geometry
+ if (tb.environmentSet.lightBin.geometryBackground != null) {
+ bgTransparentInfo = computeDirtyAcrossTransparentBins(tb, bgTransparentInfo);
+ }
+ else {
+ allTransparentObjects.add(obj);
+ transparentInfo = computeDirtyAcrossTransparentBins(tb, transparentInfo);
+ }
+ }
+ else {
+ allTransparentObjects.add(obj);
+ RenderAtom r = (RenderAtom)obj;
+ if (r.parentTInfo == null) {
+ r.parentTInfo = new TransparentRenderingInfo[r.rListInfo.length];
+ }
+ computeDirtyAcrossTransparentBins(r);
+ // System.err.println("update Centroid 2, ga = "+r.geometryAtom);
+ r.geometryAtom.updateCentroid();
+ if (dirtyDepthSortRenderAtom.add(r)) {
+ numDirtyTinfo += r.rListInfo.length;
+ }
+ /*
+ else {
+ System.err.println("addTransparentObject: attempt to add RenderAtom already in dirty list");
+ }
+ */
+ r.dirtyMask |= RenderAtom.IN_SORTED_POS_DIRTY_TRANSP_LIST;
+ // System.err.println("transparentInfo ="+transparentInfo);
+ }
+ }
+
+ TransparentRenderingInfo getTransparentInfo() {
+ return new TransparentRenderingInfo();
+ }
+
+ TransparentRenderingInfo computeDirtyAcrossTransparentBins(TextureBin tb, TransparentRenderingInfo startinfo) {
+ TransparentRenderingInfo tinfo = getTransparentInfo();
+ /*
+ tinfo.lightBin = tb.environmentSet.lightBin;
+ tinfo.envSet = tb.environmentSet;
+ tinfo.aBin = tb.attributeBin;
+ */
+ tinfo.rm = tb.transparentRMList;
+ tb.parentTInfo = tinfo;
+ if (startinfo == null) {
+ startinfo = tinfo;
+ tinfo.prev = null;
+ tinfo.next = null;
+
+ }
+ else {
+ tinfo.next = startinfo;
+ startinfo.prev = tinfo;
+ startinfo = tinfo;
+ }
+ return startinfo;
+ }
+ void computeDirtyAcrossTransparentBins(RenderAtom r) {
+
+ for (int i = 0; i < r.parentTInfo.length; i++) {
+ if (r.rListInfo[i].geometry() == null) {
+ r.parentTInfo[i] = null;
+ continue;
+ }
+ nElements++;
+ TransparentRenderingInfo tinfo = getTransparentInfo();
+ /*
+ tinfo.lightBin = r.envSet.lightBin;
+ tinfo.envSet = r.envSet;
+ tinfo.aBin = r.renderMolecule.textureBin.attributeBin;
+ */
+ tinfo.rm = r.renderMolecule;
+ tinfo.rInfo = r.rListInfo[i];
+ r.parentTInfo[i] = tinfo;
+ if (transparentInfo == null) {
+ transparentInfo = tinfo;
+ tinfo.prev = null;
+ tinfo.next = null;
+ }
+ else {
+ tinfo.prev = null;
+ tinfo.next = transparentInfo;
+ transparentInfo.prev = tinfo;
+ transparentInfo = tinfo;
+ }
+
+ }
+
+ }
+
+ void processRenderAtomTransparentInfo(RenderAtomListInfo rinfo, ArrayList newList) {
+ while (rinfo != null) {
+ // If either the renderAtom has never been in transparent mode
+ // or if it was previously in that mode and now going back
+ // to that mode
+ if (rinfo.renderAtom.parentTInfo == null) {
+ rinfo.renderAtom.parentTInfo = new TransparentRenderingInfo[rinfo.renderAtom.rListInfo.length];
+ computeDirtyAcrossTransparentBins(rinfo.renderAtom);
+ rinfo.renderAtom.geometryAtom.updateCentroid();
+ newList.add(rinfo.renderAtom);
+ }
+ else {
+ GeometryRetained geo = null;
+ int i = 0;
+ while (geo == null && i < rinfo.renderAtom.rListInfo.length) {
+ geo = rinfo.renderAtom.rListInfo[i].geometry();
+ i++;
+ }
+ // If there is atleast one non-null geometry in this renderAtom
+ if (geo != null) {
+ if (rinfo.renderAtom.parentTInfo[i-1] == null) {
+ computeDirtyAcrossTransparentBins(rinfo.renderAtom);
+ rinfo.renderAtom.geometryAtom.updateCentroid();
+ newList.add(rinfo.renderAtom);
+ }
+ }
+ }
+ rinfo = rinfo.next;
+
+ }
+ }
+
+ void convertTransparentRenderingStruct(int oldMode, int newMode) {
+ int i, size;
+ ArrayList newList = new ArrayList(5);
+ RenderAtomListInfo rinfo;
+ // Reset the transparentInfo;
+ transparentInfo = null;
+ if (oldMode == View.TRANSPARENCY_SORT_NONE && newMode == View.TRANSPARENCY_SORT_GEOMETRY) {
+ size = allTransparentObjects.size();
+
+ for (i = 0; i < size; i++) {
+ TextureBin tb = (TextureBin)allTransparentObjects.get(i);
+ tb.parentTInfo = null;
+ RenderMolecule r = tb.transparentRMList;
+ // For each renderMolecule
+ while (r != null) {
+ // If this was a dlist molecule, since we will be rendering
+ // as separate dlist per rinfo, destroy the display list
+ if ((r.primaryMoleculeType &RenderMolecule.DLIST_MOLECULE) != 0) {
+ // System.err.println("&&&&&&&&& changing from dlist to dlist_per_rinfo");
+ addDisplayListResourceFreeList(r);
+ removeDirtyRenderMolecule(r);
+
+ r.vwcBounds.set(null);
+ r.displayListId = 0;
+ r.displayListIdObj = null;
+ // Change the group type for all the rlistInfo in the primaryList
+ rinfo = r.primaryRenderAtomList;
+ while (rinfo != null) {
+ rinfo.groupType = RenderAtom.SEPARATE_DLIST_PER_RINFO;
+ if (rinfo.renderAtom.dlistIds == null) {
+ rinfo.renderAtom.dlistIds = new int[rinfo.renderAtom.rListInfo.length];
+
+ for (int k = 0; k < rinfo.renderAtom.dlistIds.length; k++) {
+ rinfo.renderAtom.dlistIds[k] = -1;
+ }
+ }
+ if (rinfo.renderAtom.dlistIds[rinfo.index] == -1) {
+ rinfo.renderAtom.dlistIds[rinfo.index] = VirtualUniverse.mc.getDisplayListId().intValue();
+ addDlistPerRinfo.add(rinfo);
+ }
+ rinfo = rinfo.next;
+ }
+ r.primaryMoleculeType = RenderMolecule.SEPARATE_DLIST_PER_RINFO_MOLECULE;
+ }
+ // Get all the renderAtoms in the list
+ processRenderAtomTransparentInfo(r.primaryRenderAtomList, newList);
+ processRenderAtomTransparentInfo(r.vertexArrayRenderAtomList, newList);
+ processRenderAtomTransparentInfo(r.separateDlistRenderAtomList, newList);
+ if (r.next == null) {
+ r = r.nextMap;
+ }
+ else {
+ r = r.next;
+ }
+ }
+ }
+ allTransparentObjects = newList;
+ }
+ else if (oldMode == View.TRANSPARENCY_SORT_GEOMETRY && newMode == View.TRANSPARENCY_SORT_NONE) {
+ // System.err.println("oldMode = TRANSPARENCY_SORT_GEOMETRY, newMode = TRANSPARENCY_SORT_NONE");
+ size = allTransparentObjects.size();
+ for (i = 0; i < size; i++) {
+ RenderAtom r= (RenderAtom)allTransparentObjects.get(i);
+ r.dirtyMask &= ~RenderAtom.IN_SORTED_POS_DIRTY_TRANSP_LIST;
+ for (int j = 0; j < r.parentTInfo.length; j++) {
+ // Corresponds to null geometry
+ if (r.parentTInfo[j] == null)
+ continue;
+
+ r.parentTInfo[j] = null;
+ }
+ if (r.renderMolecule.textureBin.parentTInfo == null) {
+ transparentInfo = computeDirtyAcrossTransparentBins(r.renderMolecule.textureBin, transparentInfo);
+ newList.add(r.renderMolecule.textureBin);
+ }
+ }
+ allTransparentObjects = newList;
+ dirtyDepthSortRenderAtom.clear();
+ numDirtyTinfo = 0;
+ }
+ }
+
+ TransparentRenderingInfo mergeDepthSort(TransparentRenderingInfo oldList, TransparentRenderingInfo newList) {
+ TransparentRenderingInfo input1 = oldList , input2 = newList, nextN;
+ TransparentRenderingInfo lastInput1 = oldList;
+ double zval1, zval2;
+ // System.err.println("&&&&&&&&mergeDepthSort");
+ /*
+ TransparentRenderingInfo t = oldList;
+ System.err.println("");
+ while (t != null) {
+ System.err.println("==> old t = "+t);
+ t = t.next;
+ }
+ System.err.println("");
+ t = newList;
+ while (t != null) {
+ System.err.println("==> new t = "+t);
+ t = t.next;
+ }
+ */
+
+ while (input1 != null && input2 != null) {
+ lastInput1 = input1;
+ nextN = input2.next;
+ zval1 = input1.zVal;
+ zval2 = input2.zVal;
+ // Put the newList before the current one
+
+// System.err.print("Code path 1 ");
+// if (transparencySortComparator!=null)
+// if (zval2 > zval1 && (transparencySortComparator.compare(input2, input1)>0))
+// System.err.println("PASS");
+// else
+// System.err.println("FAIL");
+
+ if ((transparencySortComparator==null && zval2 > zval1) ||
+ (transparencySortComparator!=null && (transparencySortComparator.compare(input2, input1)>0))){
+ // System.err.println("===> path1");
+ if (input1.prev == null) {
+ input1.prev = input2;
+ input2.prev = null;
+ input2.next = oldList;
+ oldList = input2;
+ }
+ else {
+ // System.err.println("===> path2");
+ input2.prev = input1.prev;
+ input1.prev.next = input2;
+ input2.next = input1;
+ input1.prev = input2;
+ }
+ input2 = nextN;
+ }
+ else {
+ // System.err.println("===> path3");
+ input1 = input1.next;
+ }
+ }
+ if (input1 == null && input2 != null) {
+ // add at then end
+ if (lastInput1 == null) {
+ oldList = input2;
+ input2.prev = null;
+ }
+ else {
+ lastInput1.next = input2;
+ input2.prev = lastInput1;
+ }
+ }
+ return oldList;
+ }
+
+// void insertDepthSort(RenderAtom r) {
+// TransparentRenderingInfo tinfo = null;
+// // System.err.println("&&&&&&&&insertDepthSort");
+// for (int i = 0; i < r.rListInfo.length; i++) {
+// if (r.parentTInfo[i] == null)
+// continue;
+//
+// if (transparentInfo == null) {
+// transparentInfo = r.parentTInfo[i];
+// transparentInfo.prev = null;
+// transparentInfo.next = null;
+// }
+// else {
+// tinfo = transparentInfo;
+// TransparentRenderingInfo prevInfo = transparentInfo;
+// if (transparencySortComparator==null)
+// while (tinfo != null && r.parentTInfo[i].zVal < tinfo.zVal) {
+// prevInfo = tinfo;
+// tinfo = tinfo.next;
+// }
+// else {
+// System.err.println("Code Path 2 ");
+// if (tinfo!=null && (transparencySortComparator.compare(r.parentTInfo[i], tinfo)<0)==r.parentTInfo[i].zVal < tinfo.zVal)
+// System.err.println("PASS");
+// else
+// System.err.println("FAIL");
+// while (tinfo != null && transparencySortComparator.compare(r.parentTInfo[i], tinfo)<0) {
+// prevInfo = tinfo;
+// tinfo = tinfo.next;
+// }
+// }
+// r.parentTInfo[i].prev = prevInfo;
+// if (prevInfo.next != null) {
+// prevInfo.next.prev = r.parentTInfo[i];
+// }
+// r.parentTInfo[i].next = prevInfo.next;
+// prevInfo.next = r.parentTInfo[i];
+//
+// }
+//
+// }
+// }
+
+ TransparentRenderingInfo collectDirtyTRInfo( TransparentRenderingInfo dirtyList,
+ RenderAtom r) {
+
+ for (int i = 0; i < r.rListInfo.length; i++) {
+ TransparentRenderingInfo t = r.parentTInfo[i];
+ if (t == null)
+ continue;
+ if (t == transparentInfo) {
+ transparentInfo = transparentInfo.next;
+ if (transparentInfo != null)
+ transparentInfo.prev = null;
+ }
+ else {
+ if (t == dirtyList) {
+ // This means that the the item has already been
+ // added to the dirtyList and is at the head of
+ // the list; since we ensure no duplicate
+ // renderAtoms, this should never happen. If it
+ // does, don't try to add it again.
+ System.err.println("collectDirtyTRInfo: ERROR: t == dirtyList");
+ continue;
+ }
+
+ // assert(t.prev != null);
+ t.prev.next = t.next;
+ if (t.next != null)
+ t.next.prev = t.prev;
+ }
+ if (dirtyList == null) {
+ dirtyList = t;
+ t.prev = null;
+ t.next = null;
+ } else {
+ t.next = dirtyList;
+ t.prev = null;
+ dirtyList.prev = t;
+ dirtyList = t;
+ }
+ }
+
+ return dirtyList;
+ }
+
+
+ TransparentRenderingInfo depthSortAll(TransparentRenderingInfo startinfo) {
+ transparencySortComparator = TransparencySortMap.getComparator(view);
+ TransparentRenderingInfo tinfo, previnfo, nextinfo;
+ double curZ;
+ // System.err.println("&&&&&&&&&&&depthSortAll");
+ // Do insertion sort
+ /*
+ tinfo = startinfo;
+ while (tinfo != null) {
+ System.err.println("Soreted tinfo= "+tinfo+" tinfo.prev = "+tinfo.prev+" tinfo.next = "+tinfo.next);
+ tinfo = tinfo.next;
+ }
+ */
+ tinfo = startinfo.next;
+ while (tinfo != null) {
+ // System.err.println("====> Doing tinfo = "+tinfo);
+ nextinfo = tinfo.next;
+ curZ = tinfo.zVal;
+ previnfo = tinfo.prev;
+ // Find the correct location for tinfo
+
+ if (transparencySortComparator==null) {
+ while (previnfo != null && previnfo.zVal < curZ) {
+ previnfo = previnfo.prev;
+ }
+ } else {
+// System.err.println("Code Path 3 ");
+// if (tinfo!=null && (transparencySortComparator.compare(previnfo, tinfo)<0)==previnfo.zVal < curZ)
+// System.err.println("PASS");
+// else
+// System.err.println("FAIL");
+ while (previnfo != null && transparencySortComparator.compare(previnfo,tinfo)<0) {
+ previnfo = previnfo.prev;
+ }
+ }
+
+ if (tinfo.prev != previnfo) {
+ if (previnfo == null) {
+ if (tinfo.next != null) {
+ tinfo.next.prev = tinfo.prev;
+ }
+ // tinfo.prev is not null
+ tinfo.prev.next = tinfo.next;
+ tinfo.next = startinfo;
+ startinfo.prev = tinfo;
+ startinfo = tinfo;
+ tinfo.prev = null;
+ }
+ else {
+ if (tinfo.next != null) {
+ tinfo.next.prev = tinfo.prev;
+ }
+ if (tinfo.prev != null) {
+ tinfo.prev.next = tinfo.next;
+ }
+ tinfo.next = previnfo.next;
+ if (previnfo.next != null)
+ previnfo.next.prev = tinfo;
+ tinfo.prev = previnfo;
+ previnfo.next = tinfo;
+ // System.err.println("path2, tinfo.prev = "+tinfo.prev);
+ // System.err.println("path2, tinfo.next = "+tinfo.next);
+ }
+
+ }
+ /*
+ TransparentRenderingInfo tmp = startinfo;
+ while (tmp != null) {
+ System.err.println("Soreted tmp= "+tmp+" tmp.prev = "+tmp.prev+" tmp.next = "+tmp.next);
+ tmp = tmp.next;
+ }
+ */
+
+ tinfo = nextinfo;
+
+ }
+ /*
+ tinfo = startinfo;
+ double prevZ = 0.0;
+ while (tinfo != null) {
+ tinfo.render = false;
+ curZ = ((double[])distMap.get(tinfo.rInfo.renderAtom))[tinfo.rInfo.index];
+ nextinfo = tinfo.next;
+ if (nextinfo != null) {
+ double nextZ = ((double[])distMap.get(nextinfo.rInfo.renderAtom))[tinfo.rInfo.index];
+ if (Math.abs(curZ - nextZ) < 1.0e-6 && curZ < 400) {
+ tinfo.render = true;
+ }
+ }
+
+ if (Math.abs(curZ - prevZ) < 1.0e-6 && curZ < 400) {
+ tinfo.render = true;
+ }
+
+ prevZ = curZ;
+ tinfo = tinfo.next;
+
+ }
+ tinfo = startinfo;
+ while (tinfo != null) {
+ System.err.println("z = "+((double[])distMap.get(tinfo.rInfo.renderAtom))[tinfo.rInfo.index]+" ga = "+tinfo.rInfo.renderAtom.geometryAtom);
+ tinfo = tinfo.next;
+ }
+ System.err.println("\n\n");
+ tinfo = startinfo;
+ while (tinfo != null) {
+ if (tinfo.render) {
+ System.err.println("same z = "+((double[])distMap.get(tinfo.rInfo.renderAtom))[tinfo.rInfo.index]+" ga = "+tinfo.rInfo.renderAtom.geometryAtom);
+ GeometryAtom ga = tinfo.rInfo.renderAtom.geometryAtom;
+ System.err.println("ga.geometryArray.length = "+ga.geometryArray.length);
+ for (int k = 0; k < ga.geometryArray.length; k++) {
+ System.err.println("geometry "+k+" = "+ga.geometryArray[k]);
+ if (ga.geometryArray[k] != null) {
+ System.err.println(" vcount = "+((GeometryArrayRetained)ga.geometryArray[k]).getVertexCount());
+ ((GeometryArrayRetained)ga.geometryArray[k]).printCoordinates();
+ }
+ }
+ }
+ tinfo = tinfo.next;
+ }
+ */
+ return startinfo;
+ }
+
+ void processViewSpecificGroupChanged(J3dMessage m) {
+ int component = ((Integer)m.args[0]).intValue();
+ Object[] objAry = (Object[])m.args[1];
+ if (((component & ViewSpecificGroupRetained.ADD_VIEW) != 0) ||
+ ((component & ViewSpecificGroupRetained.SET_VIEW) != 0)) {
+ int i;
+ Object obj;
+ View v = (View)objAry[0];
+ ArrayList leafList = (ArrayList)objAry[2];
+ // View being added is this view
+ if (v == view) {
+ int size = leafList.size();
+ for (i = 0; i < size; i++) {
+ obj = leafList.get(i);
+ if (obj instanceof LightRetained) {
+ envDirty |= REEVALUATE_LIGHTS;
+ if (!changedLts.contains(obj))
+ changedLts.add((LightRetained)obj);
+ }
+ else if (obj instanceof FogRetained) {
+ envDirty |= REEVALUATE_FOG;
+ if (!changedFogs.contains(obj))
+ changedFogs.add((FogRetained)obj);
+ }
+ else if (obj instanceof AlternateAppearanceRetained) {
+ altAppearanceDirty = true;
+
+ }
+ else if (obj instanceof ModelClipRetained) {
+ envDirty |= REEVALUATE_MCLIP;
+ if (!changedModelClips.contains(obj))
+ changedModelClips.add((ModelClipRetained)obj);
+ }
+ else if (obj instanceof BackgroundRetained) {
+ reEvaluateBg = true;
+ }
+
+ else if (obj instanceof ClipRetained) {
+ reEvaluateClip = true;
+
+ } else if (obj instanceof GeometryAtom) {
+ visGAIsDirty = true;
+ visQuery = true;
+ }
+ }
+
+ }
+
+ }
+ if (((component & ViewSpecificGroupRetained.REMOVE_VIEW) != 0)||
+ ((component & ViewSpecificGroupRetained.SET_VIEW) != 0)) {
+ int i;
+ Object obj;
+ ArrayList leafList;
+ View v;
+
+ if ((component & ViewSpecificGroupRetained.REMOVE_VIEW) != 0) {
+ v = (View)objAry[0];
+ leafList = (ArrayList)objAry[2];
+ }
+ else {
+ v = (View)objAry[4];
+ leafList = (ArrayList)objAry[6];
+ }
+ if (v == view) {
+ int size = leafList.size();
+ for (i = 0; i < size; i++) {
+ obj = leafList.get(i);
+ if (obj instanceof GeometryAtom) {
+ RenderAtom ra = ((GeometryAtom)obj).getRenderAtom(view);
+ if (ra != null && ra.inRenderBin()) {
+ renderAtoms.remove(renderAtoms.indexOf(ra));
+ removeARenderAtom(ra);
+ }
+ }
+ else if (obj instanceof LightRetained) {
+ envDirty |= REEVALUATE_LIGHTS;
+ }
+ else if (obj instanceof FogRetained) {
+ envDirty |= REEVALUATE_FOG;
+ }
+ else if (obj instanceof AlternateAppearanceRetained) {
+ altAppearanceDirty = true;
+
+ }
+ else if (obj instanceof ModelClipRetained) {
+ envDirty |= REEVALUATE_MCLIP;
+
+ }
+ else if (obj instanceof BackgroundRetained) {
+ reEvaluateBg = true;
+ }
+
+ else if (obj instanceof ClipRetained) {
+ reEvaluateClip = true;
+
+ }
+ }
+ }
+ }
+
+ }
+
+void insertNodes(J3dMessage m) {
+ ArrayList<NodeRetained> viewScopedNodes = (ArrayList<NodeRetained>)m.args[3];
+ ArrayList<ArrayList<View>> scopedNodesViewList = (ArrayList<ArrayList<View>>)m.args[4];
+ int i;
+ Object[] nodes = (Object[])m.args[0];
+ for (Object n : nodes) {
+ if (n instanceof LightRetained) {
+ envDirty |= REEVALUATE_LIGHTS;
+ if (!changedLts.contains(n))
+ changedLts.add((LightRetained)n);
+ }
+ else if (n instanceof FogRetained) {
+ envDirty |= REEVALUATE_FOG;
+ if (!changedFogs.contains(n))
+ changedFogs.add((FogRetained)n);
+ }
+ else if (n instanceof BackgroundRetained) {
+ // If a new background is inserted, then
+ // re_evaluate to determine if this background
+ // should be used
+ reEvaluateBg = true;
+ }
+ else if (n instanceof ClipRetained) {
+ reEvaluateClip = true;
+ }
+ else if (n instanceof ModelClipRetained) {
+ envDirty |= REEVALUATE_MCLIP;
+ if (!changedModelClips.contains(n))
+ changedModelClips.add((ModelClipRetained)n);
+ }
+ else if (n instanceof GeometryAtom) {
+ visGAIsDirty = true;
+ visQuery = true;
+ }
+ else if (n instanceof AlternateAppearanceRetained) {
+ altAppearanceDirty = true;
+ }
+ }
+
+ // Handle ViewScoped Nodes
+ if (viewScopedNodes != null) {
+ int size = viewScopedNodes.size();
+ for (i = 0; i < size; i++) {
+ NodeRetained n = viewScopedNodes.get(i);
+ ArrayList<View> vl = scopedNodesViewList.get(i);
+ // If the node object is scoped to this view, then ..
+ if (vl.contains(view)) {
+ if (n instanceof LightRetained) {
+ envDirty |= REEVALUATE_LIGHTS;
+ if (!changedLts.contains(n))
+ changedLts.add((LightRetained)n);
+ }
+ else if (n instanceof FogRetained) {
+ envDirty |= REEVALUATE_FOG;
+ if (!changedFogs.contains(n))
+ changedFogs.add((FogRetained)n);
+ }
+ else if (n instanceof BackgroundRetained) {
+ // If a new background is inserted, then
+ // re_evaluate to determine if this backgrouns
+ // should be used
+ reEvaluateBg = true;
+ }
+ else if (n instanceof ClipRetained) {
+ reEvaluateClip = true;
+ }
+ else if (n instanceof ModelClipRetained) {
+ envDirty |= REEVALUATE_MCLIP;
+ if (!changedModelClips.contains(n))
+ changedModelClips.add((ModelClipRetained)n);
+ }
+ else if (n instanceof AlternateAppearanceRetained) {
+ altAppearanceDirty = true;
+ }
+ }
+ // Note: geometryAtom is not part of viewScopedNodes
+ // Its a part of orginal nodes even if scoped
+ }
+ }
+}
+
+@Override
+void removeNodes(J3dMessage m) {
+ ArrayList<NodeRetained> viewScopedNodes = (ArrayList<NodeRetained>)m.args[3];
+ ArrayList<ArrayList<View>> scopedNodesViewList = (ArrayList<ArrayList<View>>)m.args[4];
+ int i;
+ Object[] nodes = (Object[])m.args[0];
+ for (int n = 0; n < nodes.length; n++) {
+ if (nodes[n] instanceof GeometryAtom) {
+ visGAIsDirty = true;
+ visQuery = true;
+ RenderAtom ra = ((GeometryAtom) nodes[n]).getRenderAtom(view);
+ if (ra != null && ra.inRenderBin()) {
+ renderAtoms.remove(renderAtoms.indexOf(ra));
+ removeARenderAtom(ra);
+ }
+
+ // This code segment is to handle the texture resource cleanup
+ // for Raster object.
+ GeometryAtom geomAtom = (GeometryAtom) nodes[n];
+ if (geomAtom.geometryArray != null) {
+ for (int ii = 0; ii < geomAtom.geometryArray.length; ii++) {
+ GeometryRetained geomRetained = geomAtom.geometryArray[ii];
+ if ((geomRetained != null)
+ && (geomRetained instanceof RasterRetained)) {
+ addTextureResourceFreeList(((RasterRetained) geomRetained).texture);
+ }
+ }
+ }
+ }
+ else if (nodes[n] instanceof AlternateAppearanceRetained) {
+ altAppearanceDirty = true;
+ }
+ else if (nodes[n] instanceof BackgroundRetained) {
+ reEvaluateBg = true;
+ }
+ else if (nodes[n] instanceof ClipRetained) {
+ reEvaluateClip = true;
+ }
+ else if (nodes[n] instanceof ModelClipRetained) {
+ envDirty |= REEVALUATE_MCLIP;
+ }
+ else if (nodes[n] instanceof FogRetained) {
+ envDirty |= REEVALUATE_FOG;
+ }
+ if (nodes[n] instanceof LightRetained) {
+ envDirty |= REEVALUATE_LIGHTS;
+ }
+ }
+ // Handle ViewScoped Nodes
+ if (viewScopedNodes != null) {
+ int size = viewScopedNodes.size();
+ for (i = 0; i < size; i++) {
+ NodeRetained node = viewScopedNodes.get(i);
+ ArrayList<View> vl = scopedNodesViewList.get(i);
+ // If the node object is scoped to this view, then ..
+ if (vl.contains(view)) {
+ if (node instanceof LightRetained) {
+ envDirty |= REEVALUATE_LIGHTS;
+ }
+ else if (node instanceof FogRetained) {
+ envDirty |= REEVALUATE_FOG;
+ }
+ else if (node instanceof BackgroundRetained) {
+ // If a new background is inserted, then
+ // re_evaluate to determine if this backgrouns
+ // should be used
+ reEvaluateBg = true;
+ }
+ else if (node instanceof ClipRetained) {
+ reEvaluateClip = true;
+ }
+ else if (node instanceof ModelClipRetained) {
+ envDirty |= REEVALUATE_MCLIP;
+ }
+ else if (node instanceof AlternateAppearanceRetained) {
+ altAppearanceDirty = true;
+ }
+ // Note: geometryAtom is not part of viewScopedNodes
+ // Its a part of orginal nodes even if scoped
+ }
+
+ }
+ }
+}
+
+ @Override
+ void cleanup() {
+ releaseAllDisplayListID();
+ removeAllRenderAtoms();
+ }
+
+
+ void freeAllDisplayListResources(Canvas3D cv, Context ctx) {
+
+ assert ctx != null;
+
+ int i;
+ int size = renderMoleculeList.size();
+ Renderer rdr = cv.screen.renderer;
+
+ if (size > 0) {
+ RenderMolecule[] rmArr = (RenderMolecule[])
+ renderMoleculeList.toArray(false);
+
+ for (i = 0 ; i < size; i++) {
+ rmArr[i].releaseAllPrimaryDisplayListResources(cv, ctx);
+ }
+ }
+
+ size = sharedDList.size();
+ if (size > 0) {
+ RenderAtomListInfo arr[] = new RenderAtomListInfo[size];
+ arr = sharedDList.toArray(arr);
+
+ GeometryArrayRetained geo;
+ int mask = (cv.useSharedCtx ? rdr.rendererBit : cv.canvasBit);
+
+ for (i = 0; i < size; i++) {
+ geo = (GeometryArrayRetained)arr[i].geometry();
+ // Fix for Issue 5: free all native display lists and clear the
+ // context creation bits for this canvas, but don't do anything
+ // with the geo's user list.
+ if (geo.dlistId > 0) {
+ // XXXX: for the shared ctx case, we really should
+ // only free the display lists if this is the last
+ // Canvas in the renderer. However, since the
+ // display lists will be recreated, it doesn't
+ // really matter.
+ Canvas3D.freeDisplayList(ctx, geo.dlistId);
+ geo.resourceCreationMask &= ~mask;
+ }
+ }
+ }
+ }
+
+
+ // put displayListID back to MC
+ void releaseAllDisplayListID() {
+ int i;
+ int size = renderMoleculeList.size();
+
+ if (size > 0) {
+ RenderMolecule[] rmArr = (RenderMolecule[])
+ renderMoleculeList.toArray(false);
+
+ for (i = 0 ; i < size; i++) {
+ rmArr[i].releaseAllPrimaryDisplayListID();
+ }
+ }
+
+ size = sharedDList.size();
+ if (size > 0) {
+ RenderAtomListInfo arr[] = new RenderAtomListInfo[size];
+ arr = sharedDList.toArray(arr);
+ GeometryArrayRetained geo;
+
+ for (i = 0; i < size; i++) {
+ geo = (GeometryArrayRetained)arr[i].geometry();
+ if (geo.resourceCreationMask == 0) {
+ geo.freeDlistId();
+ }
+ }
+ }
+ }
+
+
+ /*
+ void handleFrequencyBitChanged(J3dMessage m) {
+ NodeComponentRetained nc = (NodeComponentRetained)m.args[0];
+ GeometryAtom[] gaArr = (GeometryAtom[])m.args[3];
+ int i;
+ RenderAtom ra;
+ Boolean value = (Boolean)m.args[1];
+ int mask = ((Integer)m.args[2]).intValue();
+
+ // Currently, we do not handle the case of
+ // going from frequent to infrequent
+ if (value == Boolean.FALSE)
+ return;
+
+ ra = null;
+ // Get the first ra that is visible
+ for (i = 0; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+ }
+
+ if (ra == null)
+ return;
+
+ int start = i;
+ // Check if the removed renderAtom is already in
+ // a separate bin - this is to handle the case
+ // when it has been changed to frequent, then to
+ // infrequent and then to frequent again!
+ if ((nc instanceof MaterialRetained && ra.renderMolecule.definingMaterial != ra.renderMolecule.material) ||
+ (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.MATERIAL) == 0))) {
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ TextureBin tb = ra.renderMolecule.textureBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertRenderAtom(tb, ra);
+ }
+ }
+ else if ((nc instanceof PolygonAttributesRetained && ra.renderMolecule.definingPolygonAttributes != ra.renderMolecule.polygonAttributes) ||
+ (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.POLYGON) == 0))) {
+ // Check if the removed renderAtom is already in
+ // a separate bin - this is to handle the case
+ // when it has been changed to frequent, then to
+ // infrequent and then to frequent again!
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ TextureBin tb = ra.renderMolecule.textureBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertRenderAtom(tb, ra);
+ }
+ }
+ else if ((nc instanceof PointAttributesRetained && ra.renderMolecule.definingPointAttributes != ra.renderMolecule.pointAttributes) ||
+ (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.POINT) == 0))) {
+ // Check if the removed renderAtom is already in
+ // a separate bin - this is to handle the case
+ // when it has been changed to frequent, then to
+ // infrequent and then to frequent again!
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ TextureBin tb = ra.renderMolecule.textureBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertRenderAtom(tb, ra);
+ }
+ }
+ else if ((nc instanceof LineAttributesRetained && ra.renderMolecule.definingLineAttributes != ra.renderMolecule.lineAttributes) ||
+ (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.LINE) == 0))) {
+ // Check if the removed renderAtom is already in
+ // a separate bin - this is to handle the case
+ // when it has been changed to frequent, then to
+ // infrequent and then to frequent again!
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ TextureBin tb = ra.renderMolecule.textureBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertRenderAtom(tb, ra);
+ }
+ }
+ else if((nc instanceof TransparencyAttributesRetained&& ra.renderMolecule.definingTransparency != ra.renderMolecule.transparency) ||
+ (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.TRANSPARENCY) == 0))) {
+ // Check if the removed renderAtom is already in
+ // a separate bin - this is to handle the case
+ // when it has been changed to frequent, then to
+ // infrequent and then to frequent again!
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ TextureBin tb = ra.renderMolecule.textureBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertRenderAtom(tb, ra);
+ }
+ }
+ else if ((nc instanceof ColoringAttributesRetained&& ra.renderMolecule.definingColoringAttributes != ra.renderMolecule.coloringAttributes) ||
+ (nc instanceof AppearanceRetained && ((ra.renderMolecule.soleUser & AppearanceRetained.COLOR) == 0))) {
+ // Check if the removed renderAtom is already in
+ // a separate bin - this is to handle the case
+ // when it has been changed to frequent, then to
+ // infrequent and then to frequent again!
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ TextureBin tb = ra.renderMolecule.textureBin;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertRenderAtom(tb, ra);
+ }
+ }
+ else if ((nc instanceof RenderingAttributesRetained && ra.renderMolecule.textureBin.attributeBin.definingRenderingAttributes != ra.renderMolecule.textureBin.attributeBin.renderingAttrs) ||
+ (nc instanceof AppearanceRetained && ((ra.renderMolecule.textureBin.attributeBin.soleUser & AppearanceRetained.RENDER) == 0))) {
+ for (i = start; i < gaArr.length; i++) {
+ ra = gaArr[i].getRenderAtom(view);
+ if (ra== null || !ra.inRenderBin())
+ continue;
+
+ EnvironmentSet e= ra.renderMolecule.textureBin.environmentSet;
+ ra.renderMolecule.removeRenderAtom(ra);
+ reInsertAttributeBin(e, ra);
+ }
+ }
+ else {
+
+ // XXXX: handle texture
+ }
+
+
+ }
+ */
+
+}