/* * 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 java.util.ArrayList; /** * The AttributeBin manages a collection of TextureBin objects. * All objects in the AttributeBin share the same RenderingAttributes */ class AttributeBin extends Object implements ObjectUpdate { /** * The RenderingAttributes for this AttributeBin */ RenderingAttributesRetained definingRenderingAttributes = null; /** * The RenderBin for this object */ RenderBin renderBin = null; /** * The EnvirionmentSet that this AttributeBin resides */ EnvironmentSet environmentSet = null; /** * The references to the next and previous AttributeBins in the * list. */ AttributeBin next = null; AttributeBin prev = null; /** * The list of ShaderBins in this AttributeBin */ ShaderBin shaderBinList = null; /** * List of shaderBins to be added next frame */ ArrayList addShaderBins = new ArrayList(); /** * If the RenderingAttribute component of the appearance will be changed * frequently, then confine it to a separate bin */ boolean soleUser = false; AppearanceRetained app = null; int onUpdateList = 0; static int ON_OBJ_UPDATE_LIST = 0x1; static int ON_CHANGED_FREQUENT_UPDATE_LIST = 0x2; // Cache it outside, to avoid the "if" check in renderMethod // for whether the definingRendering attrs is non-null; boolean ignoreVertexColors = false; // XXXX: use definingMaterial etc. instead of these // when sole user is completely implement RenderingAttributesRetained renderingAttrs; int numEditingShaderBins = 0; AttributeBin(AppearanceRetained app, RenderingAttributesRetained renderingAttributes, RenderBin rBin) { reset(app, renderingAttributes, rBin); } void reset(AppearanceRetained app, RenderingAttributesRetained renderingAttributes, RenderBin rBin) { prev = null; next = null; shaderBinList = null; onUpdateList = 0; numEditingShaderBins = 0; renderingAttrs = renderingAttributes; renderBin = rBin; // Issue 249 - check for sole user only if property is set soleUser = false; if (VirtualUniverse.mc.allowSoleUser) { if (app != null) { soleUser = ((app.changedFrequent & AppearanceRetained.RENDERING) != 0); } } //System.err.println("soleUser = "+soleUser+" renderingAttributes ="+renderingAttributes); // Set the appearance only for soleUser case if (soleUser) this.app = app; else app = null; if (renderingAttributes != null) { if (renderingAttributes.changedFrequent != 0) { definingRenderingAttributes = renderingAttributes; if ((onUpdateList & ON_CHANGED_FREQUENT_UPDATE_LIST) == 0 ) { renderBin.aBinUpdateList.add(this); onUpdateList |= AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST; } } else { if (definingRenderingAttributes != null) { definingRenderingAttributes.set(renderingAttributes); } else { definingRenderingAttributes = (RenderingAttributesRetained)renderingAttributes.clone(); } } ignoreVertexColors = definingRenderingAttributes.ignoreVertexColors; } else { definingRenderingAttributes = null; ignoreVertexColors = false; } } /** * This tests if the given attributes match this AttributeBin */ boolean equals(RenderingAttributesRetained renderingAttributes, RenderAtom ra) { // 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 & AppearanceRetained.RENDERING) != 0))) { if (app == ra.geometryAtom.source.appearance) { // if this AttributeBin 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, // rendering attributes reference could have been changed. // Example, application could have detached an appearance, // made changes to the reference, and then // reattached the appearance. In this case, the rendering // attributes reference change would not have reflected to // the AttributeBin if (numEditingShaderBins == 0) { if ((onUpdateList & ON_CHANGED_FREQUENT_UPDATE_LIST) == 0) { renderBin.aBinUpdateList.add(this); onUpdateList |= AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST; } } return true; } else { return false; } } // 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 (definingRenderingAttributes != null) { if ((this.definingRenderingAttributes.changedFrequent != 0) || (renderingAttributes !=null && renderingAttributes.changedFrequent != 0)) if (definingRenderingAttributes == renderingAttributes) { if (definingRenderingAttributes.compChanged != 0) { if ((onUpdateList & ON_CHANGED_FREQUENT_UPDATE_LIST) == 0 ) { renderBin.aBinUpdateList.add(this); onUpdateList |= AttributeBin.ON_CHANGED_FREQUENT_UPDATE_LIST; } } } else { return false; } else if (!definingRenderingAttributes.equivalent(renderingAttributes)) { return false; } } else if (renderingAttributes != null) { return false; } return (true); } @Override public void updateObject() { ShaderBin sb; int i, size; size = addShaderBins.size(); if (size > 0) { sb = addShaderBins.get(0); if (shaderBinList == null) { shaderBinList = sb; } else { sb.next = shaderBinList; shaderBinList.prev = sb; shaderBinList = sb; } for (i = 1; i < size ; i++) { sb = addShaderBins.get(i); sb.next = shaderBinList; shaderBinList.prev = sb; shaderBinList = sb; } } addShaderBins.clear(); onUpdateList &= ~ON_OBJ_UPDATE_LIST; } /** * Adds the given shaderBin to this AttributeBin. */ void addShaderBin(ShaderBin sb, RenderBin rb, ShaderAppearanceRetained sApp) { sb.attributeBin = this; if(sApp != null) { // ShaderBin should reference to the mirror components. -- JADA. // System.err.println("AttributeBin : sApp.isMirror = " + sApp.isMirror); assert(sApp.isMirror); sb.shaderProgram = sApp.shaderProgram; sb.shaderAttributeSet = sApp.shaderAttributeSet; } sb.shaderAppearance = sApp; // TODO : JADA - sort by ShaderProgram to avoid state trashing. addShaderBins.add(sb); if ((onUpdateList & ON_OBJ_UPDATE_LIST) == 0) { onUpdateList |= ON_OBJ_UPDATE_LIST; rb.objUpdateList.add(this); } } /** * Removes the given shaderBin from this AttributeBin. */ void removeShaderBin(ShaderBin sb) { // If the shaderBin being remove is contained in addShaderBins, // then remove the shadereBin from the addList if (addShaderBins.contains(sb)) { addShaderBins.remove(addShaderBins.indexOf(sb)); } else { if (sb.prev == null) { // At the head of the list shaderBinList = sb.next; if (sb.next != null) { sb.next.prev = null; } } else { // In the middle or at the end. sb.prev.next = sb.next; if (sb.next != null) { sb.next.prev = sb.prev; } } } sb.clear(); if (shaderBinList == null && addShaderBins.size() == 0 ) { // Note: Removal of this attributebin as a user of the rendering // atttrs is done during removeRenderAtom() in RenderMolecule.java environmentSet.removeAttributeBin(this); } } /** * Renders this AttributeBin */ void render(Canvas3D cv) { ShaderBin sb; boolean visible = (definingRenderingAttributes == null || definingRenderingAttributes.visible); if ( (renderBin.view.viewCache.visibilityPolicy == View.VISIBILITY_DRAW_VISIBLE && !visible) || (renderBin.view.viewCache.visibilityPolicy == View.VISIBILITY_DRAW_INVISIBLE && visible)) { return; } // include this AttributeBin to the to-be-updated list in Canvas cv.setStateToUpdate(Canvas3D.ATTRIBUTEBIN_BIT, this); sb = shaderBinList; while (sb != null) { sb.render(cv); sb = sb.next; } } void updateAttributes(Canvas3D cv) { if ((cv.canvasDirty & Canvas3D.ATTRIBUTEBIN_DIRTY) != 0) { // Update Attribute Bundles if (definingRenderingAttributes == null) { cv.resetRenderingAttributes(cv.ctx, cv.depthBufferWriteEnableOverride, cv.depthBufferEnableOverride); } else { definingRenderingAttributes.updateNative( cv, cv.depthBufferWriteEnableOverride, cv.depthBufferEnableOverride); } cv.renderingAttrs = renderingAttrs; } else if (cv.renderingAttrs != renderingAttrs && cv.attributeBin != this) { // Update Attribute Bundles if (definingRenderingAttributes == null) { cv.resetRenderingAttributes( cv.ctx, cv.depthBufferWriteEnableOverride, cv.depthBufferEnableOverride); } else { definingRenderingAttributes.updateNative( cv, cv.depthBufferWriteEnableOverride, cv.depthBufferEnableOverride); } cv.renderingAttrs = renderingAttrs; } cv.attributeBin = this; cv.canvasDirty &= ~Canvas3D.ATTRIBUTEBIN_DIRTY; } void updateNodeComponent() { // May be in the freelist already (due to freq bit changing) // if so, don't update anything if ((onUpdateList & ON_CHANGED_FREQUENT_UPDATE_LIST) != 0) { if (soleUser) { boolean cloned = definingRenderingAttributes != null && definingRenderingAttributes != renderingAttrs; renderingAttrs = app.renderingAttributes; if (renderingAttrs == null) { definingRenderingAttributes = null; ignoreVertexColors = false; } else { if (renderingAttrs.changedFrequent != 0) { definingRenderingAttributes = renderingAttrs; } else { if (cloned) { definingRenderingAttributes.set(renderingAttrs); } else { definingRenderingAttributes = (RenderingAttributesRetained)renderingAttrs.clone(); } } ignoreVertexColors = definingRenderingAttributes.ignoreVertexColors; } } else { ignoreVertexColors = definingRenderingAttributes.ignoreVertexColors; } } onUpdateList &= ~ON_CHANGED_FREQUENT_UPDATE_LIST; } void incrActiveShaderBin() { numEditingShaderBins++; } void decrActiveShaderBin() { numEditingShaderBins--; } void updateFromShaderBin(RenderAtom ra) { AppearanceRetained raApp = ra.geometryAtom.source.appearance; RenderingAttributesRetained rAttrs = (raApp == null)? null : raApp.renderingAttributes; if (!soleUser && renderingAttrs != rAttrs) { // no longer sole user renderingAttrs = definingRenderingAttributes; } } }