0001: /*
0002: * $RCSfile: TextureBin.java,v $
0003: *
0004: * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0006: *
0007: * This code is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU General Public License version 2 only, as
0009: * published by the Free Software Foundation. Sun designates this
0010: * particular file as subject to the "Classpath" exception as provided
0011: * by Sun in the LICENSE file that accompanied this code.
0012: *
0013: * This code is distributed in the hope that it will be useful, but WITHOUT
0014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0016: * version 2 for more details (a copy is included in the LICENSE file that
0017: * accompanied this code).
0018: *
0019: * You should have received a copy of the GNU General Public License version
0020: * 2 along with this work; if not, write to the Free Software Foundation,
0021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0022: *
0023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0024: * CA 95054 USA or visit www.sun.com if you need additional information or
0025: * have any questions.
0026: *
0027: * $Revision: 1.10 $
0028: * $Date: 2008/02/28 20:17:31 $
0029: * $State: Exp $
0030: */
0031:
0032: package javax.media.j3d;
0033:
0034: import javax.vecmath.*;
0035: import java.util.*;
0036:
0037: /**
0038: * The TextureBin manages a collection of TextureSetting objects.
0039: * All objects in the TextureBin share the same Texture reference.
0040: */
0041:
0042: //class TextureBin extends Object implements ObjectUpdate, NodeComponentUpdate {
0043: class TextureBin extends Object implements ObjectUpdate {
0044:
0045: TextureUnitStateRetained[] texUnitState = null;
0046:
0047: // last active texture unit
0048: private int lastActiveTexUnitIndex;
0049:
0050: // number of active texture unit
0051: private int numActiveTexUnit;
0052:
0053: /**
0054: * The RenderBin for this object
0055: */
0056: RenderBin renderBin = null;
0057:
0058: /**
0059: * The EnvironmentSet that this TextureBin resides
0060: */
0061: EnvironmentSet environmentSet = null;
0062:
0063: /**
0064: * The AttributeBin that this TextureBin resides
0065: */
0066: AttributeBin attributeBin = null;
0067:
0068: /**
0069: * The ShaderBin that this TextureBin resides
0070: */
0071: ShaderBin shaderBin = null;
0072:
0073: /**
0074: * The references to the next and previous TextureBins in the
0075: * list.
0076: */
0077: TextureBin next = null;
0078: TextureBin prev = null;
0079:
0080: /**
0081: * Oring of the equivalence bits for all appearance attrs under
0082: * this renderBin
0083: */
0084: int equivalent = 0;
0085:
0086: /**
0087: * If any of the texture reference in an appearance is frequently
0088: * changable, then a separate TextureBin will be created for this
0089: * appearance, and this TextureBin is marked as the sole user of
0090: * this appearance, and app will be pointing to the appearance
0091: * being referenced by this TextureBin. Otherwise, app is null
0092: */
0093: AppearanceRetained app = null;
0094:
0095: /**
0096: * Sole user node component dirty mask. The first bit is reserved
0097: * for node component reference dirty bit. It is set if any of the
0098: * texture related node component reference in the appearance is
0099: * being modified. The second bit onwords are for the individual
0100: * TextureUnitState dirty bit. The ith bit set means the (i-1)
0101: * texture unit state is modified. Note, this mask only supports
0102: * 30 texture unit states. If the appearance uses more than 31
0103: * texture unit states, then the modification of the 32nd texture
0104: * unit state and up will have the first bit set, that means
0105: * the TextureBin will be reset, rather than only the particular
0106: * texture unit state will be reset.
0107: */
0108: int soleUserCompDirty;
0109:
0110: static final int SOLE_USER_DIRTY_REF = 0x1;
0111: static final int SOLE_USER_DIRTY_TA = 0x2;
0112: static final int SOLE_USER_DIRTY_TC = 0x4;
0113: static final int SOLE_USER_DIRTY_TEXTURE = 0x8;
0114: static final int SOLE_USER_DIRTY_TUS = 0x10;
0115:
0116: /**
0117: * The hashMap of RenderMolecules in this TextureBin
0118: * this is used in rendering, the key used is localToVworld
0119: */
0120: HashMap addOpaqueRMs = new HashMap();
0121: HashMap addTransparentRMs = new HashMap();
0122:
0123: // A hashmap based on localToVworld for fast
0124: // insertion of new renderMolecules
0125: HashMap opaqueRenderMoleculeMap = new HashMap();
0126: HashMap transparentRenderMoleculeMap = new HashMap();
0127:
0128: // List of renderMolecules - used in rendering ..
0129: RenderMolecule opaqueRMList = null;
0130:
0131: RenderMolecule transparentRMList = null;
0132: TransparentRenderingInfo parentTInfo;
0133:
0134: int numRenderMolecules = 0;
0135: int numEditingRenderMolecules = 0;
0136:
0137: int tbFlag = 0; // a general bitmask for TextureBin
0138:
0139: // Following are the bits used in flag
0140:
0141: final static int ON_RENDER_BIN_LIST = 0x0001;
0142: final static int ON_UPDATE_LIST = 0x0002;
0143: final static int SOLE_USER = 0x0004;
0144: final static int CONTIGUOUS_ACTIVE_UNITS = 0x0008;
0145: final static int RESORT = 0x0010;
0146: final static int ON_UPDATE_CHECK_LIST = 0x0020;
0147:
0148: final static int USE_DISPLAYLIST = -2;
0149: final static int USE_VERTEXARRAY = -1;
0150:
0151: TextureBin(TextureUnitStateRetained[] state,
0152: AppearanceRetained app, RenderBin rb) {
0153: renderBin = rb;
0154: tbFlag = 0;
0155: reset(state, app);
0156: }
0157:
0158: /**
0159: * For now, clone everything just like the other NodeComponent
0160: */
0161: void reset(TextureUnitStateRetained[] state, AppearanceRetained app) {
0162:
0163: prev = null;
0164: next = null;
0165: opaqueRMList = null;
0166: transparentRMList = null;
0167: numEditingRenderMolecules = 0;
0168:
0169: // Issue 249 - check for sole user only if property is set
0170: // determine if this appearance is a sole user of this
0171: // TextureBin
0172: tbFlag &= ~TextureBin.SOLE_USER;
0173: if (VirtualUniverse.mc.allowSoleUser) {
0174: if ((app != null)
0175: && (app.changedFrequent & (AppearanceRetained.TEXTURE
0176: | AppearanceRetained.TEXCOORD_GEN
0177: | AppearanceRetained.TEXTURE_ATTR | AppearanceRetained.TEXTURE_UNIT_STATE)) != 0) {
0178: tbFlag |= TextureBin.SOLE_USER;
0179:
0180: }
0181: }
0182:
0183: if ((tbFlag & TextureBin.SOLE_USER) != 0) {
0184: this .app = app;
0185: } else {
0186: this .app = null;
0187: }
0188:
0189: resetTextureState(state);
0190:
0191: if ((tbFlag & TextureBin.ON_RENDER_BIN_LIST) == 0) {
0192: renderBin.addTextureBin(this );
0193: tbFlag |= TextureBin.ON_RENDER_BIN_LIST;
0194: }
0195:
0196: }
0197:
0198: void resetTextureState(TextureUnitStateRetained[] state) {
0199:
0200: int i, j;
0201: boolean foundDisableUnit = false;
0202: numActiveTexUnit = 0;
0203: lastActiveTexUnitIndex = 0;
0204: boolean soleUser = ((tbFlag & TextureBin.SOLE_USER) != 0);
0205: TextureRetained prevFirstTexture = null;
0206: TextureRetained tex;
0207:
0208: tbFlag |= TextureBin.CONTIGUOUS_ACTIVE_UNITS;
0209:
0210: if (state != null) {
0211:
0212: foundDisableUnit = false;
0213:
0214: if (texUnitState == null
0215: || (texUnitState.length != state.length)) {
0216: texUnitState = new TextureUnitStateRetained[state.length];
0217: } else if (texUnitState.length > 0
0218: && texUnitState[0] != null) {
0219: prevFirstTexture = texUnitState[0].texture;
0220: }
0221:
0222: for (i = 0; i < state.length; i++) {
0223: if (state[i] == null) {
0224: texUnitState[i] = null;
0225: foundDisableUnit = true;
0226: } else {
0227:
0228: // create a clone texture unit state
0229: if (texUnitState[i] == null) {
0230: texUnitState[i] = new TextureUnitStateRetained();
0231: }
0232:
0233: // for sole user TextureUnitState, save
0234: // the node component reference in the mirror reference
0235: // of the cloned copy for equal test, and
0236: // for native download optimization
0237: if (soleUser || state[i].changedFrequent != 0) {
0238: texUnitState[i].mirror = state[i];
0239: }
0240:
0241: // for the lowest level of node component in
0242: // TextureBin, clone it only if it is not
0243: // changedFrequent; in other words, if the
0244: // lowest level of texture related node components
0245: // such as TextureAttributes & TexCoordGen is
0246: // changedFrequent, have the cloned texUnitState
0247: // reference the mirror of those node components
0248: // directly. For Texture, we'll always reference
0249: // the mirror.
0250:
0251: // decrement the TextureBin ref count of the previous
0252: // texture
0253: tex = texUnitState[i].texture;
0254: if (tex != null) {
0255: tex.decTextureBinRefCount(this );
0256: if (soleUser
0257: && (tex.getTextureBinRefCount(this ) == 0)
0258: && (tex != state[i].texture)) {
0259: // In this case texture change but
0260: // TextureBin will not invoke clear() to reset.
0261: // So we need to free the texture resource here.
0262: renderBin.addTextureResourceFreeList(tex);
0263: }
0264: }
0265:
0266: texUnitState[i].texture = state[i].texture;
0267:
0268: // increment the TextureBin ref count of the new
0269: // texture
0270:
0271: if (texUnitState[i].texture != null) {
0272: texUnitState[i].texture
0273: .incTextureBinRefCount(this );
0274: }
0275:
0276: if (state[i].texAttrs != null) {
0277:
0278: if (state[i].texAttrs.changedFrequent != 0) {
0279: texUnitState[i].texAttrs = state[i].texAttrs;
0280:
0281: } else {
0282:
0283: // need to check for texAttrs.source because
0284: // texAttrs could be pointing to the mirror
0285: // in the last frame, so don't want to
0286: // overwrite the mirror
0287:
0288: if (texUnitState[i].texAttrs == null
0289: || texUnitState[i].texAttrs.source != null) {
0290: texUnitState[i].texAttrs = new TextureAttributesRetained();
0291: }
0292: texUnitState[i].texAttrs
0293: .set(state[i].texAttrs);
0294: texUnitState[i].texAttrs.mirrorCompDirty = true;
0295:
0296: // for sole user TextureBin, we are saving
0297: // the mirror node component in the mirror
0298: // reference in the clone object. This
0299: // will be used in state download to
0300: // avoid redundant download
0301:
0302: if (soleUser) {
0303: texUnitState[i].texAttrs.mirror = state[i].texAttrs;
0304: } else {
0305: texUnitState[i].texAttrs.mirror = null;
0306: }
0307:
0308: }
0309: } else {
0310: texUnitState[i].texAttrs = null;
0311: }
0312:
0313: if (state[i].texGen != null) {
0314: if (state[i].texGen.changedFrequent != 0) {
0315: texUnitState[i].texGen = state[i].texGen;
0316: } else {
0317:
0318: // need to check for texGen.source because
0319: // texGen could be pointing to the mirror
0320: // in the last frame, so don't want to
0321: // overwrite the mirror
0322:
0323: if (texUnitState[i].texGen == null
0324: || texUnitState[i].texGen.source != null) {
0325: texUnitState[i].texGen = new TexCoordGenerationRetained();
0326: }
0327:
0328: texUnitState[i].texGen.set(state[i].texGen);
0329: texUnitState[i].texGen.mirrorCompDirty = true;
0330:
0331: // for sole user TextureBin, we are saving
0332: // the mirror node component in the mirror
0333: // reference in the clone object. This
0334: // will be used in state download to
0335: // avoid redundant download
0336:
0337: if (soleUser) {
0338: texUnitState[i].texGen.mirror = state[i].texGen;
0339: } else {
0340: texUnitState[i].texGen.mirror = null;
0341: }
0342: }
0343: } else {
0344: texUnitState[i].texGen = null;
0345: }
0346:
0347: // Track the last active texture unit and the total number
0348: // of active texture units. Note that this total number
0349: // now includes disabled units so that there is always
0350: // a one-to-one mapping. We no longer remap texture units.
0351: if (texUnitState[i].isTextureEnabled()) {
0352: lastActiveTexUnitIndex = i;
0353: numActiveTexUnit = i + 1;
0354:
0355: if (foundDisableUnit) {
0356:
0357: // mark that active texture units are not
0358: // contiguous
0359: tbFlag &= ~TextureBin.CONTIGUOUS_ACTIVE_UNITS;
0360: }
0361: } else {
0362: foundDisableUnit = true;
0363: }
0364: }
0365: }
0366:
0367: // check to see if the TextureBin sorting criteria is
0368: // modified for this textureBin; if yes, mark that
0369: // resorting is needed
0370:
0371: if ((texUnitState[0] == null && prevFirstTexture != null)
0372: || (texUnitState[0] != null && texUnitState[0].texture != prevFirstTexture)) {
0373: tbFlag |= TextureBin.RESORT;
0374: }
0375:
0376: } else {
0377:
0378: // check to see if the TextureBin sorting criteria is
0379: // modified for this textureBin; if yes, mark that
0380: // resorting is needed
0381:
0382: if (texUnitState != null && texUnitState[0].texture != null) {
0383: tbFlag |= TextureBin.RESORT;
0384: }
0385: texUnitState = null;
0386: }
0387:
0388: soleUserCompDirty = 0;
0389: }
0390:
0391: /**
0392: * The TextureBin is to be removed from RenderBin,
0393: * do the proper unsetting of any references
0394: */
0395: void clear() {
0396:
0397: // make sure there is no reference to the scenegraph
0398: app = null;
0399:
0400: // for each texture referenced in the texture units, decrement
0401: // the reference count. If the reference count == 0, tell
0402: // the renderer to free up the resource
0403: if (texUnitState != null) {
0404:
0405: TextureRetained tex;
0406:
0407: for (int i = 0; i < texUnitState.length; i++) {
0408: if (texUnitState[i] != null) {
0409: if (texUnitState[i].texture != null) {
0410: tex = texUnitState[i].texture;
0411: tex.decTextureBinRefCount(this );
0412:
0413: if (tex.getTextureBinRefCount(this ) == 0) {
0414: renderBin.addTextureResourceFreeList(tex);
0415: }
0416:
0417: texUnitState[i].texture = null;
0418: }
0419:
0420: // make sure there is no more reference to the scenegraph
0421:
0422: texUnitState[i].mirror = null;
0423: texUnitState[i].texture = null;
0424: if (texUnitState[i].texAttrs != null
0425: && texUnitState[i].texAttrs.source != null) {
0426: texUnitState[i].texAttrs = null;
0427: }
0428: if (texUnitState[i].texGen != null
0429: && texUnitState[i].texGen.source != null) {
0430: texUnitState[i].texGen = null;
0431: }
0432: }
0433: }
0434: }
0435: }
0436:
0437: /**
0438: * This tests if the qiven textureUnitState matches this TextureBin
0439: */
0440: boolean equals(TextureUnitStateRetained state[], RenderAtom ra) {
0441:
0442: int i, j, k = 0;
0443: TextureRetained texture;
0444:
0445: // if this TextureBin is a soleUser case or the incoming
0446: // app has changedFrequent bit set for any of the texture
0447: // related component, then either the current TextureBin
0448: // or the incoming app requires the same app match
0449: if (((tbFlag & TextureBin.SOLE_USER) != 0)
0450: || ((ra.app != null) && (ra.app.changedFrequent & (AppearanceRetained.TEXTURE
0451: | AppearanceRetained.TEXCOORD_GEN
0452: | AppearanceRetained.TEXTURE_ATTR | AppearanceRetained.TEXTURE_UNIT_STATE)) != 0)) {
0453:
0454: if (app == ra.app) {
0455:
0456: // if this textureBin is currently on a zombie state,
0457: // we'll need to put it on the update list to reevaluate
0458: // the state, because while it is on a zombie state,
0459: // texture state could have been changed. Example,
0460: // application could have detached an appearance,
0461: // made changes to the texture references, and then
0462: // reattached the appearance. In this case, the texture
0463: // changes would not have reflected to the textureBin
0464:
0465: if (numEditingRenderMolecules == 0) {
0466:
0467: //System.err.println("===> TB in zombie state " + this);
0468:
0469: if (soleUserCompDirty == 0) {
0470: this .renderBin.tbUpdateList.add(this );
0471: }
0472: soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_REF;
0473: }
0474: return true;
0475:
0476: } else {
0477: return false;
0478: }
0479: }
0480:
0481: if (texUnitState == null && state == null)
0482: return (true);
0483:
0484: if (texUnitState == null || state == null)
0485: return (false);
0486:
0487: if (state.length != texUnitState.length)
0488: return (false);
0489:
0490: for (i = 0; i < texUnitState.length; i++) {
0491: // If texture Unit State is null
0492: if (texUnitState[i] == null) {
0493: if (state[i] != null)
0494: return (false);
0495: } else {
0496: if (!texUnitState[i].equivalent(state[i])) {
0497: return (false);
0498: }
0499: }
0500: }
0501:
0502: // Check if the image component has changed(may be a clearLive texture
0503: // change img component. setLive case)
0504: //
0505: if ((tbFlag & TextureBin.ON_RENDER_BIN_LIST) == 0) {
0506: renderBin.addTextureBin(this );
0507: tbFlag |= TextureBin.ON_RENDER_BIN_LIST;
0508: }
0509:
0510: return (true);
0511:
0512: }
0513:
0514: /*
0515: // updateNodeComponentCheck is called for each soleUser TextureBin
0516: // into which new renderAtom has been added. This method is called before
0517: // updateNodeComponent() to allow TextureBin to catch any node
0518: // component changes that have been missed because the changes
0519: // come when there is no active renderAtom associated with the
0520: // TextureBin. See bug# 4503926 for details.
0521: public void updateNodeComponentCheck() {
0522:
0523: //System.err.println("TextureBin.updateNodeComponentCheck()");
0524:
0525: tbFlag &= ~TextureBin.ON_UPDATE_CHECK_LIST;
0526:
0527: if ((soleUserCompDirty & SOLE_USER_DIRTY_REF) != 0) {
0528: return ;
0529: }
0530:
0531: if ((app.compChanged & (AppearanceRetained.TEXTURE |
0532: AppearanceRetained.TEXCOORD_GEN |
0533: AppearanceRetained.TEXTURE_ATTR |
0534: AppearanceRetained.TEXTURE_UNIT_STATE)) != 0) {
0535: if (soleUserCompDirty == 0) {
0536: this.renderBin.tbUpdateList.add(this);
0537: }
0538: soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_REF;
0539:
0540: } else if (app.texUnitState != null) {
0541:
0542: // if one texture unit state has to be reevaluated, then
0543: // it's enough update checking because reevaluating texture unit
0544: // state will automatically take care of its node component
0545: // updates.
0546:
0547: boolean done = false;
0548:
0549: for (int i = 0; i < app.texUnitState.length && !done; i++) {
0550: if (app.texUnitState[i] != null) {
0551: if (app.texUnitState[i].compChanged != 0) {
0552: if (soleUserCompDirty == 0) {
0553: this.renderBin.tbUpdateList.add(this);
0554: }
0555: soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TUS;
0556: done = true;
0557: } else {
0558: if (app.texUnitState[i].texAttrs != null &&
0559: app.texUnitState[i].texAttrs.compChanged != 0) {
0560: if (soleUserCompDirty == 0) {
0561: this.renderBin.tbUpdateList.add(this);
0562: }
0563: soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TA;
0564: }
0565: if (app.texUnitState[i].texGen != null &&
0566: app.texUnitState[i].texGen.compChanged != 0) {
0567: if (soleUserCompDirty == 0) {
0568: this.renderBin.tbUpdateList.add(this);
0569: }
0570: soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TC;
0571: }
0572: if (app.texUnitState[i].texture != null &&
0573: ((app.texUnitState[i].texture.compChanged &
0574: TextureRetained.ENABLE_CHANGED) != 0)) {
0575: if (soleUserCompDirty == 0) {
0576: this.renderBin.tbUpdateList.add(this);
0577: }
0578: soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TEXTURE;
0579: }
0580: }
0581: }
0582: }
0583: }
0584: }
0585: */
0586:
0587: /**
0588: * updateNodeComponent is called from RenderBin to update the
0589: * clone copy of the sole user node component in TextureBin when the
0590: * corresponding node component is being modified
0591: */
0592: public void updateNodeComponent() {
0593:
0594: // don't bother to update if the TextureBin is already
0595: // removed from RenderBin
0596:
0597: if ((tbFlag & TextureBin.ON_RENDER_BIN_LIST) == 0)
0598: return;
0599:
0600: // if any of the texture reference in the appearance referenced
0601: // by a sole user TextureBin is being modified, just do a reset
0602:
0603: if (((tbFlag & TextureBin.SOLE_USER) != 0)
0604: && ((soleUserCompDirty & TextureBin.SOLE_USER_DIRTY_REF) != 0)) {
0605:
0606: resetTextureState(app.texUnitState);
0607: return;
0608: }
0609:
0610: if (texUnitState == null) {
0611: soleUserCompDirty = 0;
0612: return;
0613: }
0614:
0615: if ((soleUserCompDirty & TextureBin.SOLE_USER_DIRTY_TUS) != 0) {
0616:
0617: // Now take care of the Texture Unit State changes
0618: TextureUnitStateRetained tus, mirrorTUS = null;
0619: boolean soleUser = ((tbFlag & TextureBin.SOLE_USER) != 0);
0620:
0621: for (int i = 0; i < texUnitState.length; i++) {
0622: tus = texUnitState[i];
0623: if (tus != null) {
0624: if (tus.mirror != null) {
0625:
0626: mirrorTUS = (TextureUnitStateRetained) tus.mirror;
0627:
0628: if (tus.texture != mirrorTUS.texture) {
0629: if (tus.texture != null) {
0630: tus.texture.decTextureBinRefCount(this );
0631: }
0632: tus.texture = mirrorTUS.texture;
0633: if (tus.texture != null) {
0634: tus.texture.incTextureBinRefCount(this );
0635: }
0636:
0637: // the first texture (TextureBin sorting
0638: // criteria) is modified, so needs to resort
0639:
0640: if (i == 0) {
0641: tbFlag |= TextureBin.RESORT;
0642: }
0643: }
0644:
0645: if (mirrorTUS.texAttrs != null) {
0646: if (mirrorTUS.texAttrs.changedFrequent != 0) {
0647: tus.texAttrs = mirrorTUS.texAttrs;
0648: } else {
0649: if (tus.texAttrs == null
0650: || tus.texAttrs.source != null) {
0651: tus.texAttrs = new TextureAttributesRetained();
0652: }
0653: tus.texAttrs.set(mirrorTUS.texAttrs);
0654: tus.texAttrs.mirrorCompDirty = true;
0655:
0656: if (soleUser) {
0657: tus.texAttrs.mirror = mirrorTUS.texAttrs;
0658: } else {
0659: tus.texAttrs.mirror = null;
0660: }
0661: }
0662: } else {
0663: tus.texAttrs = null;
0664: }
0665:
0666: if (mirrorTUS.texGen != null) {
0667: if (mirrorTUS.texGen.changedFrequent != 0) {
0668: tus.texGen = mirrorTUS.texGen;
0669: } else {
0670: if (tus.texGen == null
0671: || tus.texGen.source != null) {
0672: tus.texGen = new TexCoordGenerationRetained();
0673: }
0674: tus.texGen.set(mirrorTUS.texGen);
0675: tus.texGen.mirrorCompDirty = true;
0676:
0677: if (soleUser) {
0678: tus.texGen.mirror = mirrorTUS.texGen;
0679: } else {
0680: tus.texGen.mirror = null;
0681: }
0682: }
0683: } else {
0684: tus.texGen = null;
0685: }
0686: }
0687: }
0688: }
0689:
0690: // need to reEvaluate # of active textures after the update
0691: soleUserCompDirty |= TextureBin.SOLE_USER_DIRTY_TEXTURE;
0692:
0693: // TextureUnitState update automatically taken care of
0694: // TextureAttributes & TexCoordGeneration update
0695:
0696: soleUserCompDirty &= ~(TextureBin.SOLE_USER_DIRTY_TA | TextureBin.SOLE_USER_DIRTY_TC);
0697: }
0698:
0699: if ((soleUserCompDirty & TextureBin.SOLE_USER_DIRTY_TEXTURE) != 0) {
0700:
0701: boolean foundDisableUnit = false;
0702:
0703: numActiveTexUnit = 0;
0704: lastActiveTexUnitIndex = 0;
0705: tbFlag |= TextureBin.CONTIGUOUS_ACTIVE_UNITS;
0706: for (int i = 0; i < texUnitState.length; i++) {
0707:
0708: // Track the last active texture unit and the total number
0709: // of active texture units. Note that this total number
0710: // now includes disabled units so that there is always
0711: // a one-to-one mapping. We no longer remap texture units.
0712: if (texUnitState[i] != null
0713: && texUnitState[i].isTextureEnabled()) {
0714: lastActiveTexUnitIndex = i;
0715: numActiveTexUnit = i + 1;
0716:
0717: if (foundDisableUnit) {
0718:
0719: // mark that active texture units are not
0720: // contiguous
0721: tbFlag &= ~TextureBin.CONTIGUOUS_ACTIVE_UNITS;
0722: }
0723: } else {
0724: foundDisableUnit = true;
0725: }
0726: }
0727: }
0728:
0729: if ((soleUserCompDirty & TextureBin.SOLE_USER_DIRTY_TA) != 0) {
0730: for (int i = 0; i < texUnitState.length; i++) {
0731: if (texUnitState[i] != null
0732: && texUnitState[i].texAttrs != null
0733: && texUnitState[i].texAttrs.mirror != null
0734: && texUnitState[i].texAttrs.mirror.changedFrequent != 0) {
0735: texUnitState[i].texAttrs = (TextureAttributesRetained) texUnitState[i].texAttrs.mirror;
0736: }
0737: }
0738: }
0739:
0740: if ((soleUserCompDirty & TextureBin.SOLE_USER_DIRTY_TC) != 0) {
0741: for (int i = 0; i < texUnitState.length; i++) {
0742: if (texUnitState[i] != null
0743: && texUnitState[i].texGen != null
0744: && texUnitState[i].texGen.mirror != null
0745: && texUnitState[i].texGen.mirror.changedFrequent != 0) {
0746: texUnitState[i].texGen = (TexCoordGenerationRetained) texUnitState[i].texGen.mirror;
0747: }
0748: }
0749: }
0750:
0751: soleUserCompDirty = 0;
0752: }
0753:
0754: public void updateObject() {
0755: if (!addOpaqueRMs.isEmpty()) {
0756: opaqueRMList = addAll(opaqueRenderMoleculeMap,
0757: addOpaqueRMs, opaqueRMList, true);
0758: }
0759: if (!addTransparentRMs.isEmpty()) {
0760: // If transparent and not in bg geometry and inodepth
0761: // sorted transparency
0762: if (transparentRMList == null
0763: && (renderBin.transpSortMode == View.TRANSPARENCY_SORT_NONE || environmentSet.lightBin.geometryBackground != null)) {
0764: // System.err.println("========> addTransparentTextureBin "+this);
0765: transparentRMList = addAll(
0766: transparentRenderMoleculeMap,
0767: addTransparentRMs, transparentRMList, false);
0768: // Eventhough we are adding to transparentList , if all the RMS
0769: // have been switched already due to changeLists, then there is
0770: // nothing to add, and TBIN does not have any transparentRMList
0771: if (transparentRMList != null) {
0772: renderBin.addTransparentObject(this );
0773: }
0774:
0775: } else {
0776: transparentRMList = addAll(
0777: transparentRenderMoleculeMap,
0778: addTransparentRMs, transparentRMList, false);
0779: }
0780: }
0781: tbFlag &= ~TextureBin.ON_UPDATE_LIST;
0782:
0783: }
0784:
0785: /**
0786: * Each list of renderMoledule with the same localToVworld
0787: * is connect by rm.next and rm.prev.
0788: * At the end of the list (i.e. rm.next = null) the field
0789: * rm.nextMap is link to another list (with the same
0790: * localToVworld). So during rendering it will traverse
0791: * rm.next until this is null, then follow the .nextMap
0792: * to access another list and use rm.next to continue
0793: * until both rm.next and rm.nextMap are null.
0794: *
0795: * renderMoleculeMap is use to assist faster location of
0796: * renderMolecule List with the same localToVWorld. The
0797: * start of renderMolecule in the list with same
0798: * localToVworld is insert in renderMoleculeMap. This
0799: * map is clean up at removeRenderMolecule(). TextureBin
0800: * also use the map for quick location of renderMolecule
0801: * with the same localToVworld and attributes in
0802: * findRenderMolecule().
0803: */
0804: RenderMolecule addAll(HashMap renderMoleculeMap, HashMap addRMs,
0805: RenderMolecule startList, boolean opaqueList) {
0806: int i;
0807: RenderMolecule r;
0808: Collection c = addRMs.values();
0809: Iterator listIterator = c.iterator();
0810: RenderMolecule renderMoleculeList, head;
0811:
0812: while (listIterator.hasNext()) {
0813: boolean changed = false;
0814: ArrayList curList = (ArrayList) listIterator.next();
0815: r = (RenderMolecule) curList.get(0);
0816: // If this is a opaque one , but has been switched to a transparentList or
0817: // vice-versa (dur to changeLists function called before this), then
0818: // do nothing!
0819: // For changedFrequent case: Consider the case when a RM is added
0820: // (so is in the addRM list) and then
0821: // a change in transparent value occurs that make it from opaque to
0822: // transparent (the switch is handled before this function is called)
0823: if (r.isOpaqueOrInOG != opaqueList) {
0824: continue;
0825: }
0826: // Get the list of renderMolecules for this transform
0827: renderMoleculeList = (RenderMolecule) renderMoleculeMap
0828: .get(r.localToVworld);
0829: if (renderMoleculeList == null) {
0830: renderMoleculeList = r;
0831: renderMoleculeMap.put(r.localToVworld,
0832: renderMoleculeList);
0833: // Add this renderMolecule at the beginning of RM list
0834: if (startList == null) {
0835: startList = r;
0836: r.nextMap = null;
0837: r.prevMap = null;
0838: startList.dirtyAttrsAcrossRms = RenderMolecule.ALL_DIRTY_BITS;
0839: } else {
0840: r.nextMap = startList;
0841: startList.prevMap = r;
0842: startList = r;
0843: startList.nextMap.checkEquivalenceWithLeftNeighbor(
0844: r, RenderMolecule.ALL_DIRTY_BITS);
0845: }
0846:
0847: } else {
0848: // Insert the renderMolecule next to a RM that has equivalent
0849: // texture unit state
0850: if ((head = insertRenderMolecule(r, renderMoleculeList)) != null) {
0851: if (renderMoleculeList.prevMap != null) {
0852: renderMoleculeList.prevMap.nextMap = head;
0853: }
0854: head.prevMap = renderMoleculeList.prevMap;
0855: renderMoleculeList.prevMap = null;
0856: renderMoleculeList = head;
0857: changed = true;
0858: }
0859: }
0860: for (i = 1; i < curList.size(); i++) {
0861: r = (RenderMolecule) curList.get(i);
0862: // If this is a opaque one , but has been switched to a transparentList or
0863: // vice-versa (dur to changeLists function called before this), then
0864: // do nothing!
0865: // For changedFrequent case: Consider the case when a RM is added
0866: // (so is in the addRM list) and then
0867: // a change in transparent value occurs that make it from opaque to
0868: // transparent (the switch is handled before this function is called)
0869: if (r.isOpaqueOrInOG != opaqueList)
0870: continue;
0871: if ((head = insertRenderMolecule(r, renderMoleculeList)) != null) {
0872: if (renderMoleculeList.prevMap != null) {
0873: renderMoleculeList.prevMap.nextMap = head;
0874: }
0875: head.prevMap = renderMoleculeList.prevMap;
0876: renderMoleculeList.prevMap = null;
0877: renderMoleculeList = head;
0878: changed = true;
0879: }
0880:
0881: }
0882: if (changed) {
0883: renderMoleculeMap.put(r.localToVworld,
0884: renderMoleculeList);
0885: if (renderMoleculeList.prevMap != null) {
0886: renderMoleculeList
0887: .checkEquivalenceWithLeftNeighbor(
0888: renderMoleculeList.prevMap,
0889: RenderMolecule.ALL_DIRTY_BITS);
0890: } else {
0891: startList = renderMoleculeList;
0892: startList.dirtyAttrsAcrossRms = RenderMolecule.ALL_DIRTY_BITS;
0893: }
0894: }
0895: }
0896:
0897: addRMs.clear();
0898: return startList;
0899: }
0900:
0901: // XXXX: Could the analysis be done during insertRenderMolecule?
0902: // Return the head of the list,
0903: // if the insertion occurred at beginning of the list
0904: RenderMolecule insertRenderMolecule(RenderMolecule r,
0905: RenderMolecule renderMoleculeList) {
0906: RenderMolecule rm, retval;
0907:
0908: // Look for a RM that has an equivalent material
0909: rm = renderMoleculeList;
0910: while (rm != null) {
0911: if (rm.material == r.material
0912: || (rm.definingMaterial != null && rm.definingMaterial
0913: .equivalent(r.definingMaterial))) {
0914: // Put it here
0915: r.next = rm;
0916: r.prev = rm.prev;
0917: if (rm.prev == null) {
0918: renderMoleculeList = r;
0919: retval = renderMoleculeList;
0920: } else {
0921: rm.prev.next = r;
0922: retval = null;
0923: }
0924: rm.prev = r;
0925: r
0926: .checkEquivalenceWithBothNeighbors(RenderMolecule.ALL_DIRTY_BITS);
0927: return retval;
0928: }
0929: // If they are not equivalent, then skip to the first one
0930: // that has a different material using the dirty bits
0931: else {
0932: rm = rm.next;
0933: while (rm != null
0934: && ((rm.dirtyAttrsAcrossRms & RenderMolecule.MATERIAL_DIRTY) == 0)) {
0935: rm = rm.next;
0936: }
0937: }
0938: }
0939: // Just put it up front
0940: r.next = renderMoleculeList;
0941: renderMoleculeList.prev = r;
0942: renderMoleculeList = r;
0943: r
0944: .checkEquivalenceWithBothNeighbors(RenderMolecule.ALL_DIRTY_BITS);
0945: return renderMoleculeList;
0946: }
0947:
0948: /**
0949: * Adds the given RenderMolecule to this TextureBin
0950: */
0951: void addRenderMolecule(RenderMolecule r, RenderBin rb) {
0952: RenderMolecule rm;
0953: ArrayList list;
0954: HashMap map;
0955: r.textureBin = this ;
0956:
0957: if (r.isOpaqueOrInOG)
0958: map = addOpaqueRMs;
0959: else
0960: map = addTransparentRMs;
0961:
0962: if ((list = (ArrayList) map.get(r.localToVworld)) == null) {
0963: list = new ArrayList();
0964: map.put(r.localToVworld, list);
0965: }
0966: list.add(r);
0967:
0968: if ((tbFlag & TextureBin.ON_UPDATE_LIST) == 0) {
0969: tbFlag |= TextureBin.ON_UPDATE_LIST;
0970: rb.objUpdateList.add(this );
0971: }
0972: }
0973:
0974: /**
0975: * Removes the given RenderMolecule from this TextureBin
0976: */
0977: void removeRenderMolecule(RenderMolecule r) {
0978: ArrayList list;
0979: int index;
0980: boolean found = false;
0981: RenderMolecule renderMoleculeList, rmlist;
0982: HashMap addMap;
0983: HashMap allMap;
0984: r.textureBin = null;
0985:
0986: if (r.isOpaqueOrInOG) {
0987: rmlist = opaqueRMList;
0988: allMap = opaqueRenderMoleculeMap;
0989: addMap = addOpaqueRMs;
0990: } else {
0991: rmlist = transparentRMList;
0992: allMap = transparentRenderMoleculeMap;
0993: addMap = addTransparentRMs;
0994: }
0995: // If the renderMolecule being remove is contained in addRMs, then
0996: // remove the renderMolecule from the addList
0997: if ((list = (ArrayList) addMap.get(r.localToVworld)) != null) {
0998: if ((index = list.indexOf(r)) != -1) {
0999: list.remove(index);
1000: // If this was the last element for this localToVworld, then remove
1001: // the entry from the addRMs list
1002: if (list.isEmpty()) {
1003: addMap.remove(r.localToVworld);
1004: }
1005:
1006: r.prev = null;
1007: r.next = null;
1008: found = true;
1009: }
1010: }
1011: if (!found) {
1012: RenderMolecule head = removeOneRM(r, allMap, rmlist);
1013:
1014: r.soleUserCompDirty = 0;
1015: r.onUpdateList = 0;
1016: if (r.definingPolygonAttributes != null
1017: && (r.definingPolygonAttributes.changedFrequent != 0))
1018: r.definingPolygonAttributes = null;
1019:
1020: if (r.definingLineAttributes != null
1021: && (r.definingLineAttributes.changedFrequent != 0))
1022: r.definingLineAttributes = null;
1023:
1024: if (r.definingPointAttributes != null
1025: && (r.definingPointAttributes.changedFrequent != 0))
1026: r.definingPointAttributes = null;
1027:
1028: if (r.definingMaterial != null
1029: && (r.definingMaterial.changedFrequent != 0))
1030: r.definingMaterial = null;
1031:
1032: if (r.definingColoringAttributes != null
1033: && (r.definingColoringAttributes.changedFrequent != 0))
1034: r.definingColoringAttributes = null;
1035:
1036: if (r.definingTransparency != null
1037: && (r.definingTransparency.changedFrequent != 0))
1038: r.definingTransparency = null;
1039:
1040: renderBin.removeRenderMolecule(r);
1041: if (r.isOpaqueOrInOG) {
1042: opaqueRMList = head;
1043: } else {
1044: transparentRMList = head;
1045: }
1046:
1047: }
1048: // If the renderMolecule removed is not opaque then ..
1049: if (!r.isOpaqueOrInOG
1050: && transparentRMList == null
1051: && (renderBin.transpSortMode == View.TRANSPARENCY_SORT_NONE || environmentSet.lightBin.geometryBackground != null)) {
1052: renderBin.removeTransparentObject(this );
1053: }
1054: // If the rm removed is the one that is referenced in the tinfo
1055: // then change this reference
1056: else if (parentTInfo != null && parentTInfo.rm == r) {
1057: parentTInfo.rm = transparentRMList;
1058: }
1059: // Removal of this texture setting from the texCoordGenartion
1060: // is done during the removeRenderAtom routine in RenderMolecule.java
1061: // Only remove this texture bin if there are no more renderMolcules
1062: // waiting to be added
1063: if (opaqueRenderMoleculeMap.isEmpty() && addOpaqueRMs.isEmpty()
1064: && transparentRenderMoleculeMap.isEmpty()
1065: && addTransparentRMs.isEmpty()) {
1066: if ((tbFlag & TextureBin.ON_RENDER_BIN_LIST) != 0) {
1067: tbFlag &= ~TextureBin.ON_RENDER_BIN_LIST;
1068: renderBin.removeTextureBin(this );
1069: }
1070:
1071: shaderBin.removeTextureBin(this );
1072: texUnitState = null;
1073: }
1074: }
1075:
1076: /**
1077: * This method is called to update the state for this
1078: * TextureBin. This is only applicable in the single-pass case.
1079: * Multi-pass render will have to take care of its own
1080: * state update.
1081: */
1082: void updateAttributes(Canvas3D cv) {
1083:
1084: boolean dirty = ((cv.canvasDirty & (Canvas3D.TEXTUREBIN_DIRTY | Canvas3D.TEXTUREATTRIBUTES_DIRTY)) != 0);
1085:
1086: if (cv.textureBin == this && !dirty) {
1087: return;
1088: }
1089:
1090: cv.textureBin = this ;
1091:
1092: // save the current number of active texture unit so as
1093: // to be able to reset the one that is not enabled in this bin
1094:
1095: int lastActiveTexUnitIdx = -1;
1096:
1097: // Get the number of available texture units; this depends on
1098: // whether or not shaders are being used.
1099: boolean useShaders = (shaderBin.shaderProgram != null);
1100: int availableTextureUnits = useShaders ? cv.maxTextureImageUnits
1101: : cv.maxTextureUnits;
1102:
1103: // If the number of active texture units is greater than the number of
1104: // supported units, then we
1105: // need to set a flag indicating that the texture units are invalid.
1106: boolean disableTexture = false;
1107:
1108: if (numActiveTexUnit > availableTextureUnits) {
1109: disableTexture = true;
1110: // System.err.println("*** TextureBin : number of texture units exceeded");
1111: }
1112:
1113: // set the number active texture unit in Canvas3D
1114: if (disableTexture) {
1115: cv.setNumActiveTexUnit(0);
1116: } else {
1117: cv.setNumActiveTexUnit(numActiveTexUnit);
1118: }
1119:
1120: // state update
1121: if (numActiveTexUnit <= 0 || disableTexture) {
1122: if (cv.getLastActiveTexUnit() >= 0) {
1123: // no texture units enabled
1124:
1125: // when the canvas supports multi texture units,
1126: // we'll need to reset texture for all texture units
1127: if (cv.multiTexAccelerated) {
1128: for (int i = 0; i <= cv.getLastActiveTexUnit(); i++) {
1129: cv.resetTexture(cv.ctx, i);
1130: }
1131: // set the active texture unit back to 0
1132: cv.setNumActiveTexUnit(0);
1133: cv.activeTextureUnit(cv.ctx, 0);
1134: } else {
1135: cv.resetTexture(cv.ctx, -1);
1136: }
1137: cv.setLastActiveTexUnit(-1);
1138: }
1139: } else {
1140:
1141: int j = 0;
1142:
1143: for (int i = 0; i < texUnitState.length; i++) {
1144:
1145: if (j >= cv.texUnitState.length) {
1146: // We finish enabling the texture state.
1147: // Note that it is possible
1148: // texUnitState.length > cv.texUnitState.length
1149:
1150: break;
1151: }
1152:
1153: if ((texUnitState[i] != null)
1154: && texUnitState[i].isTextureEnabled()) {
1155: if (dirty
1156: || cv.texUnitState[j].mirror == null
1157: || cv.texUnitState[j].mirror != texUnitState[i].mirror) {
1158: // update the texture unit state
1159: texUnitState[i].updateNative(j, cv, false,
1160: false);
1161: cv.texUnitState[j].mirror = texUnitState[i].mirror;
1162: }
1163:
1164: // create a mapping that maps an active texture
1165: // unit to a texture unit state
1166:
1167: lastActiveTexUnitIdx = j;
1168: } else {
1169: if (j <= cv.getLastActiveTexUnit()) {
1170: cv.resetTexture(cv.ctx, j);
1171: }
1172: }
1173:
1174: j++;
1175: }
1176:
1177: // make sure to disable the remaining texture units
1178: // since they could have been enabled from the previous
1179: // texture bin
1180:
1181: for (int i = j; i <= cv.getLastActiveTexUnit(); i++) {
1182: cv.resetTexture(cv.ctx, i);
1183: }
1184:
1185: cv.setLastActiveTexUnit(lastActiveTexUnitIdx);
1186:
1187: // set the active texture unit back to 0
1188: cv.activeTextureUnit(cv.ctx, 0);
1189:
1190: }
1191: cv.canvasDirty &= ~Canvas3D.TEXTUREBIN_DIRTY;
1192: }
1193:
1194: /**
1195: * Renders this TextureBin
1196: */
1197: void render(Canvas3D cv) {
1198: render(cv, (Object) opaqueRMList);
1199: }
1200:
1201: void render(Canvas3D cv, Object rlist) {
1202:
1203: cv.texLinearMode = false;
1204:
1205: /*
1206: System.err.println("TextureBin/render " + this +
1207: " numActiveTexUnit= " + numActiveTexUnit +
1208: " maxTextureUnits= " + cv.maxTextureUnits);
1209: */
1210:
1211: // include this TextureBin to the to-be-updated state set in canvas
1212: cv.setStateToUpdate(Canvas3D.TEXTUREBIN_BIT, this );
1213:
1214: // For D3D - set the texLinearMode flag in the canvas if texcoord
1215: // generation is enabled in object_linear mode for any texture unit.
1216: if ((texUnitState != null) && VirtualUniverse.mc.isD3D()) {
1217: TextureUnitStateRetained tus;
1218: for (int i = 0; i < texUnitState.length; i++) {
1219: tus = texUnitState[i];
1220: if ((tus != null) && tus.isTextureEnabled()) {
1221: if ((tus.texGen != null)
1222: && (tus.texGen.genMode == TexCoordGeneration.OBJECT_LINEAR)) {
1223: cv.texLinearMode = true;
1224: }
1225: }
1226: }
1227: }
1228:
1229: renderList(cv, USE_DISPLAYLIST, rlist);
1230: }
1231:
1232: /**
1233: * render a render list
1234: */
1235: void renderList(Canvas3D cv, int pass, Object rlist) {
1236: assert pass < 0;
1237:
1238: if (rlist instanceof RenderMolecule) {
1239: renderList(cv, pass, (RenderMolecule) rlist);
1240: } else if (rlist instanceof TransparentRenderingInfo) {
1241: renderList(cv, pass, (TransparentRenderingInfo) rlist);
1242: }
1243: }
1244:
1245: /**
1246: * render list of RenderMolecule
1247: */
1248: void renderList(Canvas3D cv, int pass, RenderMolecule rlist) {
1249: assert pass < 0;
1250:
1251: // bit mask of all attr fields that are equivalent across
1252: // renderMolecules thro. ORing of invisible RMs.
1253: int combinedDirtyBits = 0;
1254: boolean rmVisible = true;
1255: RenderMolecule rm = rlist;
1256:
1257: while (rm != null) {
1258: if (rmVisible) {
1259: combinedDirtyBits = rm.dirtyAttrsAcrossRms;
1260: } else {
1261: combinedDirtyBits |= rm.dirtyAttrsAcrossRms;
1262: }
1263:
1264: rmVisible = rm.render(cv, pass, combinedDirtyBits);
1265:
1266: // next render molecule or the nextmap
1267: if (rm.next == null) {
1268: rm = rm.nextMap;
1269: } else {
1270: rm = rm.next;
1271: }
1272: }
1273: }
1274:
1275: /**
1276: * render sorted transparent list
1277: */
1278: void renderList(Canvas3D cv, int pass,
1279: TransparentRenderingInfo tinfo) {
1280: assert pass < 0;
1281:
1282: RenderMolecule rm = tinfo.rm;
1283: if (rm.isSwitchOn()) {
1284: rm.transparentSortRender(cv, pass, tinfo);
1285: }
1286: }
1287:
1288: void changeLists(RenderMolecule r) {
1289: RenderMolecule renderMoleculeList, rmlist = null, head;
1290: HashMap allMap = null;
1291: ArrayList list;
1292: int index;
1293: boolean newRM = false;
1294: // System.err.println("changeLists r = "+r+" tBin = "+this);
1295: // If its a new RM then do nothing, otherwise move lists
1296: if (r.isOpaqueOrInOG) {
1297: if (opaqueRMList == null
1298: && (r.prev == null && r.prevMap == null
1299: && r.next == null && r.nextMap == null)) {
1300: newRM = true;
1301: } else {
1302: rmlist = opaqueRMList;
1303: allMap = opaqueRenderMoleculeMap;
1304: }
1305:
1306: } else {
1307: if (transparentRMList == null
1308: && (r.prev == null && r.prevMap == null
1309: && r.next == null && r.nextMap == null)) {
1310: newRM = true;
1311: } else {
1312: rmlist = transparentRMList;
1313: allMap = transparentRenderMoleculeMap;
1314: }
1315: }
1316: if (!newRM) {
1317: head = removeOneRM(r, allMap, rmlist);
1318:
1319: if (r.isOpaqueOrInOG) {
1320: opaqueRMList = head;
1321: } else {
1322: transparentRMList = head;
1323: if (transparentRMList == null
1324: && (renderBin.transpSortMode == View.TRANSPARENCY_SORT_NONE || environmentSet.lightBin.geometryBackground != null)) {
1325: renderBin.removeTransparentObject(this );
1326: }
1327: // Issue 129: remove the RM's render atoms from the
1328: // list of transparent render atoms
1329: if ((renderBin.transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY)
1330: && (environmentSet.lightBin.geometryBackground == null)) {
1331: r.addRemoveTransparentObject(renderBin, false);
1332: }
1333: }
1334: }
1335: HashMap renderMoleculeMap;
1336: RenderMolecule startList;
1337:
1338: // Now insert in the other bin
1339: r.evalAlphaUsage(
1340: shaderBin.attributeBin.definingRenderingAttributes,
1341: texUnitState);
1342: r.isOpaqueOrInOG = r.isOpaque() || r.inOrderedGroup;
1343: if (r.isOpaqueOrInOG) {
1344: startList = opaqueRMList;
1345: renderMoleculeMap = opaqueRenderMoleculeMap;
1346: markDlistAsDirty(r);
1347: } else {
1348: startList = transparentRMList;
1349: renderMoleculeMap = transparentRenderMoleculeMap;
1350: if ((r.primaryMoleculeType & RenderMolecule.DLIST_MOLECULE) != 0
1351: && renderBin.transpSortMode != View.TRANSPARENCY_SORT_NONE) {
1352: renderBin.addDisplayListResourceFreeList(r);
1353: renderBin.removeDirtyRenderMolecule(r);
1354:
1355: r.vwcBounds.set(null);
1356: r.displayListId = 0;
1357: r.displayListIdObj = null;
1358: // Change the group type for all the rlistInfo in the primaryList
1359: RenderAtomListInfo rinfo = r.primaryRenderAtomList;
1360: while (rinfo != null) {
1361: rinfo.groupType = RenderAtom.SEPARATE_DLIST_PER_RINFO;
1362: if (rinfo.renderAtom.dlistIds == null) {
1363: rinfo.renderAtom.dlistIds = new int[rinfo.renderAtom.rListInfo.length];
1364:
1365: for (int k = 0; k < rinfo.renderAtom.dlistIds.length; k++) {
1366: rinfo.renderAtom.dlistIds[k] = -1;
1367: }
1368: }
1369: if (rinfo.renderAtom.dlistIds[rinfo.index] == -1) {
1370: rinfo.renderAtom.dlistIds[rinfo.index] = VirtualUniverse.mc
1371: .getDisplayListId().intValue();
1372: renderBin.addDlistPerRinfo.add(rinfo);
1373: }
1374: rinfo = rinfo.next;
1375: }
1376: r.primaryMoleculeType = RenderMolecule.SEPARATE_DLIST_PER_RINFO_MOLECULE;
1377: } else {
1378: markDlistAsDirty(r);
1379: }
1380:
1381: }
1382: renderMoleculeList = (RenderMolecule) renderMoleculeMap
1383: .get(r.localToVworld);
1384:
1385: if (renderMoleculeList == null) {
1386: renderMoleculeList = r;
1387: renderMoleculeMap.put(r.localToVworld, renderMoleculeList);
1388: // Add this renderMolecule at the beginning of RM list
1389: if (startList == null) {
1390: startList = r;
1391: r.nextMap = null;
1392: r.prevMap = null;
1393: } else {
1394: r.nextMap = startList;
1395: startList.prevMap = r;
1396: startList = r;
1397: startList.nextMap.checkEquivalenceWithLeftNeighbor(r,
1398: RenderMolecule.ALL_DIRTY_BITS);
1399: }
1400: // Issue 67 : since we are adding the new RM at the head, we must
1401: // set all dirty bits unconditionally
1402: startList.dirtyAttrsAcrossRms = RenderMolecule.ALL_DIRTY_BITS;
1403: } else {
1404: // Insert the renderMolecule next to a RM that has equivalent
1405: // texture unit state
1406: if ((head = insertRenderMolecule(r, renderMoleculeList)) != null) {
1407: if (renderMoleculeList.prevMap != null) {
1408: renderMoleculeList.prevMap.nextMap = head;
1409: }
1410: head.prevMap = renderMoleculeList.prevMap;
1411: renderMoleculeList.prevMap = null;
1412: renderMoleculeList = head;
1413: renderMoleculeMap.put(r.localToVworld,
1414: renderMoleculeList);
1415: if (renderMoleculeList.prevMap != null) {
1416: renderMoleculeList
1417: .checkEquivalenceWithLeftNeighbor(
1418: renderMoleculeList.prevMap,
1419: RenderMolecule.ALL_DIRTY_BITS);
1420: } else {
1421: startList.dirtyAttrsAcrossRms = RenderMolecule.ALL_DIRTY_BITS;
1422: startList = renderMoleculeList;
1423: }
1424: }
1425:
1426: }
1427: if (r.isOpaqueOrInOG) {
1428: opaqueRMList = startList;
1429: } else {
1430: // If transparent and not in bg geometry and inodepth sorted transparency
1431: if (transparentRMList == null
1432: && (renderBin.transpSortMode == View.TRANSPARENCY_SORT_NONE || environmentSet.lightBin.geometryBackground != null)) {
1433: transparentRMList = startList;
1434: renderBin.addTransparentObject(this );
1435: } else {
1436: transparentRMList = startList;
1437: }
1438: // Issue 129: add the RM's render atoms to the list of
1439: // transparent render atoms
1440: // XXXX: do we need to resort the list after the add???
1441: if ((renderBin.transpSortMode == View.TRANSPARENCY_SORT_GEOMETRY)
1442: && (environmentSet.lightBin.geometryBackground == null)) {
1443: r.addRemoveTransparentObject(renderBin, true);
1444: }
1445: }
1446: }
1447:
1448: RenderMolecule removeOneRM(RenderMolecule r, HashMap allMap,
1449: RenderMolecule list) {
1450: RenderMolecule rmlist = list;
1451: // In the middle, just remove and update
1452: if (r.prev != null && r.next != null) {
1453: r.prev.next = r.next;
1454: r.next.prev = r.prev;
1455: r.next.checkEquivalenceWithLeftNeighbor(r.prev,
1456: RenderMolecule.ALL_DIRTY_BITS);
1457: }
1458: // If whats is removed is at the end of an entry
1459: else if (r.prev != null && r.next == null) {
1460: r.prev.next = r.next;
1461: r.prev.nextMap = r.nextMap;
1462: if (r.nextMap != null) {
1463: r.nextMap.prevMap = r.prev;
1464: r.nextMap.checkEquivalenceWithLeftNeighbor(r.prev,
1465: RenderMolecule.ALL_DIRTY_BITS);
1466: }
1467: } else if (r.prev == null && r.next != null) {
1468: r.next.prev = null;
1469: r.next.prevMap = r.prevMap;
1470: if (r.prevMap != null) {
1471: r.prevMap.nextMap = r.next;
1472: r.next.checkEquivalenceWithLeftNeighbor(r.prevMap,
1473: RenderMolecule.ALL_DIRTY_BITS);
1474: }
1475: // Head of the rmList
1476: else {
1477: rmlist = r.next;
1478: rmlist.dirtyAttrsAcrossRms = RenderMolecule.ALL_DIRTY_BITS;
1479: }
1480: allMap.put(r.localToVworld, r.next);
1481: }
1482: // Update the maps and remove this entry from the map list
1483: else if (r.prev == null && r.next == null) {
1484: if (r.prevMap != null) {
1485: r.prevMap.nextMap = r.nextMap;
1486:
1487: } else {
1488: rmlist = r.nextMap;
1489: if (r.nextMap != null) {
1490: rmlist.dirtyAttrsAcrossRms = RenderMolecule.ALL_DIRTY_BITS;
1491: }
1492: }
1493: if (r.nextMap != null) {
1494: r.nextMap.prevMap = r.prevMap;
1495: if (r.prevMap != null) {
1496: r.nextMap.checkEquivalenceWithLeftNeighbor(
1497: r.prevMap, RenderMolecule.ALL_DIRTY_BITS);
1498: }
1499:
1500: }
1501:
1502: allMap.remove(r.localToVworld);
1503:
1504: }
1505: r.prev = null;
1506: r.next = null;
1507: r.prevMap = null;
1508: r.nextMap = null;
1509: return rmlist;
1510: }
1511:
1512: void markDlistAsDirty(RenderMolecule r) {
1513:
1514: if (r.primaryMoleculeType == RenderMolecule.DLIST_MOLECULE) {
1515: renderBin.addDirtyRenderMolecule(r);
1516: } else if (r.primaryMoleculeType == RenderMolecule.SEPARATE_DLIST_PER_RINFO_MOLECULE) {
1517: RenderAtomListInfo ra = r.primaryRenderAtomList;
1518: while (ra != null) {
1519: renderBin.addDlistPerRinfo.add(ra);
1520: ra = ra.next;
1521: }
1522: }
1523: }
1524:
1525: void decrActiveRenderMolecule() {
1526: numEditingRenderMolecules--;
1527:
1528: if (numEditingRenderMolecules == 0) {
1529:
1530: // if number of editing renderMolecules goes to 0,
1531: // inform the shaderBin that this textureBin goes to
1532: // zombie state
1533:
1534: shaderBin.decrActiveTextureBin();
1535: }
1536: }
1537:
1538: void incrActiveRenderMolecule() {
1539:
1540: if (numEditingRenderMolecules == 0) {
1541:
1542: // if this textureBin is in zombie state, inform
1543: // the shaderBin that this textureBin is activated again.
1544:
1545: shaderBin.incrActiveTextureBin();
1546: }
1547:
1548: numEditingRenderMolecules++;
1549: }
1550: }
|