/* * Copyright 1999-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 javax.vecmath.Vector3d; /** * The RenderMolecule manages a collection of RenderAtoms. */ class RenderMolecule extends IndexedObject implements ObjectUpdate, NodeComponentUpdate { // different types of IndexedUnorderedSet that store RenderMolecule static final int REMOVE_RENDER_ATOM_IN_RM_LIST = 0; static final int RENDER_MOLECULE_LIST = 1; // total number of different IndexedUnorderedSet types static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2; /** * Values for the geometryType field */ static final int POINT = 0x01; static final int LINE = 0x02; static final int SURFACE = 0x04; static final int RASTER = 0x08; static final int COMPRESSED = 0x10; static int RM_COMPONENTS = (AppearanceRetained.POLYGON | AppearanceRetained.LINE | AppearanceRetained.POINT | AppearanceRetained.MATERIAL | AppearanceRetained.TRANSPARENCY| AppearanceRetained.COLOR); // XXXX: use definingMaterial etc. instead of these // when sole user is completely implement PolygonAttributesRetained polygonAttributes = null; LineAttributesRetained lineAttributes = null; PointAttributesRetained pointAttributes = null; MaterialRetained material = null; ColoringAttributesRetained coloringAttributes = null; TransparencyAttributesRetained transparency = null; // Use Object instead of AppearanceRetained class for // state caching optimation memory performance boolean normalPresent = true; // Equivalent bits static final int POINTATTRS_DIRTY = AppearanceRetained.POINT; static final int LINEATTRS_DIRTY = AppearanceRetained.LINE; static final int POLYGONATTRS_DIRTY = AppearanceRetained.POLYGON; static final int MATERIAL_DIRTY = AppearanceRetained.MATERIAL; static final int TRANSPARENCY_DIRTY = AppearanceRetained.TRANSPARENCY; static final int COLORINGATTRS_DIRTY = AppearanceRetained.COLOR; static final int ALL_DIRTY_BITS = POINTATTRS_DIRTY | LINEATTRS_DIRTY | POLYGONATTRS_DIRTY | MATERIAL_DIRTY | TRANSPARENCY_DIRTY | COLORINGATTRS_DIRTY; /** * bit mask of all attr fields that are equivalent across * renderMolecules */ int dirtyAttrsAcrossRms = ALL_DIRTY_BITS; // Mask set to true is any of the component have changed int soleUserCompDirty = 0; /** * The PolygonAttributes for this RenderMolecule */ PolygonAttributesRetained definingPolygonAttributes = null; /** * The LineAttributes for this RenderMolecule */ LineAttributesRetained definingLineAttributes = null; /** * The PointAttributes for this RenderMolecule */ PointAttributesRetained definingPointAttributes = null; /** * The TextureBin that this RenderMolecule resides */ TextureBin textureBin = null; /** * The localToVworld for this RenderMolecule */ Transform3D[] localToVworld = null; int[] localToVworldIndex = null; /** * The Material reference for this RenderMolecule */ MaterialRetained definingMaterial = null; /** * The ColoringAttribute reference for this RenderMolecule */ ColoringAttributesRetained definingColoringAttributes = null; /** * The Transparency reference for this RenderMolecule */ TransparencyAttributesRetained definingTransparency = null; /** * Transform3D - point to the right one based on bg or not */ Transform3D[] trans = null; /** * specify whether scale is nonuniform */ boolean isNonUniformScale = false; /** * number of renderAtoms to be rendered in this RenderMolecule */ int numRenderAtoms = 0; /** * number of render atoms, used during the renderBin update time */ int numEditingRenderAtoms = 0; RenderAtom addRAs = null; RenderAtom removeRAs = null; /** * The cached ColoringAttributes color value. It is * 1.0, 1.0, 1.0 if there is no ColoringAttributes. */ float red = 1.0f; float green = 1.0f; float blue = 1.0f; /** * Cached diffuse color value */ float dRed = 1.0f; float dGreen = 1.0f; float dBlue = 1.0f; /** * The cached TransparencyAttributes transparency value. It is * 0.0 if there is no TransparencyAttributes. */ float alpha = 0.0f; /** * The geometry type for this RenderMolecule */ int geometryType = -1; /** * A boolean indicating whether or not lighting should be on. */ boolean enableLighting = false; /** * A boolean indicating whether or not this molecule rendered Text3D */ int primaryMoleculeType = 0; static int COMPRESSED_MOLECULE = 0x1; static int TEXT3D_MOLECULE = 0x2; static int DLIST_MOLECULE = 0x4; static int RASTER_MOLECULE = 0x8; static int ORIENTEDSHAPE3D_MOLECULE = 0x10; static int SEPARATE_DLIST_PER_RINFO_MOLECULE = 0x20; /** * Cached values for polygonMode, line antialiasing, and point antialiasing */ int polygonMode = PolygonAttributes.POLYGON_FILL; boolean lineAA = false; boolean pointAA = false; /** * The vertex format for this RenderMolecule. Only looked * at for GeometryArray and CompressedGeometry objects. */ int vertexFormat = -1; /** * The texCoordSetMap length for this RenderMolecule. */ int texCoordSetMapLen = 0; /** * The primary renderMethod object for this RenderMolecule * this is either a Text3D, display list, or compressed geometry renderer. */ RenderMethod primaryRenderMethod = null; /** * The secondary renderMethod object for this RenderMolecule * this is used for geometry that is shared */ RenderMethod secondaryRenderMethod = null; /** * The RenderBino for this molecule */ RenderBin renderBin = null; /** * The references to the next and previous RenderMolecule in the * list. */ RenderMolecule next = null; RenderMolecule prev = null; /** * The list of RenderAtoms in this RenderMolecule that are not using * vertex arrays. */ RenderAtomListInfo primaryRenderAtomList = null; /** * The list of RenderAtoms in this RenderMolecule that are using * separte dlist . */ RenderAtomListInfo separateDlistRenderAtomList = null; /** * The list of RenderAtoms in this RenderMolecule that are using vertex * arrays. */ RenderAtomListInfo vertexArrayRenderAtomList = null; /** * This BoundingBox is used for View Frustum culling on the primary * list */ BoundingBox vwcBounds = null; /** * If this is end of the linked list for this xform, then * this field is non-null, if there is a map after this */ RenderMolecule nextMap = null; RenderMolecule prevMap = null; /** * If the any of the node component of the appearance in RM will be changed * frequently, then confine it to a separate bin */ boolean soleUser = false; Object appHandle = null; VertexArrayRenderMethod cachedVertexArrayRenderMethod = (VertexArrayRenderMethod) VirtualUniverse.mc.getVertexArrayRenderMethod(); // In D3D separate Quad/Triangle Geometry with others in RenderMolecule // Since we need to dynamically switch whether to use DisplayList // or not in render() as a group. boolean isQuadGeometryArray = false; boolean isTriGeometryArray = false; // display list id, valid id starts from 1 int displayListId = 0; Integer displayListIdObj = null; int onUpdateList = 0; static int NEW_RENDERATOMS_UPDATE = 0x1; static int BOUNDS_RECOMPUTE_UPDATE = 0x2; static int LOCALE_TRANSLATION = 0x4; static int UPDATE_BACKGROUND_TRANSFORM = 0x8; static int IN_DIRTY_RENDERMOLECULE_LIST = 0x10; static int LOCALE_CHANGED = 0x20; static int ON_UPDATE_CHECK_LIST = 0x40; // background geometry rendering boolean doInfinite; Transform3D[] infLocalToVworld; // Whether alpha is used in this renderMolecule boolean useAlpha = false; // Support for multiple locales Locale locale = null; // Transform when locale is different from the view's locale Transform3D[] localeLocalToVworld = null; // Vector used for locale translation Vector3d localeTranslation = null; boolean primaryChanged = false; boolean isOpaqueOrInOG = true; boolean inOrderedGroup = false; // closest switch parent SwitchRetained closestSwitchParent = null; // the child index from the closest switch parent int closestSwitchIndex = -1; RenderMolecule(GeometryAtom ga, PolygonAttributesRetained polygonAttributes, LineAttributesRetained lineAttributes, PointAttributesRetained pointAttributes, MaterialRetained material, ColoringAttributesRetained coloringAttributes, TransparencyAttributesRetained transparency, RenderingAttributesRetained renderAttrs, TextureUnitStateRetained[] texUnits, Transform3D[] transform, int[] transformIndex, RenderBin rb) { renderBin = rb; IndexedUnorderSet.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); reset(ga, polygonAttributes, lineAttributes, pointAttributes, material, coloringAttributes, transparency, renderAttrs, texUnits, transform, transformIndex); } void reset(GeometryAtom ga, PolygonAttributesRetained polygonAttributes, LineAttributesRetained lineAttributes, PointAttributesRetained pointAttributes, MaterialRetained material, ColoringAttributesRetained coloringAttributes, TransparencyAttributesRetained transparency, RenderingAttributesRetained renderAttrs, TextureUnitStateRetained[] texUnits, Transform3D[] transform, int[] transformIndex) { primaryMoleculeType = 0; numRenderAtoms = 0; numEditingRenderAtoms = 0; onUpdateList = 0; dirtyAttrsAcrossRms = ALL_DIRTY_BITS; primaryRenderMethod = null; isNonUniformScale = false; primaryChanged = false; this.material = material; this.polygonAttributes = polygonAttributes; this.lineAttributes = lineAttributes; this.pointAttributes = pointAttributes; this.coloringAttributes = coloringAttributes; this.transparency = transparency; closestSwitchParent = ga.source.closestSwitchParent; closestSwitchIndex = ga.source.closestSwitchIndex; // Find the first non-null geometey GeometryRetained geo = null; int k = 0; isOpaqueOrInOG = true; inOrderedGroup = false; while (geo == null && (k < ga.geometryArray.length)) { geo = ga.geometryArray[k]; k++; } // Issue 249 - check for sole user only if property is set soleUser = false; if (VirtualUniverse.mc.allowSoleUser) { if (ga.source.appearance != null) { soleUser = ((ga.source.appearance.changedFrequent & RM_COMPONENTS) != 0); } } // Set the appearance only for soleUser case if (soleUser) appHandle = ga.source.appearance; else appHandle = this; // If its of type GeometryArrayRetained if (ga.geoType <= GeometryRetained.GEO_TYPE_GEOMETRYARRAY || ga.geoType == GeometryRetained.GEO_TYPE_TEXT3D) { if (ga.source instanceof OrientedShape3DRetained) { primaryRenderMethod = VirtualUniverse.mc.getOrientedShape3DRenderMethod(); primaryMoleculeType = ORIENTEDSHAPE3D_MOLECULE; } else if (ga.geoType == GeometryRetained.GEO_TYPE_TEXT3D) { primaryRenderMethod = VirtualUniverse.mc.getText3DRenderMethod(); primaryMoleculeType = TEXT3D_MOLECULE; } else { // Make determination of dlist or not during addRenderAtom secondaryRenderMethod = cachedVertexArrayRenderMethod; } } else { if (ga.geoType == GeometryRetained.GEO_TYPE_COMPRESSED) { primaryRenderMethod = VirtualUniverse.mc.getCompressedGeometryRenderMethod(); primaryMoleculeType = COMPRESSED_MOLECULE; } else if (geo instanceof RasterRetained) { primaryRenderMethod = VirtualUniverse.mc.getDefaultRenderMethod(); primaryMoleculeType = RASTER_MOLECULE; } } prev = null; next = null; prevMap = null; nextMap = null; primaryRenderAtomList = null; vertexArrayRenderAtomList = null; switch (ga.geoType) { case GeometryRetained.GEO_TYPE_POINT_SET: case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET: this.geometryType = POINT; break; case GeometryRetained.GEO_TYPE_LINE_SET: case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET: case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: this.geometryType = LINE; break; case GeometryRetained.GEO_TYPE_RASTER: this.geometryType = RASTER; break; case GeometryRetained.GEO_TYPE_COMPRESSED: this.geometryType = COMPRESSED; switch (((CompressedGeometryRetained)geo).getBufferType()) { case CompressedGeometryHeader.POINT_BUFFER: this.geometryType |= POINT ; break ; case CompressedGeometryHeader.LINE_BUFFER: this.geometryType |= LINE ; break ; default: case CompressedGeometryHeader.TRIANGLE_BUFFER: this.geometryType |= SURFACE ; if (polygonAttributes != null) { if (polygonAttributes.polygonMode == PolygonAttributes.POLYGON_POINT) { this.geometryType |= POINT; } else if (polygonAttributes.polygonMode == PolygonAttributes.POLYGON_LINE) { this.geometryType |= LINE; } } break ; } break; default: this.geometryType = SURFACE; if (polygonAttributes != null) { if (polygonAttributes.polygonMode == PolygonAttributes.POLYGON_POINT) { this.geometryType |= POINT; } else if (polygonAttributes.polygonMode == PolygonAttributes.POLYGON_LINE) { this.geometryType |= LINE; } } break; } isQuadGeometryArray = (geo.getClassType() == GeometryRetained.QUAD_TYPE); isTriGeometryArray = (geo.getClassType() == GeometryRetained.TRIANGLE_TYPE); this.localToVworld = transform; this.localToVworldIndex = transformIndex; doInfinite = ga.source.inBackgroundGroup; if (doInfinite) { if (infLocalToVworld == null) { infLocalToVworld = new Transform3D[2]; infLocalToVworld[0] = infLocalToVworld[1] = new Transform3D(); } localToVworld[0].getRotation(infLocalToVworld[0]); } int mask = 0; if (polygonAttributes != null) { if (polygonAttributes.changedFrequent != 0) { definingPolygonAttributes = polygonAttributes; mask |= POLYGONATTRS_DIRTY; } else { if (definingPolygonAttributes != null) { definingPolygonAttributes.set(polygonAttributes); } else { definingPolygonAttributes = (PolygonAttributesRetained)polygonAttributes.clone(); } } polygonMode = definingPolygonAttributes.polygonMode; } else { polygonMode = PolygonAttributes.POLYGON_FILL; definingPolygonAttributes = null; } if (lineAttributes != null) { if (lineAttributes.changedFrequent != 0) { definingLineAttributes = lineAttributes; mask |= LINEATTRS_DIRTY; } else { if (definingLineAttributes != null) { definingLineAttributes.set(lineAttributes); } else { definingLineAttributes = (LineAttributesRetained)lineAttributes.clone(); } } lineAA = definingLineAttributes.lineAntialiasing; } else { lineAA = false; definingLineAttributes = null; } if (pointAttributes != null) { if (pointAttributes.changedFrequent != 0) { definingPointAttributes = pointAttributes; mask |= POINTATTRS_DIRTY; } else { if (definingPointAttributes != null) { definingPointAttributes.set(pointAttributes); } else { definingPointAttributes = (PointAttributesRetained)pointAttributes.clone(); } } pointAA = definingPointAttributes.pointAntialiasing; } else { pointAA = false; definingPointAttributes = null; } normalPresent = true; if (geo instanceof GeometryArrayRetained) { GeometryArrayRetained gr = (GeometryArrayRetained)geo; this.vertexFormat = gr.vertexFormat; if (gr.texCoordSetMap != null) { this.texCoordSetMapLen = gr.texCoordSetMap.length; } else { this.texCoordSetMapLen = 0; } // Throw an exception if lighting is enabled, but no normals defined if ((vertexFormat & GeometryArray.NORMALS) == 0) { // Force lighting to false normalPresent = false; } } else if (geo instanceof CompressedGeometryRetained) { this.vertexFormat = ((CompressedGeometryRetained)geo).getVertexFormat(); // Throw an exception if lighting is enabled, but no normals defined if ((vertexFormat & GeometryArray.NORMALS) == 0) { // Force lighting to false normalPresent = false; } this.texCoordSetMapLen = 0; } else { this.vertexFormat = -1; this.texCoordSetMapLen = 0; } if (material != null) { if (material.changedFrequent != 0) { definingMaterial = material; mask |= MATERIAL_DIRTY; } else { if (definingMaterial != null) definingMaterial.set(material); else { definingMaterial = (MaterialRetained)material.clone(); } } } else { definingMaterial = null; } evalMaterialCachedState(); if (coloringAttributes != null) { if (coloringAttributes.changedFrequent != 0) { definingColoringAttributes = coloringAttributes; mask |= COLORINGATTRS_DIRTY; } else { if (definingColoringAttributes != null) { definingColoringAttributes.set(coloringAttributes); } else { definingColoringAttributes = (ColoringAttributesRetained)coloringAttributes.clone(); } } red = coloringAttributes.color.x; green = coloringAttributes.color.y; blue = coloringAttributes.color.z; } else { red = 1.0f; green = 1.0f; blue = 1.0f; definingColoringAttributes = null; } if (transparency != null) { if (transparency.changedFrequent != 0) { definingTransparency = transparency; mask |= TRANSPARENCY_DIRTY; } else { if (definingTransparency != null) { definingTransparency.set(transparency); } else { definingTransparency = (TransparencyAttributesRetained)transparency.clone(); } } alpha = 1.0f - transparency.transparency; } else { alpha = 1.0f; definingTransparency = null; } locale = ga.source.locale; if (locale != renderBin.locale) { if (localeLocalToVworld == null) { localeLocalToVworld = new Transform3D[2]; } localeLocalToVworld[0] = new Transform3D(); localeLocalToVworld[1] = new Transform3D(); localeTranslation = new Vector3d(); ga.locale.hiRes.difference(renderBin.locale.hiRes, localeTranslation); translate(); } else { localeLocalToVworld = localToVworld; } if (doInfinite) { trans = infLocalToVworld; } else { trans = localeLocalToVworld; } evalAlphaUsage(renderAttrs, texUnits); isOpaqueOrInOG = isOpaque() || (ga.source.orderedPath != null); inOrderedGroup = (ga.source.orderedPath != null); // System.err.println("isOpaque = "+isOpaque() +" OrInOG = "+isOpaqueOrInOG); if (mask != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= mask; } } /** * This tests if the given attributes matches this TextureBin */ boolean equals(RenderAtom ra, PolygonAttributesRetained polygonAttributes, LineAttributesRetained lineAttributes, PointAttributesRetained pointAttributes, MaterialRetained material, ColoringAttributesRetained coloringAttributes, TransparencyAttributesRetained transparency, Transform3D[] transform) { int geoType = 0; GeometryAtom ga = ra.geometryAtom; if (this.localToVworld != transform) { return (false); } if (locale != ra.geometryAtom.source.locale) { return (false); } if (ra.geometryAtom.source.closestSwitchParent != closestSwitchParent || ra.geometryAtom.source.closestSwitchIndex != closestSwitchIndex) { return (false); } // Find the first non-null geometey GeometryRetained geo = null; int k = 0; while (geo == null && (k < ga.geometryArray.length)) { geo = ga.geometryArray[k]; k++; } // XXXX: Add tags switch (ga.geoType) { case GeometryRetained.GEO_TYPE_POINT_SET: case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET: geoType = POINT; break; case GeometryRetained.GEO_TYPE_LINE_SET: case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET: case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: geoType = LINE; break; case GeometryRetained.GEO_TYPE_RASTER: geoType = RASTER; break; case GeometryRetained.GEO_TYPE_COMPRESSED: geoType = COMPRESSED; switch (((CompressedGeometryRetained)geo).getBufferType()) { case CompressedGeometryHeader.POINT_BUFFER: geoType |= POINT ; break ; case CompressedGeometryHeader.LINE_BUFFER: geoType |= LINE ; break ; default: case CompressedGeometryHeader.TRIANGLE_BUFFER: geoType |= SURFACE ; break ; } break; default: geoType = SURFACE; if (polygonAttributes != null) { if (polygonAttributes.polygonMode == PolygonAttributes.POLYGON_POINT) { geoType |= POINT; } else if (polygonAttributes.polygonMode == PolygonAttributes.POLYGON_LINE) { geoType |= LINE; } } break; } if (this.geometryType != geoType) { return (false); } /* // XXXX : Check this if (useDisplayList && (ga.geometry.isEditable || ga.geometry.refCount > 1 || ((GroupRetained)ga.source.parent).switchLevel >= 0 || ga.alphaEditable)) { return (false); } */ if (ga.geoType == GeometryRetained.GEO_TYPE_TEXT3D && primaryMoleculeType != 0 && ((primaryMoleculeType & TEXT3D_MOLECULE) == 0)) { return (false); } if(!(ra.geometryAtom.source instanceof OrientedShape3DRetained) && ((primaryMoleculeType & ORIENTEDSHAPE3D_MOLECULE) != 0)) { //System.err.println("RA's NOT a OrientedShape3DRetained and RM is a ORIENTEDSHAPE3D_MOLECULE "); return (false); } // XXXX: Its is necessary to have same vformat for dl, // Howabout iteration, should we have 2 vformats in rm? if (geo instanceof GeometryArrayRetained) { GeometryArrayRetained gr = (GeometryArrayRetained)geo; if (this.vertexFormat != gr.vertexFormat) { return (false); } // we are requiring that texCoordSetMap length to be the same // so that we can either put all multi-tex ga to a display list, // or punt all to vertex array. And we don't need to worry // about some of the ga can be in display list for this canvas, // and some other can be in display list for the other canvas. if (((gr.texCoordSetMap != null) && (this.texCoordSetMapLen != gr.texCoordSetMap.length)) || ((gr.texCoordSetMap == null) && (this.texCoordSetMapLen != 0))) { return (false); } } else if (geo instanceof CompressedGeometryRetained) { if (this.vertexFormat != ((CompressedGeometryRetained)geo).getVertexFormat()) { return (false); } } else { //XXXX: compare isEditable if (this.vertexFormat != -1) { return (false); } } // If the any reference to the appearance components that is cached renderMolecule // can change frequently, make a separate bin if (soleUser || (ra.geometryAtom.source.appearance != null && ((ra.geometryAtom.source.appearance.changedFrequent & RM_COMPONENTS) != 0))) { if (appHandle == ra.geometryAtom.source.appearance) { // if this RenderMolecule is currently on a zombie state, // we'll need to put it on the update list to reevaluate // the state, because while it is on a zombie state, // state could have been changed. Example, // application could have detached an appearance, // made changes to the appearance state, and then // reattached the appearance. In this case, the // changes would not have reflected to the RenderMolecule if (numEditingRenderAtoms == 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= ALL_DIRTY_BITS; } return true; } else { return false; } } // Assign the cloned value as the original value // Either a changedFrequent or a null case // and the incoming one is not equal or null // then return; // This check also handles null == null case if (definingPolygonAttributes != null) { if ((this.definingPolygonAttributes.changedFrequent != 0) || (polygonAttributes !=null && polygonAttributes.changedFrequent != 0)) if (definingPolygonAttributes == polygonAttributes) { if (definingPolygonAttributes.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= POLYGONATTRS_DIRTY; } } else { return false; } else if (!definingPolygonAttributes.equivalent(polygonAttributes)) { return false; } } else if (polygonAttributes != null) { return false; } if (definingLineAttributes != null) { if ((this.definingLineAttributes.changedFrequent != 0) || (lineAttributes !=null && lineAttributes.changedFrequent != 0)) if (definingLineAttributes == lineAttributes) { if (definingLineAttributes.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= LINEATTRS_DIRTY; } } else { return false; } else if (!definingLineAttributes.equivalent(lineAttributes)) { return false; } } else if (lineAttributes != null) { return false; } if (definingPointAttributes != null) { if ((this.definingPointAttributes.changedFrequent != 0) || (pointAttributes !=null && pointAttributes.changedFrequent != 0)) if (definingPointAttributes == pointAttributes) { if (definingPointAttributes.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= POINTATTRS_DIRTY; } } else { return false; } else if (!definingPointAttributes.equivalent(pointAttributes)) { return false; } } else if (pointAttributes != null) { return false; } if (definingMaterial != null) { if ((this.definingMaterial.changedFrequent != 0) || (material !=null && material.changedFrequent != 0)) if (definingMaterial == material) { if (definingMaterial.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= MATERIAL_DIRTY; } } else { return false; } else if (!definingMaterial.equivalent(material)) { return false; } } else if (material != null) { return false; } if (definingColoringAttributes != null) { if ((this.definingColoringAttributes.changedFrequent != 0) || (coloringAttributes !=null && coloringAttributes.changedFrequent != 0)) if (definingColoringAttributes == coloringAttributes) { if (definingColoringAttributes.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= COLORINGATTRS_DIRTY; } } else { return false; } else if (!definingColoringAttributes.equivalent(coloringAttributes)) { return false; } } else if (coloringAttributes != null) { return false; } // if the definingTransparency is a non cloned values and the incoming // one is equivalent, then check if the component is dirty // this happens when all the RAs from this RM have been removed // but new ones are not added yet (rbin visibility) not run yet // and when there is a change in nc based on the new RA, we wil; // miss the change, doing this check will catch the change durin // new RAs insertRenderAtom if (definingTransparency != null) { if ((this.definingTransparency.changedFrequent != 0) || (transparency !=null && transparency.changedFrequent != 0)) if (definingTransparency == transparency) { if (definingTransparency.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= TRANSPARENCY_DIRTY; } } else { return false; } else if (!definingTransparency.equivalent(transparency)) { return false; } } else if (transparency != null) { return false; } return (true); } public void updateRemoveRenderAtoms() { RenderAtom r; RenderAtomListInfo rinfo; // Check if this renderMolecule was created and destroyed this frame. // so, no display list was created if (numRenderAtoms == 0 && removeRAs == null && addRAs == null) { textureBin.removeRenderMolecule(this); return; } while (removeRAs != null) { r = removeRAs; r.removed = null; numRenderAtoms--; // Loop thru all geometries in the renderAtom, they could // potentially be in different buckets in the rendermoleulce for (int index = 0; index < r.rListInfo.length; index++) { rinfo = r.rListInfo[index]; // Don't remove null geo if (rinfo.geometry() == null) continue; if ((rinfo.groupType & RenderAtom.PRIMARY) != 0) { primaryChanged = true; if (rinfo.prev == null) { // At the head of the list primaryRenderAtomList = rinfo.next; if (rinfo.next != null) { rinfo.next.prev = null; } } else { // In the middle or at the end. rinfo.prev.next = rinfo.next; if (rinfo.next != null) { rinfo.next.prev = rinfo.prev; } } // If the molecule type is Raster, then add it to the lock list if (primaryMoleculeType == RASTER) { RasterRetained geo = (RasterRetained)rinfo.geometry(); renderBin.removeGeometryFromLockList(geo); if (geo.image != null) renderBin.removeNodeComponent(geo.image); } else if ((rinfo.groupType & RenderAtom.SEPARATE_DLIST_PER_RINFO) != 0) { if (!rinfo.renderAtom.inRenderBin()) { renderBin.removeDlistPerRinfo.add(rinfo); } } } else if ((rinfo.groupType & RenderAtom.SEPARATE_DLIST_PER_GEO) != 0) { if (rinfo.prev == null) { // At the head of the list separateDlistRenderAtomList = rinfo.next; if (rinfo.next != null) { rinfo.next.prev = null; } } else { // In the middle or at the end. rinfo.prev.next = rinfo.next; if (rinfo.next != null) { rinfo.next.prev = rinfo.prev; } } renderBin.removeGeometryDlist(rinfo); } else { if (rinfo.prev == null) { // At the head of the list vertexArrayRenderAtomList = rinfo.next; if (rinfo.next != null) { rinfo.next.prev = null; } } else { // In the middle or at the end. rinfo.prev.next = rinfo.next; if (rinfo.next != null) { rinfo.next.prev = rinfo.prev; } } // For indexed geometry there is no need to lock since // the mirror is changed only when the renderer is not // running // For indexed geometry, if use_coord is set, then either we // are using the index geometry as is or we will be unindexifying // on the fly, so its better to lock GeometryArrayRetained geo = (GeometryArrayRetained)rinfo.geometry(); if (!(geo instanceof IndexedGeometryArrayRetained) || ((geo.vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0)) { renderBin.removeGeometryFromLockList(geo); } } rinfo.prev = null; rinfo.next = null; } removeRAs = removeRAs.nextRemove; r.nextRemove = null; r.prevRemove = null; if (r.isOriented()) { renderBin.orientedRAs.remove(r); } if ((textureBin.environmentSet.lightBin.geometryBackground == null) && !isOpaqueOrInOG && renderBin.transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY) { renderBin.removeTransparentObject(r); } } // If this renderMolecule will not be touched for adding new RenderAtoms // then .. if (addRAs == null) { // If there are no more renderAtoms and there will be no more // renderatoms added to this renderMolecule , then remove if (numRenderAtoms == 0) { // If both lists are empty remove this renderMolecule if ((primaryMoleculeType &DLIST_MOLECULE) != 0) { renderBin.addDisplayListResourceFreeList(this); vwcBounds.set(null); displayListId = 0; displayListIdObj = null; } if (locale != renderBin.locale) { localeLocalToVworld = null; } textureBin.removeRenderMolecule(this); } else { if ((primaryMoleculeType &DLIST_MOLECULE) != 0 && primaryChanged) { // If a renderAtom is added to the display list // structure then add this to the dirty list of rm // for which the display list needs to be recreated renderBin.addDirtyRenderMolecule(this); vwcBounds.set(null); rinfo = primaryRenderAtomList; while (rinfo != null) { vwcBounds.combine(rinfo.renderAtom.localeVwcBounds); rinfo = rinfo.next; } primaryChanged = false; } } } numEditingRenderAtoms = numRenderAtoms; } @Override public void updateObject() { int i; RenderAtom renderAtom; RenderAtomListInfo r; if (textureBin == null) { return; } if (addRAs != null) { while (addRAs != null) { numRenderAtoms++; renderAtom = addRAs; renderAtom.renderMolecule = this; renderAtom.added = null; for (int j = 0; j < renderAtom.rListInfo.length; j++) { r = renderAtom.rListInfo[j]; // Don't add null geo if (r.geometry() == null) continue; r.groupType = evalRinfoGroupType(r); if ((r.groupType & RenderAtom.PRIMARY) != 0) { if ((r.groupType & RenderAtom.DLIST) != 0 && primaryRenderMethod == null) { primaryMoleculeType = DLIST_MOLECULE; renderBin.renderMoleculeList.add(this); if (vwcBounds == null) vwcBounds = new BoundingBox((BoundingBox)null); primaryRenderMethod = VirtualUniverse.mc.getDisplayListRenderMethod(); // Assign a displayListId for this renderMolecule if (displayListId == 0) { displayListIdObj = VirtualUniverse.mc.getDisplayListId(); displayListId = displayListIdObj.intValue(); } } else if ((r.groupType & RenderAtom.SEPARATE_DLIST_PER_RINFO) != 0 && primaryRenderMethod == null) { primaryMoleculeType = SEPARATE_DLIST_PER_RINFO_MOLECULE; renderBin.renderMoleculeList.add(this); primaryRenderMethod = VirtualUniverse.mc.getDisplayListRenderMethod(); } primaryChanged = true; if (primaryRenderAtomList == null) { primaryRenderAtomList = r; } else { r.next = primaryRenderAtomList; primaryRenderAtomList.prev = r; primaryRenderAtomList = r; } if (primaryMoleculeType == SEPARATE_DLIST_PER_RINFO_MOLECULE) { if (r.renderAtom.dlistIds == null) { r.renderAtom.dlistIds = new int[r.renderAtom.rListInfo.length]; for (int k = 0; k < r.renderAtom.dlistIds.length; k++) { r.renderAtom.dlistIds[k] = -1; } } if (r.renderAtom.dlistIds[r.index] == -1) { r.renderAtom.dlistIds[r.index] = VirtualUniverse.mc.getDisplayListId().intValue(); renderBin.addDlistPerRinfo.add(r); } } // If the molecule type is Raster, then add it to the lock list if (primaryMoleculeType == RASTER) { RasterRetained geo = (RasterRetained)r.geometry(); renderBin.addGeometryToLockList(geo); if (geo.image != null) renderBin.addNodeComponent(geo.image); } } else if ((r.groupType & RenderAtom.SEPARATE_DLIST_PER_GEO) != 0) { if (separateDlistRenderAtomList == null) { separateDlistRenderAtomList = r; } else { r.next = separateDlistRenderAtomList; separateDlistRenderAtomList.prev = r; separateDlistRenderAtomList = r; } ((GeometryArrayRetained)r.geometry()).assignDlistId(); renderBin.addGeometryDlist(r); } else { if (secondaryRenderMethod == null) secondaryRenderMethod = cachedVertexArrayRenderMethod; if (vertexArrayRenderAtomList == null) { vertexArrayRenderAtomList = r; } else { r.next = vertexArrayRenderAtomList; vertexArrayRenderAtomList.prev = r; vertexArrayRenderAtomList = r; } // For indexed geometry there is no need to lock since // the mirror is changed only when the renderer is not // running // For indexed geometry, if use_coord is set, then either we // are using the index geometry as is or we will be unindexifying // on the fly, so its better to loc GeometryArrayRetained geo = (GeometryArrayRetained)r.geometry(); if (!(geo instanceof IndexedGeometryArrayRetained) || ((geo.vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0)) { renderBin.addGeometryToLockList(geo); // Add the geometry to the dirty list only if the geometry is by // refernce and there is color and we need to use alpha // Issue 113 - ignore multiScreen if ((( geo.vertexFormat & GeometryArray.BY_REFERENCE)!=0) && (geo.c4fAllocated == 0) && ((geo.vertexFormat & GeometryArray.COLOR) != 0) && useAlpha) { renderBin.addDirtyReferenceGeometry(geo); } } } } addRAs = addRAs.nextAdd; renderAtom.nextAdd = null; renderAtom.prevAdd = null; if (renderAtom.isOriented()) { renderBin.orientedRAs.add(renderAtom); } // If transparent and not in bg geometry and is depth sorted transparency if (!isOpaqueOrInOG && (textureBin.environmentSet.lightBin.geometryBackground == null)&& (renderBin.transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY)) { GeometryRetained geo = null; int k = 0; while (geo == null && k < renderAtom.rListInfo.length) { geo = renderAtom.rListInfo[k].geometry(); k++; } if (geo != null) { if (renderAtom.parentTInfo != null && renderAtom.parentTInfo[k-1] != null) { renderBin.updateTransparentInfo(renderAtom); } // Newly added renderAtom else { renderBin.addTransparentObject(renderAtom); } } // Moving within the renderBin } } if ((primaryMoleculeType &DLIST_MOLECULE) != 0 && primaryChanged) { // If a renderAtom is added to the display list // structure then add this to the dirty list of rm // for which the display list needs to be recreated renderBin.addDirtyRenderMolecule(this); vwcBounds.set(null); r = primaryRenderAtomList; while (r != null) { vwcBounds.combine(r.renderAtom.localeVwcBounds); r = r.next; } primaryChanged = false; } if ((onUpdateList & LOCALE_CHANGED) != 0) { handleLocaleChange(); } if (locale != renderBin.locale) { translate(); } } else { // The flag LOCALE_CHANGED only gets sets when there is a new additon // There are cases when RM updateObject() get called (due to addition // in renderBin - see processTransformChanged()), we need to // evaluate locale change for this case as well if (renderBin.localeChanged) { handleLocaleChange(); } if (locale != renderBin.locale) { translate(); } if ((onUpdateList & UPDATE_BACKGROUND_TRANSFORM) != 0) { i = localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]; localeLocalToVworld[i].getRotation(infLocalToVworld[i]); } // No new renderAtoms were added, but need to // recompute vwcBounds in response to xform change if ((onUpdateList & BOUNDS_RECOMPUTE_UPDATE) != 0) { vwcBounds.set(null); r = primaryRenderAtomList; while (r != null) { vwcBounds.combine(r.renderAtom.localeVwcBounds); r = r.next; } } } // Clear all bits except the IN_DIRTY_LIST onUpdateList &= IN_DIRTY_RENDERMOLECULE_LIST; numEditingRenderAtoms = numRenderAtoms; } boolean canBeInDisplayList(GeometryRetained geo, GeometryAtom ga) { if (ga.source.sourceNode instanceof MorphRetained) { return false; } return geo.canBeInDisplayList(ga.alphaEditable); } // If dlist will be altered due to alpha or ignoreVertexColors, then don't // put in a separate dlist that can be shared ... final boolean geoNotAltered(GeometryArrayRetained geo) { return !(((geo.vertexFormat & GeometryArray.COLOR) != 0) && (textureBin.attributeBin.ignoreVertexColors || useAlpha)); } int evalRinfoGroupType(RenderAtomListInfo r) { int groupType = 0; GeometryRetained geo = r.geometry(); if (geo == null) return groupType; if ((primaryMoleculeType & (COMPRESSED_MOLECULE | RASTER_MOLECULE | TEXT3D_MOLECULE | ORIENTEDSHAPE3D_MOLECULE)) != 0) { groupType = RenderAtom.OTHER; } else if (canBeInDisplayList(geo, r.renderAtom.geometryAtom)) { // if geometry is under share group we immediate set the // dlistID to something other than -1 if ( !((GeometryArrayRetained)geo).isShared || // if we do a compiled and push the transform down to // Geometry, we can't share the displayList (r.renderAtom.geometryAtom.source.staticTransform != null)) { // If the molecule is already defined to be SEPARATE_DLIST_PER_RINFO_MOLECULE // continue adding in that mode even if it was switched back to // no depth sorted mode // System.err.println("isOpaqueOrInOG ="+isOpaqueOrInOG+" primaryMoleculeType ="+primaryMoleculeType+" renderBin.transpSortMode ="+renderBin.transpSortMode); if (primaryMoleculeType == SEPARATE_DLIST_PER_RINFO_MOLECULE) { groupType = RenderAtom.SEPARATE_DLIST_PER_RINFO; } else { if (isOpaqueOrInOG || renderBin.transpSortMode == View.TRANSPARENCY_SORT_NONE) { groupType = RenderAtom.DLIST; } else { groupType = RenderAtom.SEPARATE_DLIST_PER_RINFO; } } } else if (geoNotAltered((GeometryArrayRetained)r.geometry()) ) { groupType = RenderAtom.SEPARATE_DLIST_PER_GEO; } else { groupType = RenderAtom.VARRAY; } } else { groupType = RenderAtom.VARRAY; } return groupType; } /** * Adds the given RenderAtom to this RenderMolecule. */ void addRenderAtom(RenderAtom renderAtom, RenderBin rb) { int i; renderAtom.envSet = textureBin.environmentSet; renderAtom.renderMolecule = this; renderAtom.dirtyMask &= ~RenderAtom.NEED_SEPARATE_LOCALE_VWC_BOUNDS; AppearanceRetained raApp = renderAtom.geometryAtom.source.appearance; MaterialRetained mat = (raApp == null)? null : raApp.material; if (!soleUser && material != mat) { // no longer sole user material = definingMaterial; } if ((geometryType & SURFACE) != 0) { PolygonAttributesRetained pgAttrs = (raApp == null)? null : raApp.polygonAttributes; if (!soleUser && polygonAttributes != pgAttrs) { // no longer sole user polygonAttributes = definingPolygonAttributes; } } if ((geometryType & LINE) != 0) { LineAttributesRetained lnAttrs = (raApp == null)? null : raApp.lineAttributes; if (!soleUser && lineAttributes != lnAttrs) { // no longer sole user lineAttributes = definingLineAttributes; } } if ((geometryType & POINT) != 0) { PointAttributesRetained pnAttrs = (raApp == null)? null : raApp.pointAttributes; if (!soleUser && pointAttributes != pnAttrs) { // no longer sole user pointAttributes = definingPointAttributes; } } ColoringAttributesRetained coAttrs = (raApp == null)? null : raApp.coloringAttributes; if (!soleUser && coloringAttributes != coAttrs) { // no longer sole user coloringAttributes = definingColoringAttributes; } TransparencyAttributesRetained trAttrs = (raApp == null)? null : raApp.transparencyAttributes; if (!soleUser && transparency != trAttrs) { // no longer sole user transparency = definingTransparency; } // If the renderAtom is being inserted first time, then evaluate // the groupType to determine if need separate localeVwcBounds if (!renderAtom.inRenderBin()) { for (i = 0; i < renderAtom.rListInfo.length; i++) { if (renderAtom.rListInfo[i].geometry() == null) continue; int groupType = evalRinfoGroupType(renderAtom.rListInfo[i]); if (groupType != RenderAtom.DLIST) { renderAtom.dirtyMask |= RenderAtom.NEED_SEPARATE_LOCALE_VWC_BOUNDS; } } } if (renderAtom.removed == this) { // Remove the renderAtom from the list of removeRAs // If this is at the head of the list if (renderAtom == removeRAs) { removeRAs = renderAtom.nextRemove; if (removeRAs != null) removeRAs.prevRemove = null; renderAtom.nextRemove = null; renderAtom.prevRemove = null; } // Somewhere in the middle else { renderAtom.prevRemove.nextRemove = renderAtom.nextRemove; if (renderAtom.nextRemove != null) renderAtom.nextRemove.prevRemove = renderAtom.prevRemove; renderAtom.nextRemove = null; renderAtom.prevRemove = null; } renderAtom.removed = null; // Redo any dlist etc, because it has been added for ( i = 0; i < renderAtom.rListInfo.length; i++) { if (renderAtom.rListInfo[i].geometry() == null) continue; if ((renderAtom.rListInfo[i].groupType & RenderAtom.DLIST) != 0) renderBin.addDirtyRenderMolecule(this); else if ((renderAtom.rListInfo[i].groupType & RenderAtom.SEPARATE_DLIST_PER_RINFO) != 0) { renderBin.addDlistPerRinfo.add(renderAtom.rListInfo[i]); } else if ((renderAtom.rListInfo[i].groupType & RenderAtom.SEPARATE_DLIST_PER_GEO) != 0) renderBin.addGeometryDlist(renderAtom.rListInfo[i]); } if (removeRAs == null) rb.removeRenderAtomInRMList.remove(this); } else { // Add this renderAtom to the addList if (addRAs == null) { addRAs = renderAtom; renderAtom.nextAdd = null; renderAtom.prevAdd = null; } else { renderAtom.nextAdd = addRAs; renderAtom.prevAdd = null; addRAs.prevAdd = renderAtom; addRAs = renderAtom; } renderAtom.added = this; if (onUpdateList == 0) rb.objUpdateList.add(this); onUpdateList |= NEW_RENDERATOMS_UPDATE; } if (renderBin.localeChanged && !doInfinite) { if (onUpdateList == 0) rb.objUpdateList.add(this); onUpdateList |= LOCALE_CHANGED; } // inform the texture bin that this render molecule is no longer // in zombie state if (numEditingRenderAtoms == 0) { textureBin.incrActiveRenderMolecule(); } numEditingRenderAtoms++; } /** * Removes the given RenderAtom from this RenderMolecule. */ void removeRenderAtom(RenderAtom r) { r.renderMolecule = null; if (r.added == this) { //Remove this renderAtom from the addRAs list // If this is at the head of the list if (r == addRAs) { addRAs = r.nextAdd; if (addRAs != null) addRAs.prevAdd = null; r.nextAdd = null; r.prevAdd = null; } // Somewhere in the middle else { r.prevAdd.nextAdd = r.nextAdd; if (r.nextAdd != null) r.nextAdd.prevAdd = r.prevAdd; r.nextAdd = null; r.prevAdd = null; } r.added = null; r.envSet = null; // If the number of renderAtoms is zero, and it is on the // update list for adding new renderatroms only (not for // bounds update), then remove this rm from the update list // Might be expensive to remove this entry from the renderBin // objUpdateList, just let it call the renderMolecule /* if (addRAs == null) { if (onUpdateList == NEW_RENDERATOMS_UPDATE){ renderBin.objUpdateList.remove(renderBin.objUpdateList.indexOf(this)); } onUpdateList &= ~NEW_RENDERATOMS_UPDATE; } */ } else { // Add this renderAtom to the remove list if (removeRAs == null) { removeRAs = r; r.nextRemove = null; r.prevRemove = null; } else { r.nextRemove = removeRAs; r.prevRemove = null; removeRAs.prevRemove = r; removeRAs = r; } r.removed = this; } // Add it to the removeRenderAtom List , in case the renderMolecule // needs to be removed if (!renderBin.removeRenderAtomInRMList.contains(this)) { renderBin.removeRenderAtomInRMList.add(this); } // decrement the number of editing render atoms in this render molecule numEditingRenderAtoms--; // if there is no more editing render atoms, inform the texture bin // that this render molecule is going to zombie state if (numEditingRenderAtoms == 0) { textureBin.decrActiveRenderMolecule(); } } /** * Recalculates the vwcBounds for a RenderMolecule */ void recalcBounds() { RenderAtomListInfo ra; if (primaryRenderMethod == VirtualUniverse.mc.getDisplayListRenderMethod()) { vwcBounds.set(null); ra = primaryRenderAtomList; while (ra != null) { vwcBounds.combine(ra.renderAtom.localeVwcBounds); ra = ra.next; } } } void evalAlphaUsage(RenderingAttributesRetained renderAttrs, TextureUnitStateRetained[] texUnits) { boolean alphaBlend, alphaTest, textureBlend = false; alphaBlend = TransparencyAttributesRetained.useAlpha(definingTransparency); if (texUnits != null) { for (int i = 0; textureBlend == false && i < texUnits.length; i++) { if (texUnits[i] != null && texUnits[i].texAttrs != null) { textureBlend = textureBlend || (texUnits[i].texAttrs.textureMode == TextureAttributes.BLEND); } } } alphaTest = renderAttrs != null && renderAttrs.alphaTestFunction != RenderingAttributes.ALWAYS; boolean oldUseAlpha = useAlpha; useAlpha = alphaBlend || alphaTest || textureBlend; if( !oldUseAlpha && useAlpha) { GeometryArrayRetained geo = null; if(vertexArrayRenderAtomList != null) geo = (GeometryArrayRetained)vertexArrayRenderAtomList.geometry(); if(geo != null) { if (!(geo instanceof IndexedGeometryArrayRetained) || ((geo.vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0)) { renderBin.addGeometryToLockList(geo); // Add the geometry to the dirty list only if the geometry is by // reference and there is color and we need to use alpha // Issue 113 - ignore multiScreen if ((( geo.vertexFormat & GeometryArray.BY_REFERENCE)!=0) && (geo.c4fAllocated == 0) && ((geo.vertexFormat & GeometryArray.COLOR) != 0) && useAlpha) { renderBin.addDirtyReferenceGeometry(geo); } } } } } final boolean isSwitchOn() { // The switchOn status of the entire RM can be determined // by the switchOn status of any renderAtoms below. // This is possible because renderAtoms generated from a common // switch branch are placed in the same renderMolecule if (primaryRenderAtomList != null) { return primaryRenderAtomList.renderAtom.geometryAtom. source.switchState.lastSwitchOn; } if (vertexArrayRenderAtomList != null) { return vertexArrayRenderAtomList.renderAtom.geometryAtom. source.switchState.lastSwitchOn; } if (separateDlistRenderAtomList != null) { return separateDlistRenderAtomList.renderAtom.geometryAtom. source.switchState.lastSwitchOn; } return false; } /** * Renders this RenderMolecule */ boolean render(Canvas3D cv, int pass, int dirtyBits) { assert pass < 0; boolean isVisible = isSwitchOn(); if (!isVisible) { return false; } isVisible = false; // include this LightBin to the to-be-updated list in Canvas cv.setStateToUpdate(Canvas3D.RENDERMOLECULE_BIT, this); boolean modeSupportDL = true; isNonUniformScale = !trans[localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]].isCongruent(); // We have to dynamically switch between using displaymode // mode or not instead of decide in canBeInDisplayList(), // since polygonAttribute can be change by editable Appearance // or editable polygonAttribute which mode we can't take // advantage of display list mode in many cases just because // there are three special cases to handle. // Another case for punting to vertex array is if pass specifies // something other than -1. That means, we are in the // multi-texturing multi-pass case. Then we'll use vertex array // instead. Or the length of the texCoordSetMap is greater than // the number of texture units supported by the Canvas, then // we'll have to punt to vertex array as well. if ((pass != TextureBin.USE_DISPLAYLIST) || (texCoordSetMapLen > cv.maxTexCoordSets)) { modeSupportDL = false; } /* System.err.println("texCoord " + texCoordSetMapLen + " " + cv.maxTexCoordSets + " " + modeSupportDL); System.err.println("primaryMoleculeType = "+primaryMoleculeType+" primaryRenderAtomList ="+primaryRenderAtomList+" separateDlistRenderAtomList ="+separateDlistRenderAtomList+" vertexArrayRenderAtomList ="+vertexArrayRenderAtomList); */ // Send down the model view only once, if its not of type text if ((primaryMoleculeType & (TEXT3D_MOLECULE| ORIENTEDSHAPE3D_MOLECULE)) == 0) { if (primaryRenderAtomList != null) { if ((primaryRenderMethod != VirtualUniverse.mc.getDisplayListRenderMethod()) || modeSupportDL) { if (primaryMoleculeType != SEPARATE_DLIST_PER_RINFO_MOLECULE) { if (primaryRenderMethod.render(this, cv, primaryRenderAtomList,dirtyBits)) isVisible = true; } else { if (renderBin.dlistRenderMethod.renderSeparateDlistPerRinfo(this, cv, primaryRenderAtomList,dirtyBits)) isVisible = true; } } else { if(cachedVertexArrayRenderMethod.render(this, cv, primaryRenderAtomList, dirtyBits)) { isVisible = true; } } } } else { // TEXT3D or ORIENTEDSHAPE3D if (primaryRenderAtomList != null) { if(primaryRenderMethod.render(this, cv, primaryRenderAtomList, dirtyBits)) { isVisible = true; } } } if (separateDlistRenderAtomList != null) { if (modeSupportDL) { if(renderBin.dlistRenderMethod.renderSeparateDlists(this, cv, separateDlistRenderAtomList, dirtyBits)) { isVisible = true; } } else { if(cachedVertexArrayRenderMethod.render(this, cv, separateDlistRenderAtomList, dirtyBits)) { isVisible = true; } } } // XXXX: In the case of independent primitives such as quads, // it would still be better to call multi draw arrays if (vertexArrayRenderAtomList != null) { if(cachedVertexArrayRenderMethod.render(this, cv, vertexArrayRenderAtomList, dirtyBits)) { isVisible = true; } } return isVisible; } void updateAttributes(Canvas3D cv, int dirtyBits) { boolean setTransparency = false; // If this is a beginning of a frame OR diff. geometryType // then reload everything for the first rendermolecule // System.err.println("updateAttributes"); int bitMask = geometryType | Canvas3D.MATERIAL_DIRTY| Canvas3D.COLORINGATTRS_DIRTY| Canvas3D.TRANSPARENCYATTRS_DIRTY; // If beginning of a frame then reload all the attributes if ((cv.canvasDirty & bitMask) != 0) { if ((geometryType & SURFACE) != 0) { if (definingPolygonAttributes == null) { cv.resetPolygonAttributes(cv.ctx); } else { definingPolygonAttributes.updateNative(cv.ctx); } cv.polygonAttributes = polygonAttributes; } if ((geometryType & LINE) != 0) { if (definingLineAttributes == null) { cv.resetLineAttributes(cv.ctx); } else { definingLineAttributes.updateNative(cv.ctx); } cv.lineAttributes = lineAttributes; } if ((geometryType & POINT) != 0) { if (definingPointAttributes == null) { cv.resetPointAttributes(cv.ctx); } else { definingPointAttributes.updateNative(cv.ctx); } cv.pointAttributes = pointAttributes; } if (definingTransparency == null) { cv.resetTransparency(cv.ctx, geometryType, polygonMode, lineAA, pointAA); } else { definingTransparency.updateNative(cv.ctx, alpha, geometryType, polygonMode, lineAA, pointAA); } cv.transparency = transparency; if (definingMaterial == null) { cv.updateMaterial(cv.ctx, red, green, blue, alpha); } else { definingMaterial.updateNative(cv.ctx, red, green, blue, alpha, enableLighting); } cv.material = material; cv.enableLighting = enableLighting; if (definingColoringAttributes == null) { cv.resetColoringAttributes(cv.ctx, red, green, blue, alpha, enableLighting); } else { definingColoringAttributes.updateNative(cv.ctx, dRed, dBlue, dGreen,alpha, enableLighting); } cv.coloringAttributes = coloringAttributes; // Use Object instead of AppearanceRetained class for // state caching optimation for memory performance cv.appHandle = appHandle; } // assuming neighbor dirty bits ORing is implemented // note that we need to set it to ALL_DIRTY at the // begining of textureBin first and only do the ORing // whenever encounter a non-visible rm else if (cv.renderMolecule != this && (dirtyBits != 0)) { // no need to download states if appHandle is the same if (cv.appHandle != appHandle) { // Check if the attribute bundle in the canvas is the same // as the attribute bundle in this renderMolecule if (cv.transparency != transparency && (dirtyBits & TRANSPARENCY_DIRTY) != 0) { setTransparency = true; if (definingTransparency == null) { cv.resetTransparency(cv.ctx, geometryType, polygonMode, lineAA, pointAA); } else { definingTransparency.updateNative(cv.ctx, alpha, geometryType, polygonMode, lineAA, pointAA); } cv.transparency = transparency; } if (setTransparency || ((cv.enableLighting != enableLighting) || (cv.material != material) && (dirtyBits & MATERIAL_DIRTY) != 0)){ if (definingMaterial == null) { cv.updateMaterial(cv.ctx, red, green, blue, alpha); } else { definingMaterial.updateNative(cv.ctx, red, green, blue, alpha, enableLighting); } cv.material = material; cv.enableLighting = enableLighting; } if (((geometryType & SURFACE) != 0) && cv.polygonAttributes != polygonAttributes && (dirtyBits & POLYGONATTRS_DIRTY) != 0) { if (definingPolygonAttributes == null) { cv.resetPolygonAttributes(cv.ctx); } else { definingPolygonAttributes.updateNative(cv.ctx); } cv.polygonAttributes = polygonAttributes; } if (((geometryType & LINE) != 0) && cv.lineAttributes != lineAttributes && (dirtyBits & LINEATTRS_DIRTY) != 0) { if (definingLineAttributes == null) { cv.resetLineAttributes(cv.ctx); } else { definingLineAttributes.updateNative(cv.ctx); } cv.lineAttributes = lineAttributes; } if (((geometryType & POINT) != 0) && cv.pointAttributes != pointAttributes && (dirtyBits & POINTATTRS_DIRTY) != 0) { if (definingPointAttributes == null) { cv.resetPointAttributes(cv.ctx); } else { definingPointAttributes.updateNative(cv.ctx); } cv.pointAttributes = pointAttributes; } // Use Object instead of AppearanceRetained class for // state caching optimation for memory performance cv.appHandle = appHandle; } // no state caching for color attrs, which can also be // changed by primitive with colors if(setTransparency || ((dirtyBits & COLORINGATTRS_DIRTY) != 0)) { if (definingColoringAttributes == null) { cv.resetColoringAttributes(cv.ctx, red, green, blue, alpha, enableLighting); } else { definingColoringAttributes.updateNative(cv.ctx, dRed, dBlue, dGreen,alpha, enableLighting); } cv.coloringAttributes = coloringAttributes; } } if ((primaryMoleculeType & (TEXT3D_MOLECULE| ORIENTEDSHAPE3D_MOLECULE)) == 0) { /* System.err.println("updateAttributes setModelViewMatrix (1)"); */ Transform3D modelMatrix = trans[localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]]; if (cv.modelMatrix != modelMatrix) { /* System.err.println("updateAttributes setModelViewMatrix (2)"); */ cv.setModelViewMatrix(cv.ctx, cv.vworldToEc.mat, modelMatrix); } } cv.canvasDirty &= ~bitMask; cv.renderMolecule = this; } void transparentSortRender(Canvas3D cv, int pass, TransparentRenderingInfo tinfo) { assert pass < 0; Transform3D modelMatrix = trans[localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]]; // include this LightBin to the to-be-updated list in Canvas cv.setStateToUpdate(Canvas3D.RENDERMOLECULE_BIT, this); boolean modeSupportDL = true; // We have to dynamically switch between using displaymode // mode or not instead of decide in canBeInDisplayList(), // since polygonAttribute can be change by editable Appearance // or editable polygonAttribute which mode we can't take // advantage of display list mode in many cases just because // there are three special cases to handle. // Another case for punting to vertex array is if pass specifies // something other than -1. That means, we are in the // multi-texturing multi-pass case. Then we'll use vertex array // instead. if ((pass != TextureBin.USE_DISPLAYLIST) || (texCoordSetMapLen > cv.maxTexCoordSets)) { modeSupportDL = false; } // System.err.println("r.isOpaque = "+isOpaque+" rinfo = "+tinfo.rInfo+" groupType = "+tinfo.rInfo.groupType); // Only support individual dlist or varray // If this rInfo is a part of a bigger dlist, render as VA // XXXX: What to do with Text3D, Raster, CG? if ((tinfo.rInfo.groupType & RenderAtom.SEPARATE_DLIST_PER_RINFO) != 0) { RenderAtomListInfo save= tinfo.rInfo.next; // Render only one geometry tinfo.rInfo.next = null; // System.err.println("cachedVertexArrayRenderMethod = "+cachedVertexArrayRenderMethod); // System.err.println("tinfo.rInfo = "+tinfo.rInfo); if (modeSupportDL) { renderBin.dlistRenderMethod.renderSeparateDlistPerRinfo(this, cv, tinfo.rInfo, ALL_DIRTY_BITS); } else { cachedVertexArrayRenderMethod.render(this, cv, tinfo.rInfo,ALL_DIRTY_BITS); } tinfo.rInfo.next = save; } else if ((tinfo.rInfo.groupType & (RenderAtom.VARRAY| RenderAtom.DLIST)) != 0) { RenderAtomListInfo save= tinfo.rInfo.next; // Render only one geometry tinfo.rInfo.next = null; // System.err.println("cachedVertexArrayRenderMethod = "+cachedVertexArrayRenderMethod); // System.err.println("tinfo.rInfo = "+tinfo.rInfo); cachedVertexArrayRenderMethod.render(this, cv, tinfo.rInfo, ALL_DIRTY_BITS); tinfo.rInfo.next = save; } // Only support individual dlist or varray else if ((tinfo.rInfo.groupType & RenderAtom.SEPARATE_DLIST_PER_GEO) != 0) { RenderAtomListInfo save= tinfo.rInfo.next; tinfo.rInfo.next = null; if (modeSupportDL) { renderBin.dlistRenderMethod.renderSeparateDlists(this, cv, tinfo.rInfo, ALL_DIRTY_BITS); } else { cachedVertexArrayRenderMethod.render(this, cv, tinfo.rInfo, ALL_DIRTY_BITS); } tinfo.rInfo.next = save; } else { RenderAtomListInfo save= tinfo.rInfo.next; primaryRenderMethod.render(this, cv, primaryRenderAtomList, ALL_DIRTY_BITS); tinfo.rInfo.next = save; } } /** * This render method is used to render the transparency attributes. * It is used in the multi-texture multi-pass case to reset the * transparency attributes to what it was */ void updateTransparencyAttributes(Canvas3D cv) { if (definingTransparency == null) { cv.resetTransparency(cv.ctx, geometryType, polygonMode, lineAA, pointAA); } else { definingTransparency.updateNative(cv.ctx, alpha, geometryType, polygonMode, lineAA, pointAA); } } void updateDisplayList(Canvas3D cv) { // This function only gets called when primaryRenderAtomsList are if (primaryRenderAtomList != null) { ((DisplayListRenderMethod)primaryRenderMethod).buildDisplayList(this, cv); } } void releaseAllPrimaryDisplayListID() { if (primaryRenderAtomList != null) { if (primaryMoleculeType == SEPARATE_DLIST_PER_RINFO_MOLECULE) { RenderAtomListInfo ra = primaryRenderAtomList; int id; while (ra != null) { id = ra.renderAtom.dlistIds[ra.index]; if (id > 0) { VirtualUniverse.mc.freeDisplayListId(new Integer(id)); ra.renderAtom.dlistIds[ra.index] = -1; } ra = ra.next; } } else if (primaryMoleculeType == DLIST_MOLECULE) { if (displayListIdObj != null) { VirtualUniverse.mc.freeDisplayListId(displayListIdObj); displayListIdObj = null; displayListId = -1; } } } } void releaseAllPrimaryDisplayListResources(Canvas3D cv, Context ctx) { if (primaryRenderAtomList != null) { if (primaryMoleculeType == SEPARATE_DLIST_PER_RINFO_MOLECULE) { RenderAtomListInfo ra = primaryRenderAtomList; int id; while (ra != null) { id = ra.renderAtom.dlistIds[ra.index]; if (id > 0) { Canvas3D.freeDisplayList(ctx, id); } ra = ra.next; } } else if (primaryMoleculeType == DLIST_MOLECULE) { if (displayListId > 0) { Canvas3D.freeDisplayList(ctx, displayListId); } } } } void updateAllPrimaryDisplayLists(Canvas3D cv) { // This function only gets called when primaryRenderAtomsList are if (primaryRenderAtomList != null) { if (primaryMoleculeType == SEPARATE_DLIST_PER_RINFO_MOLECULE) { RenderAtomListInfo ra = primaryRenderAtomList; while (ra != null) { renderBin.dlistRenderMethod.buildDlistPerRinfo(ra, this, cv); ra = ra.next; } } else if(primaryMoleculeType == DLIST_MOLECULE) { ((DisplayListRenderMethod)primaryRenderMethod).buildDisplayList(this, cv); } } } void checkEquivalenceWithBothNeighbors(int dirtyBits) { dirtyAttrsAcrossRms = ALL_DIRTY_BITS; if (prev != null) { checkEquivalenceWithLeftNeighbor(prev, dirtyBits); } if (next != null) { next.checkEquivalenceWithLeftNeighbor(this, dirtyBits); } } boolean reloadColor(RenderMolecule rm) { if (((rm.vertexFormat & GeometryArray.COLOR) == 0) || (((rm.vertexFormat & GeometryArray.COLOR) != 0) && (vertexFormat & GeometryArray.COLOR) != 0)) { return false; } return true; } void checkEquivalenceWithLeftNeighbor(RenderMolecule rm, int dirtyBits) { boolean reload_color = reloadColor(rm); // XXXX : For now ignore the dirtyBits being sent in dirtyAttrsAcrossRms = ALL_DIRTY_BITS ; // There is some interdepenency between the different components // in the way it is sent down to the native code // Material is affected by transparency and coloring attrs // Transparency is affected by poly/line/pointAA // ColoringAttrs is affected by material and transaparency int materialColoringDirty = (MATERIAL_DIRTY | TRANSPARENCY_DIRTY | COLORINGATTRS_DIRTY); int transparencyDirty = (TRANSPARENCY_DIRTY| POLYGONATTRS_DIRTY | LINEATTRS_DIRTY | POINTATTRS_DIRTY); if ((dirtyAttrsAcrossRms & POLYGONATTRS_DIRTY) != 0) { if (rm.geometryType == geometryType && (rm.polygonAttributes == polygonAttributes || ((rm.definingPolygonAttributes != null) && (rm.definingPolygonAttributes.equivalent(definingPolygonAttributes))))) dirtyAttrsAcrossRms &= ~POLYGONATTRS_DIRTY; } if ((dirtyAttrsAcrossRms & POINTATTRS_DIRTY) != 0) { if (rm.geometryType == geometryType && ((rm.pointAttributes == pointAttributes) || ((rm.definingPointAttributes != null) && (rm.definingPointAttributes.equivalent(definingPointAttributes))))) dirtyAttrsAcrossRms &= ~POINTATTRS_DIRTY; } if ((dirtyAttrsAcrossRms & LINEATTRS_DIRTY) != 0) { if (rm.geometryType == geometryType && ((rm.lineAttributes == lineAttributes) || ((rm.definingLineAttributes != null) && (rm.definingLineAttributes.equivalent(definingLineAttributes))))) dirtyAttrsAcrossRms &= ~LINEATTRS_DIRTY; } if ((dirtyAttrsAcrossRms & materialColoringDirty) != 0) { if (materialEquivalent(rm, reload_color)) { dirtyAttrsAcrossRms &= ~MATERIAL_DIRTY; } else { dirtyAttrsAcrossRms |= MATERIAL_DIRTY; } } if ((dirtyAttrsAcrossRms & materialColoringDirty) != 0) { if (coloringEquivalent(rm, reload_color)) { dirtyAttrsAcrossRms &= ~COLORINGATTRS_DIRTY; } else { dirtyAttrsAcrossRms |= COLORINGATTRS_DIRTY; } } if ((dirtyAttrsAcrossRms & transparencyDirty) != 0) { if (transparencyEquivalent(rm)) { dirtyAttrsAcrossRms &= ~TRANSPARENCY_DIRTY; } else { dirtyAttrsAcrossRms |= TRANSPARENCY_DIRTY; } } } void translate() { // System.err.println("onUpdateList = "+onUpdateList+" renderBin.localeChanged = "+renderBin.localeChanged+" rm = "+this); int i = localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]; localeLocalToVworld[i].mat[0] = localToVworld[i].mat[0]; localeLocalToVworld[i].mat[1] = localToVworld[i].mat[1]; localeLocalToVworld[i].mat[2] = localToVworld[i].mat[2]; localeLocalToVworld[i].mat[3] = localToVworld[i].mat[3] + localeTranslation.x ; localeLocalToVworld[i].mat[4] = localToVworld[i].mat[4]; localeLocalToVworld[i].mat[5] = localToVworld[i].mat[5]; localeLocalToVworld[i].mat[6] = localToVworld[i].mat[6]; localeLocalToVworld[i].mat[7] = localToVworld[i].mat[7]+ localeTranslation.y; localeLocalToVworld[i].mat[8] = localToVworld[i].mat[8]; localeLocalToVworld[i].mat[9] = localToVworld[i].mat[9]; localeLocalToVworld[i].mat[10] = localToVworld[i].mat[10]; localeLocalToVworld[i].mat[11] = localToVworld[i].mat[11]+ localeTranslation.z; localeLocalToVworld[i].mat[12] = localToVworld[i].mat[12]; localeLocalToVworld[i].mat[13] = localToVworld[i].mat[13]; localeLocalToVworld[i].mat[14] = localToVworld[i].mat[14]; localeLocalToVworld[i].mat[15] = localToVworld[i].mat[15]; // System.err.println("rm = "+this+" localTovworld = "+localeLocalToVworld[i]+" localeTranslation = "+localeTranslation); } boolean isOpaque() { if ((geometryType & SURFACE) != 0) { if (definingPolygonAttributes != null) { if ((definingPolygonAttributes.polygonMode == PolygonAttributes.POLYGON_POINT) && (definingPointAttributes != null) && definingPointAttributes.pointAntialiasing) { return false; } else if ((definingPolygonAttributes.polygonMode == PolygonAttributes.POLYGON_LINE) && (definingLineAttributes != null) && definingLineAttributes.lineAntialiasing) { return false; } } } else if ((geometryType & POINT) != 0) { if ((definingPointAttributes != null) && definingPointAttributes.pointAntialiasing) { return false; } } else if ((geometryType & LINE) != 0) { if ((definingLineAttributes != null) && definingLineAttributes.lineAntialiasing) { return false; } } return !TransparencyAttributesRetained.useAlpha(definingTransparency); } boolean updateNodeComponent() { // System.err.println("soleUser = "+soleUser+" rm = "+this); if ((soleUserCompDirty & MATERIAL_DIRTY) != 0) { // Note: this RM is a soleUser(only then this function is called) // and if definingMaterial == material, then the material is freq // changed and therefore is not cloned, only other time it can be // same is when an equivalent material is added in and this can // never be true when a bin is a soleUser of a appearance // Evaluate before replacing the old Value if (soleUser) { boolean cloned = definingMaterial != null && definingMaterial != material; // System.err.println("===>Rm = "+this); // System.err.println("===> updating node component, cloned = "+cloned+" material.changedFrequent = "+material.changedFrequent); // System.err.println("===> definingMaterial ="+definingMaterial+" material = "+material); material = ((AppearanceRetained)appHandle).material; if (material == null) definingMaterial = null; else { if (material.changedFrequent != 0) { definingMaterial = material; } else { // If the one replaced is a cloned copy, then .. if (cloned) { definingMaterial.set(material); } else { definingMaterial = (MaterialRetained)material.clone(); } } } } evalMaterialCachedState(); } if ((soleUserCompDirty & LINEATTRS_DIRTY) != 0) { if (soleUser) { // Evaluate before replacing the old Value boolean cloned = definingLineAttributes != null && definingLineAttributes != lineAttributes; lineAttributes = ((AppearanceRetained)appHandle).lineAttributes; if (lineAttributes == null) { lineAA = false; definingLineAttributes = null; } else { if (lineAttributes.changedFrequent != 0) { definingLineAttributes = lineAttributes; } else { // If the one replaced is a cloned copy, then .. if (cloned) { definingLineAttributes.set(lineAttributes); } else { definingLineAttributes = (LineAttributesRetained)lineAttributes.clone(); } } lineAA = definingLineAttributes.lineAntialiasing; } } else { lineAA = definingLineAttributes.lineAntialiasing; } } if ((soleUserCompDirty & POINTATTRS_DIRTY) != 0) { if (soleUser) { // Evaluate before replacing the old Value boolean cloned = definingPointAttributes != null && definingPointAttributes != pointAttributes; pointAttributes = ((AppearanceRetained)appHandle).pointAttributes; if (pointAttributes == null) { pointAA = false; definingPointAttributes = null; } else { if (pointAttributes.changedFrequent != 0) { definingPointAttributes = pointAttributes; } else { // If the one replaced is a cloned copy, then .. if (cloned) { definingPointAttributes.set(pointAttributes); } else { definingPointAttributes = (PointAttributesRetained)pointAttributes.clone(); } } pointAA = definingPointAttributes.pointAntialiasing; } } else { pointAA = definingPointAttributes.pointAntialiasing; } } if ((soleUserCompDirty & POLYGONATTRS_DIRTY) != 0) { if (soleUser) { // Evaluate before replacing the old Value boolean cloned = definingPolygonAttributes != null && definingPolygonAttributes != polygonAttributes; polygonAttributes = ((AppearanceRetained)appHandle).polygonAttributes; if (polygonAttributes == null) { polygonMode = PolygonAttributes.POLYGON_FILL; definingPolygonAttributes = null; } else { if (polygonAttributes.changedFrequent != 0) { definingPolygonAttributes = polygonAttributes; } else { // If the one replaced is a cloned copy, then .. if (cloned) { definingPolygonAttributes.set(polygonAttributes); } else { definingPolygonAttributes = (PolygonAttributesRetained)polygonAttributes.clone(); } } polygonMode = definingPolygonAttributes.polygonMode; } } else { polygonMode = definingPolygonAttributes.polygonMode; } if (polygonMode == PolygonAttributes.POLYGON_LINE) { geometryType |= LINE; } else if (polygonMode == PolygonAttributes.POLYGON_POINT) { geometryType |= POINT; } } if ((soleUserCompDirty & TRANSPARENCY_DIRTY) != 0) { if (soleUser) { // Evaluate before replacing the old Value boolean cloned = definingTransparency != null && definingTransparency != transparency; transparency = ((AppearanceRetained)appHandle).transparencyAttributes; if (transparency == null) { alpha = 1.0f ; definingTransparency = null; } else { if (transparency.changedFrequent != 0) { definingTransparency = transparency; } else { // If the one replaced is a cloned copy, then .. if (cloned) { definingTransparency.set(transparency); } else { definingTransparency = (TransparencyAttributesRetained)transparency.clone(); } } alpha = 1.0f - definingTransparency.transparency; } } else { alpha = 1.0f - definingTransparency.transparency; } } if ((soleUserCompDirty & COLORINGATTRS_DIRTY) != 0) { if (soleUser) { // Evaluate before replacing the old Value boolean cloned = definingColoringAttributes != null && definingColoringAttributes != coloringAttributes; coloringAttributes = ((AppearanceRetained)appHandle).coloringAttributes; // System.err.println("coloringAttributes and soleUser"); // System.err.println("coloringAttributes ="+coloringAttributes); if (coloringAttributes == null) { definingColoringAttributes = null; red = 1.0f; green = 1.0f; blue = 1.0f; } else { // System.err.println("coloringAttributes.changedFrequent = "+coloringAttributes.changedFrequent ); if (coloringAttributes.changedFrequent != 0) { definingColoringAttributes = coloringAttributes; } else { // If the one replaced is a cloned copy, then .. if (cloned) { definingColoringAttributes.set(coloringAttributes); } else { definingColoringAttributes = (ColoringAttributesRetained)coloringAttributes.clone(); } } red = definingColoringAttributes.color.x; green = definingColoringAttributes.color.y; blue = definingColoringAttributes.color.z; } } else { red = definingColoringAttributes.color.x; green = definingColoringAttributes.color.y; blue = definingColoringAttributes.color.z; } } // System.err.println("rm = "+this+"red = "+red+" green = "+green+" blue = "+blue); boolean newVal = isOpaque() || inOrderedGroup; return (isOpaqueOrInOG != newVal); } // Issue 129: method to add or remove all rendering atoms in this // RenderMolecule to or from the transparent info list when we are // in depth sorted transparency mode and the RenderMolecule // changes from opaque to transparent or vice versa. void addRemoveTransparentObject(RenderBin renderBin, boolean add) { addRemoveTransparentObject(renderBin, add, primaryRenderAtomList); addRemoveTransparentObject(renderBin, add, separateDlistRenderAtomList); addRemoveTransparentObject(renderBin, add, vertexArrayRenderAtomList); } private void addRemoveTransparentObject(RenderBin renderBin, boolean add, RenderAtomListInfo rinfo) { while (rinfo != null) { if (add) { renderBin.addTransparentObject(rinfo.renderAtom); } else { renderBin.removeTransparentObject(rinfo.renderAtom); } rinfo = rinfo.next; } } void evalMaterialCachedState() { if (definingMaterial == null) { enableLighting = false;; definingMaterial = null; dRed = 1.0f; dGreen = 1.0f; dBlue = 1.0f; } else { if ((geometryType & RASTER) != 0) { enableLighting = false; dRed = 1.0f; dGreen = 1.0f; dBlue = 1.0f; } else { if (normalPresent) enableLighting = definingMaterial.lightingEnable; else enableLighting = false; dRed = definingMaterial.diffuseColor.x; dGreen = definingMaterial.diffuseColor.y; dBlue = definingMaterial.diffuseColor.z; } } } void markBitsAsDirty(int leftBits, int rightBits) { if (prev != null) { checkEquivalenceWithLeftNeighbor(prev, leftBits); prev.soleUserCompDirty &= ~ALL_DIRTY_BITS; } else if (prevMap != null) { checkEquivalenceWithLeftNeighbor(prevMap, leftBits); prevMap.soleUserCompDirty &= ~ALL_DIRTY_BITS; } if (next != null) { if ((next.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { next.checkEquivalenceWithLeftNeighbor(this, rightBits); } else { next.soleUserCompDirty = rightBits; } } else if (nextMap != null) { if ((nextMap.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { nextMap.checkEquivalenceWithLeftNeighbor(this, rightBits); } else { nextMap.soleUserCompDirty = rightBits; } } } void handleMaterialEquivalence() { // Check if it has equivalent material to any of the "non-dirty" // renderMolecules before this one RenderMolecule curPrevRm = null; RenderMolecule curNextRm = null; boolean found = false; int leftBits = ALL_DIRTY_BITS; int rightBits = ALL_DIRTY_BITS; if (prev != null) { curPrevRm = prev.prev; if (materialEquivalent(prev, reloadColor(prev))) { found = true; leftBits = (((soleUserCompDirty | prev.soleUserCompDirty) &ALL_DIRTY_BITS) & ~MATERIAL_DIRTY); rightBits = (soleUserCompDirty & ALL_DIRTY_BITS); markBitsAsDirty(leftBits, rightBits); } } else if (!found && next != null) { curNextRm = next.next; if (materialEquivalent(next, reloadColor(next))) { found = true; int bits = 0; if (prev != null) bits = prev.soleUserCompDirty; else if (prevMap != null) bits = prevMap.soleUserCompDirty; leftBits = ((soleUserCompDirty |bits) &ALL_DIRTY_BITS); rightBits = ((soleUserCompDirty & ALL_DIRTY_BITS) & ~MATERIAL_DIRTY); markBitsAsDirty(leftBits, rightBits); } } // try place it next to a equivalent material on the left while (!found && curPrevRm != null) { if (materialEquivalent(curPrevRm, reloadColor(curPrevRm))) { found = true; // Remove the renderMolecule from it place prev.next = next; prev.nextMap = nextMap; if (next != null) { next.prev = prev; if ((next.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { next.checkEquivalenceWithLeftNeighbor(prev, ALL_DIRTY_BITS); } else { next.soleUserCompDirty = ALL_DIRTY_BITS; } } else if (nextMap != null) { nextMap.prevMap = prev; if ((nextMap.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { nextMap.checkEquivalenceWithLeftNeighbor(prev,ALL_DIRTY_BITS); } else { nextMap.soleUserCompDirty |= ALL_DIRTY_BITS; } } // Insert it after the equivalent RM next = curPrevRm.next; nextMap = curPrevRm.nextMap; curPrevRm.nextMap = null; if (next != null) { next.prev = this; } else if (nextMap != null) { nextMap.prevMap = this; } prev = curPrevRm; curPrevRm.next = this; leftBits = (ALL_DIRTY_BITS & ~MATERIAL_DIRTY); markBitsAsDirty(leftBits, ALL_DIRTY_BITS); } curPrevRm = curPrevRm.prev; } // Check if it has equivalent material to any of the renderMolecules after // this one while (!found && curNextRm != null) { if (materialEquivalent(curNextRm, reloadColor(curNextRm))) { found = true; // switch the pointers next.prev = prev; next.prevMap = prevMap; if (prev != null) { prev.next = next; if ((next.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { next.checkEquivalenceWithLeftNeighbor(prev, ALL_DIRTY_BITS); } else { next.soleUserCompDirty = ALL_DIRTY_BITS; } } else if (prevMap != null) { prevMap.nextMap = next; if ((next.soleUserCompDirty & ALL_DIRTY_BITS) == 0) { next.checkEquivalenceWithLeftNeighbor(prevMap, ALL_DIRTY_BITS); } else { next.soleUserCompDirty = ALL_DIRTY_BITS; } } // Insert it before the equivalent RM prev = curNextRm.prev; prevMap = curNextRm.prevMap; curNextRm.prevMap = null; if (curNextRm.prev != null) { curNextRm.prev.next = this; } else if (prevMap != null) { prevMap.nextMap = this; } next = curNextRm; curNextRm.prev = this; rightBits = (ALL_DIRTY_BITS & ~MATERIAL_DIRTY); markBitsAsDirty(ALL_DIRTY_BITS, rightBits); } curNextRm = curNextRm.next; } // If there are no equivalent ones, evaluate the dirty bits in the current place if (!found) { if (prev != null) { leftBits = ((soleUserCompDirty|prev.soleUserCompDirty) & ALL_DIRTY_BITS); } else if (prevMap != null) { leftBits = ((soleUserCompDirty|prevMap.soleUserCompDirty) & ALL_DIRTY_BITS); } if (next != null) { rightBits = ((soleUserCompDirty|next.soleUserCompDirty) & ALL_DIRTY_BITS); } else if (nextMap != null) { rightBits = ((soleUserCompDirty|nextMap.soleUserCompDirty) & ALL_DIRTY_BITS); } markBitsAsDirty(leftBits, rightBits); } } void reEvaluateEquivalence () { // If Material changed, reInsert next to a equivalent material under // the same transform group // to prevent unnecessary material download // This RM may have been evaluated due to an other RM is the same list // If not, ... if ((soleUserCompDirty & ALL_DIRTY_BITS) != 0) { if ((soleUserCompDirty & MATERIAL_DIRTY) != 0) { handleMaterialEquivalence(); } else { int dirtyBits = (soleUserCompDirty & ALL_DIRTY_BITS); if (prev != null) { checkEquivalenceWithLeftNeighbor(prev, ((dirtyBits|prev.soleUserCompDirty) & ALL_DIRTY_BITS)); prev.soleUserCompDirty = 0; } else if (prevMap != null) { checkEquivalenceWithLeftNeighbor(prevMap, ((dirtyBits|prevMap.soleUserCompDirty) & ALL_DIRTY_BITS)); prevMap.soleUserCompDirty = 0; } if (next != null) { next.checkEquivalenceWithLeftNeighbor(this,((next.soleUserCompDirty|soleUserCompDirty) & ALL_DIRTY_BITS)); } else if (nextMap != null) { nextMap.checkEquivalenceWithLeftNeighbor(this,((nextMap.soleUserCompDirty | soleUserCompDirty) & ALL_DIRTY_BITS)); } } } soleUserCompDirty &= ~ALL_DIRTY_BITS; } boolean materialEquivalent(RenderMolecule rm, boolean reloadColor) { if (!reloadColor) { if (((this.material == rm.material) || ((rm.definingMaterial != null) && (rm.definingMaterial.equivalent(definingMaterial)))) && rm.alpha == alpha && enableLighting == rm.enableLighting && (enableLighting || (!enableLighting && rm.red ==red && rm.green == green && rm.blue == blue))) { return true; } } return false; } boolean coloringEquivalent(RenderMolecule rm, boolean reload_color) { if (!reload_color) { if (((rm.coloringAttributes == coloringAttributes) || ((rm.definingColoringAttributes != null) && (rm.definingColoringAttributes.equivalent(definingColoringAttributes)))) && (!enableLighting || (enableLighting && (dRed == rm.dRed && dBlue == rm.dBlue && dGreen == rm.dGreen)))) { return true; } } return false; } boolean transparencyEquivalent(RenderMolecule rm) { if (((rm.transparency == transparency) || ((rm.definingTransparency != null) && (rm.definingTransparency.equivalent(definingTransparency))) && (rm.definingTransparency.transparencyMode < TransparencyAttributes.SCREEN_DOOR && blendOn() == rm.blendOn()))) { return true; } return false; } boolean blendOn() { if (lineAA && ((((geometryType & LINE) != 0) || polygonMode == PolygonAttributes.POLYGON_LINE))) { return true; } if (pointAA && ((((geometryType & POINT) != 0) || polygonMode == PolygonAttributes.POLYGON_POINT))) { return true; } return false; } @Override VirtualUniverse getVirtualUniverse() { return null; } void handleLocaleChange() { if (locale == renderBin.locale) { if (localToVworld != localeLocalToVworld) { localeLocalToVworld = localToVworld; localeTranslation = null; } } else { // Using the localToVworl then, go back to making a new copy if (localeTranslation == null) { localeLocalToVworld = new Transform3D[2]; localeLocalToVworld[0] = new Transform3D(); localeLocalToVworld[1] = new Transform3D(); localeTranslation = new Vector3d(); locale.hiRes.difference(renderBin.locale.hiRes, localeTranslation); translate(); int i = localToVworldIndex[NodeRetained.CURRENT_LOCAL_TO_VWORLD]; localeLocalToVworld[i].mat[0] = localToVworld[i].mat[0]; localeLocalToVworld[i].mat[1] = localToVworld[i].mat[1]; localeLocalToVworld[i].mat[2] = localToVworld[i].mat[2]; localeLocalToVworld[i].mat[3] = localToVworld[i].mat[3] + localeTranslation.x ; localeLocalToVworld[i].mat[4] = localToVworld[i].mat[4]; localeLocalToVworld[i].mat[5] = localToVworld[i].mat[5]; localeLocalToVworld[i].mat[6] = localToVworld[i].mat[6]; localeLocalToVworld[i].mat[7] = localToVworld[i].mat[7]+ localeTranslation.y; localeLocalToVworld[i].mat[8] = localToVworld[i].mat[8]; localeLocalToVworld[i].mat[9] = localToVworld[i].mat[9]; localeLocalToVworld[i].mat[10] = localToVworld[i].mat[10]; localeLocalToVworld[i].mat[11] = localToVworld[i].mat[11]+ localeTranslation.z; localeLocalToVworld[i].mat[12] = localToVworld[i].mat[12]; localeLocalToVworld[i].mat[13] = localToVworld[i].mat[13]; localeLocalToVworld[i].mat[14] = localToVworld[i].mat[14]; localeLocalToVworld[i].mat[15] = localToVworld[i].mat[15]; } } trans = localeLocalToVworld; } /** * updateNodeComponentCheck is called for each soleUser RenderMolecule * into which new renderAtom has been added. This method is called before * updateNodeComponent() to allow RenderMolecule to catch any node * component changes that have been missed because the changes * come when there is no active renderAtom associated with the * TextureBin. See bug# 4503926 for details. */ @Override public void updateNodeComponentCheck() { // If the renderMolecule has been removed, do nothing .. if ((onUpdateList &ON_UPDATE_CHECK_LIST ) == 0) return; onUpdateList &= ~ON_UPDATE_CHECK_LIST; NodeComponentRetained nc = (NodeComponentRetained)appHandle; if ((nc.compChanged & RM_COMPONENTS) != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= (nc.compChanged & RM_COMPONENTS); } if (definingPolygonAttributes != null && definingPolygonAttributes == polygonAttributes) { if (definingPolygonAttributes.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= POLYGONATTRS_DIRTY; } } if (definingLineAttributes != null && definingLineAttributes == lineAttributes) { if (definingLineAttributes.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= LINEATTRS_DIRTY; } } if (definingPointAttributes != null && definingPointAttributes.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= POINTATTRS_DIRTY; } if (definingMaterial != null && definingMaterial == material) { if (definingMaterial.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= MATERIAL_DIRTY; } } if (definingColoringAttributes != null && definingColoringAttributes == coloringAttributes) { if (definingColoringAttributes.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= COLORINGATTRS_DIRTY; } } if (definingTransparency != null && definingTransparency == transparency) { if (definingTransparency.compChanged != 0) { if ((soleUserCompDirty& ALL_DIRTY_BITS) == 0 ) { renderBin.rmUpdateList.add(this); } soleUserCompDirty |= TRANSPARENCY_DIRTY; } } } }