/* * 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 renderAtoms = new ArrayList(5); /** * A couple ArrayLists used during light Processing */ ArrayList lightMessageList = new ArrayList(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 rmUpdateList = new ArrayList(); ArrayList aBinUpdateList = new ArrayList(); /** * List of ShaderBin that are soleUser that needs to have its components updated @updateObject * time */ ArrayList sBinUpdateList = new ArrayList(); /** * List of TextureBin that are soleUser that needs to have its components * updated @updateObject time */ ArrayList tbUpdateList = new ArrayList(); /** * 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 updateCheckList = new ArrayList(); /** * 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 positionDirtyList = new ArrayList(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 transparencySortComparator = null; private ArrayList toBeAddedTextureResourceFreeList = new ArrayList(5); private ArrayList displayListResourceFreeList = new ArrayList(5); // a list of top level OrderedGroups ArrayList orderedBins = new ArrayList(5); // List of changed elements in the environment that needs to // be reloaded ArrayList changedLts = new ArrayList(5); ArrayList changedFogs = new ArrayList(5); ArrayList changedModelClips = new ArrayList(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 sharedDList = new HashSet(); ArrayList dirtyRenderMoleculeList = new ArrayList(5); /** * ArrayList of objects to be updated */ ArrayList objUpdateList = new ArrayList(5); ArrayList raLocaleVwcBoundsUpdateList = new ArrayList(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 ogCIOList = new ArrayList(5); /** * list of ordered bins from which orderedCollection are added/removed */ ArrayList obList = new ArrayList(5); /** * Ordered Bin processing */ ArrayList> orderedBinsList = new ArrayList>(5); ArrayList> toBeAddedBinList = new ArrayList>(5); /** * arraylist of geometry that should be locked to ensure * that the same snapshot of the geometry is rendered * across all canvases */ ArrayList lockGeometryList = new ArrayList(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 bgOrderedBins = new ArrayList(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 textureBinList = new ArrayList(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 dirtyReferenceGeomList = new ArrayList(5); // list of all Oriented RenderAtoms ArrayList orientedRAs = new ArrayList(5); // list of Oriented RenderAtoms whose orientedTransforms require update ArrayList dirtyOrientedRAs = new ArrayList(5); // Cached copy of dirty oriented RAs to be updated in MasterControl ArrayList cachedDirtyOrientedRAs = null; // list of offScreen message that ArrayList offScreenMessage = new ArrayList(5); // Vector used for locale translation Vector3d localeTranslation = new Vector3d(); // Separate dlists that were added/removed in this snapshot private HashSet addDlist = new HashSet(); private HashSet removeDlist = new HashSet(); // Separate dlists per rinfo that were added/removed in this snapshot ArrayList addDlistPerRinfo = new ArrayList(5); ArrayList removeDlistPerRinfo = new ArrayList(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 dirtyList = new ArrayList(5); // Transaprency sort mode int transpSortMode = View.TRANSPARENCY_SORT_NONE; int cachedTranspSortMode = View.TRANSPARENCY_SORT_NONE; // Temporary dirtylist private LinkedHashSet dirtyDepthSortRenderAtom = new LinkedHashSet(); 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 0) { for (i = 0 ; i < size; i++) { orderBin = obList.get(i); orderBin.addRemoveOrderedCollection(); } } size = ogCIOList.size(); if(size > 0) { for(i=0; i 0 ) { for (i = 0; i < size; i++) { ArrayList obs = orderedBinsList.get(i); ArrayList 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 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 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 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(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 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 rlist = new ArrayList(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 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 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 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 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= 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 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 rmList, ArrayList dlistPerRinfoList, ArrayList 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 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 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 ocs; ArrayList 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 list = new ArrayList(5); list.add(ob); toBeAddedBinList.add(list); } else { ArrayList 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 rmap = null; HashMap> 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 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 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 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 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 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 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 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 mLts, ArrayList fogs, ArrayList 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 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 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 viewScopedNodes = (ArrayList)m.args[3]; ArrayList> scopedNodesViewList = (ArrayList>)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 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 viewScopedNodes = (ArrayList)m.args[3]; ArrayList> scopedNodesViewList = (ArrayList>)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 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 } } */ }