0001: /*
0002: * $RCSfile: Shape3DRetained.java,v $
0003: *
0004: * Copyright 1996-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.12 $
0028: * $Date: 2008/02/28 20:17:30 $
0029: * $State: Exp $
0030: */
0031:
0032: package javax.media.j3d;
0033:
0034: import javax.vecmath.*;
0035: import java.util.ArrayList;
0036: import java.util.Enumeration;
0037: import java.util.Vector;
0038:
0039: /**
0040: * A shape leaf node consisting of geometry and appearance properties.
0041: */
0042:
0043: class Shape3DRetained extends LeafRetained {
0044:
0045: static final int GEOMETRY_CHANGED = 0x00001;
0046: static final int APPEARANCE_CHANGED = 0x00002;
0047: static final int COLLISION_CHANGED = 0x00004;
0048: static final int BOUNDS_CHANGED = 0x00008;
0049: static final int APPEARANCEOVERRIDE_CHANGED = 0x00010;
0050: static final int LAST_DEFINED_BIT = 0x00010;
0051:
0052: // Target threads to be notified when light changes
0053: static final int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT
0054: | J3dThread.UPDATE_RENDER;
0055:
0056: /**
0057: * The appearance component of the shape node.
0058: */
0059: AppearanceRetained appearance = null;
0060:
0061: /**
0062: * The arraylist of geometry component of the shape node.
0063: */
0064: ArrayList geometryList = null;
0065:
0066: /**
0067: * A 2D storage of all geometry atoms associated with this shape node.
0068: * There may be more than one geometry for a Shape3D node.
0069: * Do not change the following private variables to public, its access need to synchronize
0070: * via mirrorShape3DLock.
0071: */
0072:
0073: // geomAtomArr should always be a 1 element array, unless S3D contains multiple Text3Ds.
0074: private GeometryAtom geomAtom = null;
0075:
0076: /**
0077: * To sychronize access of the mirrorShape3D's geomAtomArray*.
0078: * A multiple read single write Lock to sychronize access into mirrorShape3D.
0079: * To prevent deadlock a call to read/write lock must end with a read/write unlock
0080: * respectively.
0081: */
0082: private MRSWLock mirrorShape3DLock = null;
0083:
0084: /**
0085: * The mirror Shape3DRetained nodes for this object. There is one
0086: * mirror for each instance of this Shape3D node. If it is not in
0087: * a SharedGroup, only index 0 is valid.
0088: * Do not change the following private variables to public, its access need to synchronize
0089: * via mirrorShape3DLock.
0090: */
0091: ArrayList mirrorShape3D = new ArrayList(1);
0092:
0093: /**
0094: * This field is used for mirror Shape3D nodes accessing their
0095: * original nodes. It is a NodeRetained because the original
0096: * node may be a Shape3DRetained or a MorphRetained node.
0097: */
0098: NodeRetained sourceNode = null;
0099:
0100: /**
0101: * The hashkey for this Shape3DRetained mirror object
0102: */
0103: HashKey key = null;
0104:
0105: // This is true when this geometry is referenced in an IMM mode context
0106: boolean inImmCtx = false;
0107:
0108: // A bitmask to indicate when something has changed
0109: int isDirty = 0xffff;
0110:
0111: // The list of lights that are scoped to this node
0112: LightRetained[] lights = null;
0113:
0114: // The number of lights in the above array, may be less than lights.length
0115: int numlights = 0;
0116:
0117: // The list of fogs that are scoped to this node
0118: FogRetained[] fogs = null;
0119:
0120: // The number of fogs in the above array, may be less than fogs.length
0121: int numfogs = 0;
0122:
0123: // The list of modelClips that are scoped to this node
0124: ModelClipRetained[] modelClips = null;
0125:
0126: // The number of modelClips in the above array, may be less than modelClips.length
0127: int numModelClips = 0;
0128:
0129: // The list of alt app that are scoped to this node
0130: AlternateAppearanceRetained[] altApps = null;
0131:
0132: //The number of alt app in the above array, may be less than alt app.length
0133: int numAltApps = 0;
0134:
0135: /**
0136: * Reference to the BranchGroup path of this mirror shape
0137: * This is used for picking and GeometryStructure only.
0138: */
0139: BranchGroupRetained branchGroupPath[];
0140:
0141: // cache value for picking in mirror shape.
0142: // True if all the node of the path from this to root are all pickable
0143: boolean isPickable = true;
0144:
0145: // cache value for collidable in mirror shape.
0146: // True if all the node of the path from this to root are all collidable
0147: boolean isCollidable = true;
0148:
0149: // closest switch parent
0150: SwitchRetained closestSwitchParent = null;
0151:
0152: // the child index from the closest switch parent
0153: int closestSwitchIndex = -1;
0154:
0155: // Is this S3D visible ? The default is true.
0156: boolean visible = true;
0157:
0158: // Whether the normal appearance is overrided by the alternate app
0159: boolean appearanceOverrideEnable = false;
0160:
0161: // AlternateAppearance retained that is applicable to this
0162: // mirror shape when the override flag is true
0163: AppearanceRetained otherAppearance = null;
0164:
0165: // geometry Bounds in local coordinate
0166: Bounds bounds = null;
0167:
0168: // geometry Bounds in virtual world coordinate
0169: BoundingBox vwcBounds = null;
0170:
0171: // collision Bounds in local coordinate
0172: Bounds collisionBound = null;
0173:
0174: // collision Bounds in virtual world coordinate
0175: Bounds collisionVwcBound = null;
0176:
0177: // a path of OrderedGroup, childrenId pairs which leads to this node
0178: OrderedPath orderedPath = null;
0179:
0180: // List of views that a mirror object is scoped to
0181: ArrayList viewList = null;
0182:
0183: int changedFrequent = 0;
0184:
0185: Shape3DRetained() {
0186: super ();
0187: this .nodeType = NodeRetained.SHAPE;
0188: numlights = 0;
0189: numfogs = 0;
0190: numModelClips = 0;
0191: numAltApps = 0;
0192: localBounds = new BoundingBox((BoundingBox) null);
0193:
0194: mirrorShape3DLock = new MRSWLock();
0195: geometryList = new ArrayList(1);
0196: geometryList.add(null);
0197: }
0198:
0199: /**
0200: * Sets the collision bounds of a node.
0201: * @param bounds the bounding object for the node
0202: */
0203: void setCollisionBounds(Bounds bounds) {
0204: if (bounds == null) {
0205: this .collisionBound = null;
0206: } else {
0207: this .collisionBound = (Bounds) bounds.clone();
0208: }
0209:
0210: if (source.isLive()) {
0211: // Notify Geometry Structure to check for collision
0212: J3dMessage message = new J3dMessage();
0213: message.type = J3dMessage.COLLISION_BOUND_CHANGED;
0214: message.threads = J3dThread.UPDATE_TRANSFORM;
0215: message.universe = universe;
0216: message.args[0] = getGeomAtomsArray(mirrorShape3D);
0217: // no need to clone collisionBound
0218: message.args[1] = collisionBound;
0219: VirtualUniverse.mc.processMessage(message);
0220: }
0221: }
0222:
0223: Bounds getLocalBounds(Bounds bounds) {
0224: if (localBounds != null) {
0225: localBounds.set(bounds);
0226: } else {
0227: localBounds = new BoundingBox(bounds);
0228: }
0229: return localBounds;
0230: }
0231:
0232: /**
0233: * Sets the geometric bounds of a node.
0234: * @param bounds the bounding object for the node
0235: */
0236: void setBounds(Bounds bounds) {
0237: super .setBounds(bounds);
0238:
0239: if (source.isLive() && !boundsAutoCompute) {
0240: J3dMessage message = new J3dMessage();
0241: message.type = J3dMessage.REGION_BOUND_CHANGED;
0242: message.threads = J3dThread.UPDATE_TRANSFORM
0243: | J3dThread.UPDATE_GEOMETRY
0244: | J3dThread.UPDATE_RENDER;
0245:
0246: message.universe = universe;
0247: message.args[0] = getGeomAtomsArray(mirrorShape3D);
0248: // no need to clone localBounds
0249: message.args[1] = localBounds;
0250: VirtualUniverse.mc.processMessage(message);
0251: }
0252: }
0253:
0254: /**
0255: * Gets the collision bounds of a node.
0256: * @return the node's bounding object
0257: */
0258: Bounds getCollisionBounds(int id) {
0259: return (collisionBound == null ? null : (Bounds) collisionBound
0260: .clone());
0261: }
0262:
0263: /**
0264: * Appends the specified geometry component to this Shape3D
0265: * node's list of geometry components.
0266: * If there are existing geometry components in the list, the new
0267: * geometry component must be of the same equivalence class
0268: * (point, line, polygon, CompressedGeometry, Raster, Text3D) as
0269: * the others.
0270: * @param geometry the geometry component to be appended.
0271: * @exception IllegalArgumentException if the new geometry
0272: * component is not of of the same equivalence class as the
0273: * existing geometry components.
0274: *
0275: * @since Java 3D 1.2
0276: */
0277: void addGeometry(Geometry geometry) {
0278: int i;
0279: Shape3DRetained s;
0280: GeometryRetained newGeom = null;
0281:
0282: checkEquivalenceClass(geometry, -1);
0283:
0284: if (((Shape3D) this .source).isLive()) {
0285: if (geometry != null) {
0286:
0287: newGeom = ((GeometryRetained) geometry.retained);
0288: newGeom.setLive(inBackgroundGroup, refCount);
0289:
0290: geometryList.add(newGeom);
0291:
0292: } else {
0293: geometryList.add(null);
0294: newGeom = null;
0295: }
0296: sendDataChangedMessage(newGeom);
0297:
0298: } else {
0299: if (geometry != null) {
0300: geometryList.add((GeometryRetained) geometry.retained);
0301: } else {
0302: geometryList.add(null);
0303: }
0304: }
0305: dirtyBoundsCache();
0306: }
0307:
0308: /**
0309: * Replaces the geometry component at the specified index in this
0310: * Shape3D node's list of geometry components with the specified
0311: * geometry component.
0312: * If there are existing geometry components in the list (besides
0313: * the one being replaced), the new geometry component must be of
0314: * the same equivalence class (point, line, polygon, CompressedGeometry,
0315: * Raster, Text3D) as the others.
0316: * @param geometry the geometry component to be stored at the
0317: * specified index.
0318: * @param index the index of the geometry component to be replaced.
0319: * @exception IllegalArgumentException if the new geometry
0320: * component is not of of the same equivalence class as the
0321: * existing geometry components.
0322: *
0323: * @since Java 3D 1.2
0324: */
0325: void setGeometry(Geometry geometry, int index) {
0326: int i;
0327: Shape3DRetained mShape;
0328: GeometryRetained newGeom = null;
0329: GeometryRetained oldGeom = null;
0330:
0331: checkEquivalenceClass(geometry, index);
0332:
0333: if (((Shape3D) this .source).isLive()) {
0334:
0335: oldGeom = (GeometryRetained) (geometryList.get(index));
0336: if (oldGeom != null) {
0337: oldGeom.clearLive(refCount);
0338: for (i = 0; i < mirrorShape3D.size(); i++) {
0339: mShape = (Shape3DRetained) mirrorShape3D.get(i);
0340: oldGeom.removeUser(mShape);
0341: }
0342: oldGeom.decRefCnt();
0343: }
0344:
0345: if (geometry != null) {
0346: newGeom = (GeometryRetained) geometry.retained;
0347: newGeom.incRefCnt();
0348: newGeom.setLive(inBackgroundGroup, refCount);
0349: geometryList.set(index, newGeom);
0350: sendDataChangedMessage(newGeom);
0351: } else {
0352: geometryList.set(index, null);
0353: sendDataChangedMessage(null);
0354: }
0355:
0356: } else {
0357:
0358: oldGeom = (GeometryRetained) (geometryList.get(index));
0359: if (oldGeom != null) {
0360: oldGeom.decRefCnt();
0361: }
0362: if (geometry != null) {
0363: geometryList.set(index,
0364: (GeometryRetained) geometry.retained);
0365: ((GeometryRetained) geometry.retained).incRefCnt();
0366: } else {
0367: geometryList.set(index, null);
0368: }
0369: }
0370: dirtyBoundsCache();
0371: }
0372:
0373: /**
0374: * Inserts the specified geometry component into this Shape3D
0375: * node's list of geometry components at the specified index.
0376: * If there are existing geometry components in the list, the new
0377: * geometry component must be of the same equivalence class
0378: * (point, line, polygon, CompressedGeometry, Raster, Text3D) as
0379: * the others.
0380: * @param geometry the geometry component to be inserted at the
0381: * specified index.
0382: * @param index the index at which the geometry component is inserted.
0383: *
0384: * @since Java 3D 1.2
0385: */
0386: void insertGeometry(Geometry geometry, int index) {
0387: int i;
0388: Shape3DRetained mShape;
0389: GeometryRetained newGeom = null;
0390: GeometryRetained oldGeom = null;
0391:
0392: checkEquivalenceClass(geometry, -1);
0393:
0394: if (((Shape3D) this .source).isLive()) {
0395:
0396: if (geometry != null) {
0397: // Note : The order of the statements in important. Want ArrayList class to do index bounds
0398: // check before creating internal object.
0399: newGeom = (GeometryRetained) geometry.retained;
0400: newGeom.incRefCnt();
0401: geometryList.add(index, newGeom);
0402: newGeom.setLive(inBackgroundGroup, refCount);
0403: sendDataChangedMessage(newGeom);
0404: } else {
0405: geometryList.add(index, null);
0406: sendDataChangedMessage(null);
0407: }
0408:
0409: } else {
0410:
0411: if (geometry != null) {
0412: geometryList.add(index,
0413: (GeometryRetained) geometry.retained);
0414: ((GeometryRetained) geometry.retained).incRefCnt();
0415: } else {
0416: geometryList.add(index, null);
0417: }
0418: }
0419: dirtyBoundsCache();
0420: }
0421:
0422: /**
0423: * Removes the geometry component at the specified index from
0424: * this Shape3D node's list of geometry components.
0425: * @param index the index of the geometry component to be removed.
0426: *
0427: * @since Java 3D 1.2
0428: */
0429: void removeGeometry(int index) {
0430: int i;
0431: Shape3DRetained mShape;
0432: GeometryRetained oldGeom = null;
0433:
0434: if (((Shape3D) this .source).isLive()) {
0435:
0436: oldGeom = (GeometryRetained) (geometryList.get(index));
0437: if (oldGeom != null) {
0438: oldGeom.clearLive(refCount);
0439: oldGeom.decRefCnt();
0440: for (i = 0; i < mirrorShape3D.size(); i++) {
0441: mShape = (Shape3DRetained) mirrorShape3D.get(i);
0442: oldGeom.removeUser(mShape);
0443:
0444: }
0445: }
0446:
0447: geometryList.remove(index);
0448: sendDataChangedMessage(null);
0449:
0450: } else {
0451: oldGeom = (GeometryRetained) (geometryList.get(index));
0452: if (oldGeom != null) {
0453: oldGeom.decRefCnt();
0454: }
0455: geometryList.remove(index);
0456: }
0457:
0458: dirtyBoundsCache();
0459:
0460: }
0461:
0462: /**
0463: * Retrieves the geometry component of this Shape3D node.
0464: * @return the geometry component of this shape node
0465: *
0466: * @since Java 3D 1.2
0467: */
0468: Geometry getGeometry(int index, int id) {
0469: GeometryRetained ga = (GeometryRetained) geometryList
0470: .get(index);
0471: return (ga == null ? null : (Geometry) ga.source);
0472: }
0473:
0474: /**
0475: * Returns an enumeration of this Shape3D node's list of geometry
0476: * components.
0477: * @return an Enumeration object containing all geometry components in
0478: * this Shape3D node's list of geometry components.
0479: *
0480: * @since Java 3D 1.2
0481: */
0482: Enumeration getAllGeometries(int id) {
0483: GeometryRetained ga = null;
0484: Vector geomList = new Vector(geometryList.size());
0485:
0486: for (int i = 0; i < geometryList.size(); i++) {
0487: ga = (GeometryRetained) geometryList.get(i);
0488: if (ga != null)
0489: geomList.add((Geometry) ga.source);
0490: else
0491: geomList.add(null);
0492: }
0493:
0494: return geomList.elements();
0495: }
0496:
0497: /**
0498: * Returns the number of geometry components in this Shape3D node's
0499: * list of geometry components.
0500: * @return the number of geometry components in this Shape3D node's
0501: * list of geometry components.
0502: *
0503: * @since Java 3D 1.2
0504: */
0505: int numGeometries(int id) {
0506:
0507: return geometryList.size();
0508: }
0509:
0510: /**
0511: * Sets the appearance component of this Shape3D node.
0512: * @param appearance the new apearance component for this shape node
0513: */
0514: void setAppearance(Appearance newAppearance) {
0515:
0516: Shape3DRetained s;
0517: boolean visibleIsDirty = false;
0518:
0519: if (((Shape3D) this .source).isLive()) {
0520: if (appearance != null) {
0521: appearance.clearLive(refCount);
0522: for (int i = 0; i < mirrorShape3D.size(); i++) {
0523: s = (Shape3DRetained) mirrorShape3D.get(i);
0524: appearance.removeAMirrorUser(s);
0525: }
0526: }
0527:
0528: if (newAppearance != null) {
0529: ((AppearanceRetained) newAppearance.retained).setLive(
0530: inBackgroundGroup, refCount);
0531: appearance = ((AppearanceRetained) newAppearance.retained);
0532: for (int i = 0; i < mirrorShape3D.size(); i++) {
0533: s = (Shape3DRetained) mirrorShape3D.get(i);
0534: appearance.addAMirrorUser(s);
0535: }
0536: if ((appearance.renderingAttributes != null)
0537: && (visible != appearance.renderingAttributes.visible)) {
0538: visible = appearance.renderingAttributes.visible;
0539: visibleIsDirty = true;
0540: }
0541: } else {
0542: if (visible == false) {
0543: visible = true;
0544: visibleIsDirty = true;
0545: }
0546: }
0547: int size = 0;
0548: if (visibleIsDirty)
0549: size = 2;
0550: else
0551: size = 1;
0552: J3dMessage[] createMessage = new J3dMessage[size];
0553: // Send a message
0554: createMessage[0] = new J3dMessage();
0555: createMessage[0].threads = targetThreads;
0556: createMessage[0].type = J3dMessage.SHAPE3D_CHANGED;
0557: createMessage[0].universe = universe;
0558: createMessage[0].args[0] = this ;
0559: createMessage[0].args[1] = new Integer(APPEARANCE_CHANGED);
0560: Shape3DRetained[] s3dArr = new Shape3DRetained[mirrorShape3D
0561: .size()];
0562: mirrorShape3D.toArray(s3dArr);
0563: createMessage[0].args[2] = s3dArr;
0564: Object[] obj = new Object[2];
0565: if (newAppearance == null) {
0566: obj[0] = null;
0567: } else {
0568: obj[0] = appearance.mirror;
0569: }
0570: obj[1] = new Integer(changedFrequent);
0571: createMessage[0].args[3] = obj;
0572: createMessage[0].args[4] = getGeomAtomsArray(mirrorShape3D);
0573: if (visibleIsDirty) {
0574: createMessage[1] = new J3dMessage();
0575: createMessage[1].threads = J3dThread.UPDATE_GEOMETRY;
0576: createMessage[1].type = J3dMessage.SHAPE3D_CHANGED;
0577: createMessage[1].universe = universe;
0578: createMessage[1].args[0] = this ;
0579: createMessage[1].args[1] = new Integer(
0580: APPEARANCE_CHANGED);
0581: createMessage[1].args[2] = visible ? Boolean.TRUE
0582: : Boolean.FALSE;
0583: createMessage[1].args[3] = createMessage[0].args[4];
0584: }
0585: VirtualUniverse.mc.processMessage(createMessage);
0586:
0587: } else { // not live.
0588: if (newAppearance == null) {
0589: appearance = null;
0590: } else {
0591: appearance = (AppearanceRetained) newAppearance.retained;
0592: }
0593: }
0594: }
0595:
0596: /**
0597: * Retrieves the shape node's appearance component.
0598: * @return the shape node's appearance
0599: */
0600: Appearance getAppearance() {
0601: return (appearance == null ? null
0602: : (Appearance) appearance.source);
0603: }
0604:
0605: void setAppearanceOverrideEnable(boolean flag) {
0606: if (((Shape3D) this .source).isLive()) {
0607:
0608: // Send a message
0609: J3dMessage createMessage = new J3dMessage();
0610: createMessage.threads = targetThreads;
0611: createMessage.type = J3dMessage.SHAPE3D_CHANGED;
0612: createMessage.universe = universe;
0613: createMessage.args[0] = this ;
0614: createMessage.args[1] = new Integer(
0615: APPEARANCEOVERRIDE_CHANGED);
0616: Shape3DRetained[] s3dArr = new Shape3DRetained[mirrorShape3D
0617: .size()];
0618: mirrorShape3D.toArray(s3dArr);
0619: createMessage.args[2] = s3dArr;
0620: Object[] obj = new Object[2];
0621: if (flag) {
0622: obj[0] = Boolean.TRUE;
0623: } else {
0624: obj[0] = Boolean.FALSE;
0625: }
0626: obj[1] = new Integer(changedFrequent);
0627: createMessage.args[3] = obj;
0628: createMessage.args[4] = getGeomAtomsArray(mirrorShape3D);
0629:
0630: VirtualUniverse.mc.processMessage(createMessage);
0631: }
0632: appearanceOverrideEnable = flag;
0633: }
0634:
0635: boolean getAppearanceOverrideEnable() {
0636: return appearanceOverrideEnable;
0637: }
0638:
0639: boolean intersect(PickInfo pickInfo, PickShape pickShape, int flags) {
0640:
0641: Transform3D localToVworld = pickInfo.getLocalToVWorldRef();
0642:
0643: // Support OrientedShape3D here.
0644: // Note - BugId : 4363899 - APIs issue : OrientedShape3D's intersect needs view
0645: // info. temp. fix use the primary view.
0646: if (this instanceof OrientedShape3DRetained) {
0647: Transform3D orientedTransform = ((OrientedShape3DRetained) this )
0648: .getOrientedTransform(getPrimaryViewIdx());
0649: localToVworld.mul(orientedTransform);
0650: }
0651:
0652: Transform3D t3d = new Transform3D();
0653: t3d.invert(localToVworld);
0654: PickShape newPS = pickShape.transform(t3d);
0655:
0656: // Note: For optimization - Should do a geobounds check of
0657: // each geometry first. But this doesn't work for
0658: // OrientedShape3D case...
0659: int geomListSize = geometryList.size();
0660: GeometryRetained geometry;
0661:
0662: if (((flags & PickInfo.CLOSEST_INTERSECTION_POINT) == 0)
0663: && ((flags & PickInfo.CLOSEST_DISTANCE) == 0)
0664: && ((flags & PickInfo.CLOSEST_GEOM_INFO) == 0)
0665: && ((flags & PickInfo.ALL_GEOM_INFO) == 0)) {
0666:
0667: for (int i = 0; i < geomListSize; i++) {
0668: geometry = (GeometryRetained) geometryList.get(i);
0669: if (geometry != null) {
0670: if (geometry.mirrorGeometry != null) {
0671: geometry = geometry.mirrorGeometry;
0672: }
0673: if (geometry.intersect(newPS, null, 0, null, null,
0674: 0)) {
0675: return true;
0676: }
0677: }
0678: }
0679: } else {
0680: double distance;
0681: double minDist = Double.POSITIVE_INFINITY;
0682: Point3d closestIPnt = new Point3d();
0683: Point3d iPnt = new Point3d();
0684: Point3d iPntVW = new Point3d();
0685:
0686: for (int i = 0; i < geomListSize; i++) {
0687: geometry = (GeometryRetained) geometryList.get(i);
0688: if (geometry != null) {
0689: if (geometry.mirrorGeometry != null) {
0690: geometry = geometry.mirrorGeometry;
0691: }
0692: //if (geometry.intersect(newPS, intersectionInfo, flags, iPnt)) {
0693: if (geometry.intersect(newPS, pickInfo, flags,
0694: iPnt, geometry, i)) {
0695:
0696: iPntVW.set(iPnt);
0697: localToVworld.transform(iPntVW);
0698: distance = pickShape.distance(iPntVW);
0699:
0700: if (minDist > distance) {
0701: minDist = distance;
0702: closestIPnt.set(iPnt);
0703: }
0704: }
0705: }
0706: }
0707:
0708: if (minDist < Double.POSITIVE_INFINITY) {
0709: if ((flags & PickInfo.CLOSEST_DISTANCE) != 0) {
0710: pickInfo.setClosestDistance(minDist);
0711: }
0712: if ((flags & PickInfo.CLOSEST_INTERSECTION_POINT) != 0) {
0713: pickInfo.setClosestIntersectionPoint(closestIPnt);
0714: }
0715: return true;
0716: }
0717: }
0718:
0719: return false;
0720:
0721: }
0722:
0723: /**
0724: * Check if the geometry component of this shape node under path
0725: * intersects with the pickShape.
0726: * This is an expensive method. It should only be called if and only
0727: * if the path's bound intersects pickShape.
0728: * @exception IllegalArgumentException if <code>path</code> is
0729: * invalid.
0730: */
0731:
0732: boolean intersect(SceneGraphPath path, PickShape pickShape,
0733: double[] dist) {
0734:
0735: int flags;
0736: PickInfo pickInfo = new PickInfo();
0737:
0738: Transform3D localToVworld = path.getTransform();
0739: if (localToVworld == null) {
0740: throw new IllegalArgumentException(J3dI18N
0741: .getString("Shape3DRetained3"));
0742: }
0743: pickInfo.setLocalToVWorldRef(localToVworld);
0744: //System.err.println("Shape3DRetained.intersect() : ");
0745: if (dist == null) {
0746: //System.err.println(" no dist request ....");
0747: return intersect(pickInfo, pickShape, 0);
0748: }
0749:
0750: flags = PickInfo.CLOSEST_DISTANCE;
0751: if (intersect(pickInfo, pickShape, flags)) {
0752: dist[0] = pickInfo.getClosestDistance();
0753: return true;
0754: }
0755:
0756: return false;
0757:
0758: }
0759:
0760: /**
0761: * This sets the immedate mode context flag
0762: */
0763: void setInImmCtx(boolean inCtx) {
0764: inImmCtx = inCtx;
0765: }
0766:
0767: /**
0768: * This gets the immedate mode context flag
0769: */
0770: boolean getInImmCtx() {
0771: return (inImmCtx);
0772: }
0773:
0774: /**
0775: * This updates the mirror shape to reflect the state of the
0776: * real shape3d.
0777: */
0778: private void initMirrorShape3D(SetLiveState s, Shape3DRetained ms,
0779: int index) {
0780:
0781: // New 1.2.1 code
0782:
0783: ms.inBackgroundGroup = inBackgroundGroup;
0784: ms.geometryBackground = geometryBackground;
0785: ms.source = source;
0786: ms.universe = universe;
0787: // Has to be false. We have a instance of mirror for every link to the shape3d.
0788: ms.inSharedGroup = false;
0789: ms.locale = locale;
0790: ms.parent = parent;
0791:
0792: // New 1.3.2
0793: // Used when user supplied their own bounds for transparency sorting
0794: // GeometryAtom uses this to change how it computes the centroid
0795: ms.boundsAutoCompute = boundsAutoCompute;
0796: ms.localBounds = localBounds;
0797: // End new 1.3.2
0798:
0799: OrderedPath op = (OrderedPath) s.orderedPaths.get(index);
0800: if (op.pathElements.size() == 0) {
0801: ms.orderedPath = null;
0802: } else {
0803: ms.orderedPath = op;
0804: /*
0805: System.err.println("initMirrorShape3D ms.orderedPath ");
0806: ms.orderedPath.printPath();
0807: */
0808: }
0809:
0810: // all mirror shapes point to the same transformGroupRetained
0811: // for the static transform
0812: ms.staticTransform = staticTransform;
0813:
0814: ms.appearanceOverrideEnable = appearanceOverrideEnable;
0815:
0816: ms.geometryList = geometryList;
0817:
0818: // Assign the parent of this mirror shape node
0819: ms.sourceNode = this ;
0820:
0821: if (this instanceof OrientedShape3DRetained) {
0822: OrientedShape3DRetained os = (OrientedShape3DRetained) this ;
0823: OrientedShape3DRetained oms = (OrientedShape3DRetained) ms;
0824: oms.initAlignmentMode(os.mode);
0825: oms.initAlignmentAxis(os.axis);
0826: oms.initRotationPoint(os.rotationPoint);
0827: oms.initConstantScaleEnable(os.constantScale);
0828: oms.initScale(os.scaleFactor);
0829: }
0830:
0831: }
0832:
0833: void updateImmediateMirrorObject(Object[] objs) {
0834: int component = ((Integer) objs[1]).intValue();
0835: GeometryArrayRetained ga;
0836:
0837: Shape3DRetained[] msArr = (Shape3DRetained[]) objs[2];
0838: int i, j;
0839: if ((component & APPEARANCE_CHANGED) != 0) {
0840: Object[] arg = (Object[]) objs[3];
0841: int val = ((Integer) arg[1]).intValue();
0842: for (i = msArr.length - 1; i >= 0; i--) {
0843: msArr[i].appearance = (AppearanceRetained) arg[0];
0844: msArr[i].changedFrequent = val;
0845: }
0846: }
0847: if ((component & APPEARANCEOVERRIDE_CHANGED) != 0) {
0848: Object[] arg = (Object[]) objs[3];
0849: int val = ((Integer) arg[1]).intValue();
0850: for (i = msArr.length - 1; i >= 0; i--) {
0851: msArr[i].appearanceOverrideEnable = ((Boolean) arg[0])
0852: .booleanValue();
0853: msArr[i].changedFrequent = val;
0854: }
0855: }
0856: }
0857:
0858: /**
0859: * Gets the bounding object of a node.
0860: * @return the node's bounding object
0861: */
0862:
0863: Bounds getBounds() {
0864:
0865: if (boundsAutoCompute) {
0866: // System.err.println("getBounds ---- localBounds is " + localBounds);
0867: // Issue 514 : NPE in Wonderland : triggered in cached bounds computation
0868: if (validCachedBounds) {
0869: return (Bounds) cachedBounds.clone();
0870: }
0871:
0872: if (geometryList != null) {
0873: BoundingBox bbox = new BoundingBox((Bounds) null);
0874: GeometryRetained geometry;
0875: for (int i = 0; i < geometryList.size(); i++) {
0876: geometry = (GeometryRetained) geometryList.get(i);
0877: if ((geometry != null)
0878: && (geometry.geoType != GeometryRetained.GEO_TYPE_NONE)) {
0879: geometry.computeBoundingBox();
0880: synchronized (geometry.geoBounds) {
0881: bbox.combine(geometry.geoBounds);
0882: }
0883: }
0884: }
0885: return (Bounds) bbox;
0886:
0887: } else {
0888: return null;
0889: }
0890:
0891: } else {
0892: return super .getBounds();
0893: }
0894: }
0895:
0896: Bounds getEffectiveBounds() {
0897: if (boundsAutoCompute) {
0898: return getBounds();
0899: } else {
0900: return super .getEffectiveBounds();
0901: }
0902: }
0903:
0904: /**
0905: * ONLY needed for SHAPE, MORPH, and LINK node type.
0906: * Compute the combine bounds of bounds and its localBounds.
0907: */
0908: void computeCombineBounds(Bounds bounds) {
0909:
0910: if (boundsAutoCompute) {
0911: if (geometryList != null) {
0912: GeometryRetained geometry;
0913: BoundingBox bbox = null;
0914:
0915: if (staticTransform != null) {
0916: bbox = new BoundingBox((BoundingBox) null);
0917: }
0918:
0919: if (!VirtualUniverse.mc.cacheAutoComputedBounds) {
0920: for (int i = 0; i < geometryList.size(); i++) {
0921: geometry = (GeometryRetained) geometryList
0922: .get(i);
0923: if ((geometry != null)
0924: && (geometry.geoType != GeometryRetained.GEO_TYPE_NONE)) {
0925: geometry.computeBoundingBox();
0926: // Should this be lock too ? ( MT safe ? )
0927: synchronized (geometry.geoBounds) {
0928: if (staticTransform != null) {
0929: bbox.set(geometry.geoBounds);
0930: bbox
0931: .transform(staticTransform.transform);
0932: bounds.combine((Bounds) bbox);
0933: } else {
0934: bounds
0935: .combine((Bounds) geometry.geoBounds);
0936: }
0937: }
0938: }
0939: }
0940: } else {
0941: // Issue 514 : NPE in Wonderland : triggered in cached bounds computation
0942: if (!validCachedBounds) {
0943: validCachedBounds = true;
0944: cachedBounds = new BoundingBox(
0945: (BoundingBox) null);
0946:
0947: for (int i = 0; i < geometryList.size(); i++) {
0948: geometry = (GeometryRetained) geometryList
0949: .get(i);
0950: if ((geometry != null)
0951: && (geometry.geoType != GeometryRetained.GEO_TYPE_NONE)) {
0952: geometry.computeBoundingBox();
0953: // Should this be lock too ? ( MT safe ? )
0954: synchronized (geometry.geoBounds) {
0955: if (staticTransform != null) {
0956: bbox.set(geometry.geoBounds);
0957: bbox
0958: .transform(staticTransform.transform);
0959: cachedBounds
0960: .combine((Bounds) bbox);
0961: } else {
0962: cachedBounds
0963: .combine((Bounds) geometry.geoBounds);
0964: }
0965: }
0966: }
0967: }
0968: }
0969: bounds.combine(cachedBounds);
0970: }
0971: }
0972: } else {
0973:
0974: // Should this be lock too ? ( MT safe ? )
0975: synchronized (localBounds) {
0976: bounds.combine((Bounds) localBounds);
0977: }
0978: }
0979: }
0980:
0981: /**
0982: * assign a name to this node when it is made live.
0983: */
0984:
0985: void setLive(SetLiveState s) {
0986: doSetLive(s);
0987: markAsLive();
0988: }
0989:
0990: void doSetLive(SetLiveState s) {
0991: // System.err.println("S3DRetained : setLive " + s);
0992: Shape3DRetained shape;
0993: GeometryRetained geometry;
0994: int i, j, k, gaCnt;
0995: ArrayList msList = new ArrayList();
0996:
0997: super .doSetLive(s);
0998:
0999: nodeId = universe.getNodeId();
1000:
1001: if (inSharedGroup) {
1002: for (i = 0; i < s.keys.length; i++) {
1003: if (this instanceof OrientedShape3DRetained) {
1004: shape = new OrientedShape3DRetained();
1005: } else {
1006: shape = new Shape3DRetained();
1007: }
1008: shape.key = s.keys[i];
1009: shape.localToVworld = new Transform3D[1][];
1010: shape.localToVworldIndex = new int[1][];
1011:
1012: j = s.keys[i].equals(localToVworldKeys, 0,
1013: localToVworldKeys.length);
1014: /*
1015: System.err.print("s.keys[i] = "+s.keys[i]+" j = "+j);
1016: if(j < 0) {
1017: System.err.println("Shape3dRetained : Can't find hashKey");
1018: }
1019: */
1020: shape.localToVworld[0] = localToVworld[j];
1021: shape.localToVworldIndex[0] = localToVworldIndex[j];
1022: shape.branchGroupPath = (BranchGroupRetained[]) branchGroupPaths
1023: .get(j);
1024: shape.isPickable = s.pickable[i];
1025: shape.isCollidable = s.collidable[i];
1026:
1027: initMirrorShape3D(s, shape, j);
1028:
1029: if (s.switchTargets != null
1030: && s.switchTargets[i] != null) {
1031: s.switchTargets[i].addNode(shape,
1032: Targets.GEO_TARGETS);
1033: shape.closestSwitchParent = s.closestSwitchParents[i];
1034: shape.closestSwitchIndex = s.closestSwitchIndices[i];
1035: }
1036: shape.switchState = (SwitchState) s.switchStates.get(j);
1037:
1038: // Add any scoped lights to the mirror shape
1039: if (s.lights != null) {
1040: ArrayList l = (ArrayList) s.lights.get(j);
1041: if (l != null) {
1042: for (int m = 0; m < l.size(); m++) {
1043: shape.addLight((LightRetained) l.get(m));
1044: }
1045: }
1046: }
1047:
1048: // Add any scoped fog
1049: if (s.fogs != null) {
1050: ArrayList l = (ArrayList) s.fogs.get(j);
1051: if (l != null) {
1052: for (int m = 0; m < l.size(); m++) {
1053: shape.addFog((FogRetained) l.get(m));
1054: }
1055: }
1056: }
1057:
1058: // Add any scoped modelClip
1059: if (s.modelClips != null) {
1060: ArrayList l = (ArrayList) s.modelClips.get(j);
1061: if (l != null) {
1062: for (int m = 0; m < l.size(); m++) {
1063: shape.addModelClip((ModelClipRetained) l
1064: .get(m));
1065: }
1066: }
1067: }
1068:
1069: // Add any scoped alt app
1070: if (s.altAppearances != null) {
1071: ArrayList l = (ArrayList) s.altAppearances.get(j);
1072: if (l != null) {
1073: for (int m = 0; m < l.size(); m++) {
1074: shape
1075: .addAltApp((AlternateAppearanceRetained) l
1076: .get(m));
1077: }
1078: }
1079: }
1080: synchronized (mirrorShape3D) {
1081: mirrorShape3D.add(j, shape);
1082: }
1083:
1084: msList.add(shape);
1085: if (s.viewLists != null) {
1086: shape.viewList = (ArrayList) s.viewLists.get(j);
1087: } else {
1088: shape.viewList = null;
1089: }
1090: }
1091: } else {
1092: if (this instanceof OrientedShape3DRetained) {
1093: shape = new OrientedShape3DRetained();
1094: } else {
1095: shape = new Shape3DRetained();
1096: }
1097:
1098: shape.localToVworld = new Transform3D[1][];
1099: shape.localToVworldIndex = new int[1][];
1100: shape.localToVworld[0] = localToVworld[0];
1101: shape.localToVworldIndex[0] = localToVworldIndex[0];
1102: shape.branchGroupPath = (BranchGroupRetained[]) branchGroupPaths
1103: .get(0);
1104: shape.isPickable = s.pickable[0];
1105: shape.isCollidable = s.collidable[0];
1106: initMirrorShape3D(s, shape, 0);
1107:
1108: // Add any scoped lights to the mirror shape
1109: if (s.lights != null) {
1110: ArrayList l = (ArrayList) s.lights.get(0);
1111: for (i = 0; i < l.size(); i++) {
1112: shape.addLight((LightRetained) l.get(i));
1113: }
1114: }
1115:
1116: // Add any scoped fog
1117: if (s.fogs != null) {
1118: ArrayList l = (ArrayList) s.fogs.get(0);
1119: for (i = 0; i < l.size(); i++) {
1120: shape.addFog((FogRetained) l.get(i));
1121: }
1122: }
1123:
1124: // Add any scoped modelClip
1125: if (s.modelClips != null) {
1126: ArrayList l = (ArrayList) s.modelClips.get(0);
1127: for (i = 0; i < l.size(); i++) {
1128: shape.addModelClip((ModelClipRetained) l.get(i));
1129: }
1130:
1131: }
1132:
1133: // Add any scoped alt app
1134: if (s.altAppearances != null) {
1135: ArrayList l = (ArrayList) s.altAppearances.get(0);
1136: for (i = 0; i < l.size(); i++) {
1137: shape.addAltApp((AlternateAppearanceRetained) l
1138: .get(i));
1139: }
1140: }
1141: synchronized (mirrorShape3D) {
1142: mirrorShape3D.add(shape);
1143: }
1144:
1145: msList.add(shape);
1146: if (s.viewLists != null)
1147: shape.viewList = (ArrayList) s.viewLists.get(0);
1148: else
1149: shape.viewList = null;
1150:
1151: if (s.switchTargets != null && s.switchTargets[0] != null) {
1152: s.switchTargets[0].addNode(shape, Targets.GEO_TARGETS);
1153: shape.closestSwitchParent = s.closestSwitchParents[0];
1154: shape.closestSwitchIndex = s.closestSwitchIndices[0];
1155: }
1156: shape.switchState = (SwitchState) s.switchStates.get(0);
1157: }
1158:
1159: for (k = 0; k < msList.size(); k++) {
1160: Shape3DRetained sh = (Shape3DRetained) msList.get(k);
1161:
1162: if (appearance != null) {
1163: synchronized (appearance.liveStateLock) {
1164: if (k == 0) { // Do only first time
1165: appearance.setLive(inBackgroundGroup,
1166: s.refCount);
1167: appearance.initMirrorObject();
1168: if (appearance.renderingAttributes != null)
1169: visible = appearance.renderingAttributes.visible;
1170: }
1171: sh.appearance = (AppearanceRetained) appearance.mirror;
1172: appearance.addAMirrorUser(sh);
1173:
1174: }
1175: } else {
1176: sh.appearance = null;
1177: }
1178:
1179: if (geometryList != null) {
1180: for (gaCnt = 0; gaCnt < geometryList.size(); gaCnt++) {
1181: geometry = (GeometryRetained) geometryList
1182: .get(gaCnt);
1183: if (geometry != null) {
1184: synchronized (geometry.liveStateLock) {
1185: if (k == 0) { // Do only first time
1186: geometry.setLive(inBackgroundGroup,
1187: s.refCount);
1188: }
1189: geometry.addUser(sh);
1190: }
1191: }
1192: }
1193:
1194: }
1195:
1196: // after the geometry has been setLived and bounds computed
1197: if (k == 0 && boundsAutoCompute) { // Do only once
1198: // user may call setBounds with a bounds other than boundingBox
1199: if (!(localBounds instanceof BoundingBox)) {
1200: localBounds = new BoundingBox((BoundingBox) null);
1201: }
1202: getCombineBounds((BoundingBox) localBounds);
1203:
1204: }
1205: // Assign GAtom and set the bounds if we are not using switch
1206: initializeGAtom(sh);
1207:
1208: GeometryAtom ga = getGeomAtom(sh);
1209:
1210: // Add the geometry atom for this shape to the nodeList
1211: s.nodeList.add(ga);
1212:
1213: if (s.transformTargets != null
1214: && s.transformTargets[k] != null) {
1215: // Add the geometry atom for this shape to the transformTargets
1216:
1217: s.transformTargets[k].addNode(ga, Targets.GEO_TARGETS);
1218: }
1219: }
1220:
1221: s.notifyThreads |= (J3dThread.UPDATE_GEOMETRY
1222: | J3dThread.UPDATE_TRANSFORM | J3dThread.UPDATE_RENDER | J3dThread.UPDATE_RENDERING_ENVIRONMENT);
1223:
1224: }
1225:
1226: /**
1227: * This clears all references in a mirror shape
1228: */
1229: // This is call in RenderingEnvironmentStructure.removeNode() because that is the
1230: // last point that will reference this ms.
1231: // called on the mirror shape ..
1232: void clearMirrorShape() {
1233: int i;
1234:
1235: source = null;
1236: sourceNode = null;
1237: parent = null;
1238:
1239: if (otherAppearance != null) {
1240: otherAppearance.sgApp.removeAMirrorUser(this );
1241: otherAppearance = null;
1242: }
1243:
1244: appearance = null;
1245:
1246: branchGroupPath = null;
1247: isPickable = true;
1248: isCollidable = true;
1249: branchGroupPath = null;
1250: // No locking needed. Owner, s3dR, has already been destory.
1251: // DO NOT clear geometryList, ie. geometryList.clear().
1252: // It is referred by the source s3DRetained.
1253: geometryList = null;
1254:
1255: // Clear the mirror scoping info
1256: // Remove all the fogs
1257: for (i = 0; i < numfogs; i++)
1258: fogs[i] = null;
1259: numfogs = 0;
1260:
1261: // Remove all the modelClips
1262: for (i = 0; i < numModelClips; i++)
1263: modelClips[i] = null;
1264: numModelClips = 0;
1265:
1266: // Remove all the lights
1267: for (i = 0; i < numlights; i++)
1268: lights[i] = null;
1269: numlights = 0;
1270:
1271: // Remove all the al app
1272: for (i = 0; i < numAltApps; i++)
1273: altApps[i] = null;
1274: numAltApps = 0;
1275:
1276: viewList = null;
1277:
1278: }
1279:
1280: /**
1281: * assign a name to this node when it is made live.
1282: */
1283: void clearLive(SetLiveState s) {
1284:
1285: //System.err.println("S3DRetained : clearLive " + s);
1286:
1287: int i, j, gaCnt;
1288: Shape3DRetained shape;
1289: GeometryRetained geometry;
1290: Object[] shapes;
1291: ArrayList msList = new ArrayList();
1292:
1293: super .clearLive(s);
1294:
1295: if (inSharedGroup) {
1296: synchronized (mirrorShape3D) {
1297: shapes = mirrorShape3D.toArray();
1298: for (i = 0; i < s.keys.length; i++) {
1299: for (j = 0; j < shapes.length; j++) {
1300: shape = (Shape3DRetained) shapes[j];
1301: if (shape.key.equals(s.keys[i])) {
1302: mirrorShape3D.remove(mirrorShape3D
1303: .indexOf(shape));
1304: if (s.switchTargets != null
1305: && s.switchTargets[i] != null) {
1306: s.switchTargets[i].addNode(shape,
1307: Targets.GEO_TARGETS);
1308: }
1309: msList.add(shape);
1310: GeometryAtom ga = getGeomAtom(shape);
1311:
1312: // Add the geometry atom for this shape to the nodeList
1313: s.nodeList.add(ga);
1314: if (s.transformTargets != null
1315: && s.transformTargets[i] != null) {
1316: s.transformTargets[i].addNode(ga,
1317: Targets.GEO_TARGETS);
1318: }
1319: }
1320: }
1321: }
1322: }
1323: } else {
1324: // Only entry 0 is valid
1325: shape = (Shape3DRetained) mirrorShape3D.get(0);
1326: synchronized (mirrorShape3D) {
1327: mirrorShape3D.remove(0);
1328: }
1329:
1330: if (s.switchTargets != null && s.switchTargets[0] != null) {
1331: s.switchTargets[0].addNode(shape, Targets.GEO_TARGETS);
1332: }
1333:
1334: msList.add(shape);
1335:
1336: GeometryAtom ga = getGeomAtom(shape);
1337:
1338: // Add the geometry atom for this shape to the nodeList
1339: s.nodeList.add(ga);
1340: if (s.transformTargets != null
1341: && s.transformTargets[0] != null) {
1342: s.transformTargets[0].addNode(ga, Targets.GEO_TARGETS);
1343: }
1344: }
1345:
1346: for (int k = 0; k < msList.size(); k++) {
1347: Shape3DRetained sh = (Shape3DRetained) msList.get(k);
1348: if (appearance != null) {
1349: synchronized (appearance.liveStateLock) {
1350: if (k == 0) {
1351: appearance.clearLive(s.refCount);
1352: }
1353: appearance.removeAMirrorUser(sh);
1354: }
1355: }
1356: if (geometryList != null) {
1357: for (gaCnt = 0; gaCnt < geometryList.size(); gaCnt++) {
1358: geometry = (GeometryRetained) geometryList
1359: .get(gaCnt);
1360: if (geometry != null) {
1361: synchronized (geometry.liveStateLock) {
1362: if (k == 0) {
1363: geometry.clearLive(s.refCount);
1364: }
1365: geometry.removeUser(sh);
1366: }
1367: }
1368: }
1369: }
1370: }
1371:
1372: s.notifyThreads |= (J3dThread.UPDATE_GEOMETRY
1373: | J3dThread.UPDATE_TRANSFORM |
1374: // This is used to clear the scope info
1375: // of all the mirror shapes
1376: J3dThread.UPDATE_RENDERING_ENVIRONMENT | J3dThread.UPDATE_RENDER);
1377:
1378: if (!source.isLive()) {
1379: // Clear the mirror scoping info
1380: // Remove all the fogs
1381: for (i = 0; i < numfogs; i++)
1382: fogs[i] = null;
1383: numfogs = 0;
1384:
1385: // Remove all the modelClips
1386: for (i = 0; i < numModelClips; i++)
1387: modelClips[i] = null;
1388: numModelClips = 0;
1389:
1390: // Remove all the lights
1391: for (i = 0; i < numlights; i++)
1392: lights[i] = null;
1393: numlights = 0;
1394:
1395: // Remove all the al app
1396: for (i = 0; i < numAltApps; i++)
1397: altApps[i] = null;
1398: numAltApps = 0;
1399: }
1400: }
1401:
1402: boolean isStatic() {
1403: if (source.getCapability(Shape3D.ALLOW_APPEARANCE_WRITE)
1404: || source.getCapability(Shape3D.ALLOW_GEOMETRY_WRITE)
1405: || source
1406: .getCapability(Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE)) {
1407: return false;
1408: } else {
1409: return true;
1410: }
1411: }
1412:
1413: boolean staticXformCanBeApplied() {
1414:
1415: // static xform can be applied if
1416: // . shape is not pickable or collidable
1417: // . geometry is not being shared by more than one shape nodes
1418: // . geometry will be put in display list
1419: // . geometry is not readable
1420:
1421: // no static xform if shape is pickable or collidable because
1422: // otherwise the static xform will have to be applied to the
1423: // currentLocalToVworld in the intersect test, it will then
1424: // be more costly and really beat the purpose of eliminating
1425: // the static transform group
1426: if (isPickable || isCollidable
1427: || source.getCapability(Shape3D.ALLOW_PICKABLE_WRITE)
1428: || source.getCapability(Shape3D.ALLOW_COLLIDABLE_WRITE)) {
1429: return false;
1430: }
1431:
1432: if (appearance != null
1433: && (appearance.transparencyAttributes != null && appearance.transparencyAttributes.transparencyMode != TransparencyAttributes.NONE))
1434: return false;
1435:
1436: GeometryRetained geo;
1437: boolean alphaEditable;
1438:
1439: for (int i = 0; i < geometryList.size(); i++) {
1440: geo = (GeometryRetained) geometryList.get(i);
1441: if (geo != null) {
1442: if (geo.refCnt > 1) {
1443: return false;
1444: }
1445: alphaEditable = isAlphaEditable(geo);
1446: if (geo instanceof GeometryArrayRetained) {
1447: geo.isEditable = !((GeometryArrayRetained) geo)
1448: .isWriteStatic();
1449:
1450: // TODO: for now if vertex data can be returned, then
1451: // don't apply static transform
1452: if (geo.source
1453: .getCapability(GeometryArray.ALLOW_COORDINATE_READ)
1454: || geo.source
1455: .getCapability(GeometryArray.ALLOW_NORMAL_READ))
1456: return false;
1457:
1458: }
1459:
1460: if (!geo.canBeInDisplayList(alphaEditable)) {
1461: return false;
1462: }
1463: }
1464: }
1465: return true;
1466: }
1467:
1468: void compile(CompileState compState) {
1469: AppearanceRetained newApp;
1470:
1471: super .compile(compState);
1472:
1473: if (isStatic() && staticXformCanBeApplied()) {
1474: mergeFlag = SceneGraphObjectRetained.MERGE;
1475: if (J3dDebug.devPhase && J3dDebug.debug) {
1476: compState.numShapesWStaticTG++;
1477: }
1478: } else {
1479: mergeFlag = SceneGraphObjectRetained.DONT_MERGE;
1480: compState.keepTG = true;
1481: }
1482:
1483: if (J3dDebug.devPhase && J3dDebug.debug) {
1484: compState.numShapes++;
1485: }
1486:
1487: if (appearance != null) {
1488: appearance.compile(compState);
1489: // Non-static apperanace can still be compiled, since in compile
1490: // state we will be grouping all shapes that have same appearance
1491: // so, when the appearance changes, all the shapes will be affected
1492: // For non-static appearances, we don't get an equivalent appearance
1493: // from the compile state
1494: if (appearance.isStatic()) {
1495: newApp = compState.getAppearance(appearance);
1496: appearance = newApp;
1497: }
1498: }
1499:
1500: for (int i = 0; i < geometryList.size(); i++) {
1501: GeometryRetained geo = (GeometryRetained) geometryList
1502: .get(i);
1503: if (geo != null)
1504: geo.compile(compState);
1505: }
1506:
1507: }
1508:
1509: void merge(CompileState compState) {
1510:
1511: if (mergeFlag == SceneGraphObjectRetained.DONT_MERGE) {
1512:
1513: // no need to save the staticTransform here
1514:
1515: TransformGroupRetained saveStaticTransform = compState.staticTransform;
1516: compState.staticTransform = null;
1517: super .merge(compState);
1518: compState.staticTransform = saveStaticTransform;
1519: } else {
1520: super .merge(compState);
1521: }
1522:
1523: if (shapeIsMergeable(compState)) {
1524: compState.addShape(this );
1525: }
1526: }
1527:
1528: boolean shapeIsMergeable(CompileState compState) {
1529: boolean mergeable = true;
1530: AppearanceRetained newApp;
1531: int i;
1532:
1533: GeometryRetained geometry = null;
1534: int index = 0;
1535: i = 0;
1536: /*
1537: if (isPickable)
1538: return false;
1539: */
1540:
1541: // For now, don't merge if the shape has static transform
1542: if (staticTransform != null)
1543: return false;
1544:
1545: // If this shape's to be immediate parent is orderedGroup or a switchNode
1546: // this shape is not mergerable
1547: if (parent instanceof OrderedGroupRetained
1548: || parent instanceof SwitchRetained)
1549: return false;
1550:
1551: // Get the first geometry that is non-null
1552: while (geometry == null && index < geometryList.size()) {
1553: geometry = (GeometryRetained) geometryList.get(index);
1554: index++;
1555: }
1556:
1557: if (!(geometry instanceof GeometryArrayRetained)) {
1558: return false;
1559: }
1560:
1561: GeometryArrayRetained firstGeo = (GeometryArrayRetained) geometry;
1562:
1563: for (i = index; (i < geometryList.size() && mergeable); i++) {
1564: geometry = (GeometryRetained) geometryList.get(i);
1565: if (geometry != null) {
1566: GeometryArrayRetained geo = (GeometryArrayRetained) geometry;
1567:
1568: if (!geo.isWriteStatic())
1569: mergeable = false;
1570:
1571: if (geo.vertexFormat != firstGeo.vertexFormat)
1572: mergeable = false;
1573:
1574: }
1575: }
1576:
1577: // For now, turn off lots of capability bits
1578: if (source.getCapability(Shape3D.ALLOW_COLLISION_BOUNDS_WRITE)
1579: || source.getCapability(Shape3D.ALLOW_APPEARANCE_WRITE)
1580: || source
1581: .getCapability(Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE)
1582: || source
1583: .getCapability(Shape3D.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE)
1584: || source.getCapability(Shape3D.ALLOW_BOUNDS_WRITE)
1585: || source.getCapability(Shape3D.ALLOW_COLLIDABLE_WRITE)
1586: || source.getCapability(Shape3D.ALLOW_PICKABLE_WRITE)
1587: || source.getCapability(Shape3D.ALLOW_GEOMETRY_WRITE)) {
1588: mergeable = false;
1589: }
1590:
1591: return mergeable;
1592:
1593: }
1594:
1595: void getMirrorObjects(ArrayList list, HashKey k) {
1596: Shape3DRetained ms;
1597: if (inSharedGroup) {
1598: if (k.count == 0) {
1599: // System.err.println("===> CAN NEVER BE TRUE");
1600: return;
1601: } else {
1602: ms = getMirrorShape(k);
1603: }
1604: } else {
1605: ms = (Shape3DRetained) mirrorShape3D.get(0);
1606: }
1607:
1608: list.add(getGeomAtom(ms));
1609:
1610: }
1611:
1612: // Called on the mirror Object
1613: void addLight(LightRetained light) {
1614: LightRetained[] newlights;
1615: int i, n;
1616: Shape3DRetained ms;
1617:
1618: if (lights == null) {
1619: lights = new LightRetained[10];
1620: } else if (lights.length == numlights) {
1621: newlights = new LightRetained[numlights * 2];
1622: for (i = 0; i < numlights; i++) {
1623: newlights[i] = lights[i];
1624: }
1625: lights = newlights;
1626: }
1627: lights[numlights] = light;
1628: numlights++;
1629: }
1630:
1631: // called on the mirror object
1632: void removeLight(LightRetained light) {
1633: int i;
1634:
1635: for (i = 0; i < numlights; i++) {
1636: if (lights[i] == light) {
1637: lights[i] = null;
1638: break;
1639: }
1640: }
1641:
1642: // Shift everyone down one.
1643: for (i++; i < numlights; i++) {
1644: lights[i - 1] = lights[i];
1645: }
1646: numlights--;
1647: }
1648:
1649: // Called on the mirror object
1650: void addFog(FogRetained fog) {
1651: FogRetained[] newfogs;
1652: int i;
1653:
1654: if (fogs == null) {
1655: fogs = new FogRetained[10];
1656: } else if (fogs.length == numfogs) {
1657: newfogs = new FogRetained[numfogs * 2];
1658: for (i = 0; i < numfogs; i++) {
1659: newfogs[i] = fogs[i];
1660: }
1661: fogs = newfogs;
1662: }
1663: fogs[numfogs] = fog;
1664: numfogs++;
1665: }
1666:
1667: // called on the mirror object
1668: void removeFog(FogRetained fog) {
1669: int i;
1670:
1671: for (i = 0; i < numfogs; i++) {
1672: if (fogs[i] == fog) {
1673: fogs[i] = null;
1674: break;
1675: }
1676: }
1677:
1678: // Shift everyone down one.
1679: for (i++; i < numfogs; i++) {
1680: fogs[i - 1] = fogs[i];
1681: }
1682: numfogs--;
1683:
1684: }
1685:
1686: // Called on the mirror object
1687: void addModelClip(ModelClipRetained modelClip) {
1688: ModelClipRetained[] newModelClips;
1689: int i;
1690:
1691: if (modelClips == null) {
1692: modelClips = new ModelClipRetained[10];
1693: } else if (modelClips.length == numModelClips) {
1694: newModelClips = new ModelClipRetained[numModelClips * 2];
1695: for (i = 0; i < numModelClips; i++) {
1696: newModelClips[i] = modelClips[i];
1697: }
1698: modelClips = newModelClips;
1699: }
1700: modelClips[numModelClips] = modelClip;
1701: numModelClips++;
1702: }
1703:
1704: // called on the mirror object
1705: void removeModelClip(ModelClipRetained modelClip) {
1706: int i;
1707:
1708: for (i = 0; i < numModelClips; i++) {
1709: if (modelClips[i] == modelClip) {
1710: modelClips[i] = null;
1711: break;
1712: }
1713: }
1714:
1715: // Shift everyone down one.
1716: for (i++; i < numModelClips; i++) {
1717: modelClips[i - 1] = modelClips[i];
1718: }
1719: numModelClips--;
1720:
1721: }
1722:
1723: // Called on the mirror object
1724: void addAltApp(AlternateAppearanceRetained aApp) {
1725: AlternateAppearanceRetained[] newAltApps;
1726: int i;
1727: if (altApps == null) {
1728: altApps = new AlternateAppearanceRetained[10];
1729: } else if (altApps.length == numAltApps) {
1730: newAltApps = new AlternateAppearanceRetained[numAltApps * 2];
1731: for (i = 0; i < numAltApps; i++) {
1732: newAltApps[i] = altApps[i];
1733: }
1734: altApps = newAltApps;
1735: }
1736: altApps[numAltApps] = aApp;
1737: numAltApps++;
1738: }
1739:
1740: // called on the mirror object
1741: void removeAltApp(AlternateAppearanceRetained aApp) {
1742: int i;
1743:
1744: for (i = 0; i < numAltApps; i++) {
1745: if (altApps[i] == aApp) {
1746: altApps[i] = null;
1747: break;
1748: }
1749: }
1750:
1751: // Shift everyone down one.
1752: for (i++; i < numAltApps; i++) {
1753: altApps[i - 1] = altApps[i];
1754: }
1755: numAltApps--;
1756:
1757: }
1758:
1759: void updatePickable(HashKey keys[], boolean pick[]) {
1760: super .updatePickable(keys, pick);
1761: Shape3DRetained shape;
1762:
1763: if (!inSharedGroup) {
1764: shape = (Shape3DRetained) mirrorShape3D.get(0);
1765: shape.isPickable = pick[0];
1766: } else {
1767: int size = mirrorShape3D.size();
1768: for (int j = 0; j < keys.length; j++) {
1769: for (int i = 0; i < size; i++) {
1770: shape = (Shape3DRetained) mirrorShape3D.get(i);
1771: if (keys[j].equals(shape.key)) {
1772: shape.isPickable = pick[j];
1773: break;
1774: }
1775:
1776: }
1777: }
1778: }
1779: }
1780:
1781: void updateCollidable(HashKey keys[], boolean collide[]) {
1782: super .updateCollidable(keys, collide);
1783: Shape3DRetained shape;
1784:
1785: if (!inSharedGroup) {
1786: shape = (Shape3DRetained) mirrorShape3D.get(0);
1787: shape.isCollidable = collide[0];
1788: } else {
1789: int size = mirrorShape3D.size();
1790: for (int j = 0; j < keys.length; j++) {
1791: for (int i = 0; i < size; i++) {
1792: shape = (Shape3DRetained) mirrorShape3D.get(i);
1793: if (keys[j].equals(shape.key)) {
1794: shape.isCollidable = collide[j];
1795: break;
1796: }
1797:
1798: }
1799: }
1800: }
1801: }
1802:
1803: // New 1.2.1 code ....
1804:
1805: // Remove the old geometry atoms and reInsert
1806: // the new geometry atoms and update the transform
1807: // target list
1808:
1809: private void sendDataChangedMessage(GeometryRetained newGeom) {
1810:
1811: int i, j, gaCnt;
1812: GeometryAtom[] newGAArray = null;
1813: GeometryAtom[] oldGAArray = null;
1814: GeometryAtom[] newGeometryAtoms = null;
1815: int geometryCnt = 0;
1816: GeometryRetained geometry = null;
1817:
1818: int s3dMSize = mirrorShape3D.size();
1819:
1820: if (s3dMSize < 1)
1821: return;
1822:
1823: Shape3DRetained mS3d = (Shape3DRetained) mirrorShape3D.get(0);
1824:
1825: mS3d.mirrorShape3DLock.writeLock();
1826:
1827: GeometryAtom oldGA = mS3d.geomAtom;
1828:
1829: GeometryAtom newGA = new GeometryAtom();
1830:
1831: if (newGeom != null) {
1832: newGeom.addUser(mS3d);
1833: }
1834:
1835: int gSize = geometryList.size();
1836:
1837: for (i = 0; i < gSize; i++) {
1838: geometry = (GeometryRetained) geometryList.get(i);
1839: if (geometry != null) {
1840: newGA.geoType = geometry.geoType;
1841: newGA.alphaEditable = mS3d.isAlphaEditable(geometry);
1842: break;
1843: }
1844: }
1845:
1846: if ((geometry != null)
1847: && (geometry.geoType == GeometryRetained.GEO_TYPE_TEXT3D)) {
1848:
1849: for (i = 0; i < gSize; i++) {
1850: geometry = (GeometryRetained) geometryList.get(i);
1851: if (geometry != null) {
1852: Text3DRetained tempT3d = (Text3DRetained) geometry;
1853: geometryCnt += tempT3d.numChars;
1854: } else {
1855: // This is slightly wasteful, but not quite worth to optimize yet.
1856: geometryCnt++;
1857: }
1858: }
1859: newGA.geometryArray = new GeometryRetained[geometryCnt];
1860: newGA.lastLocalTransformArray = new Transform3D[geometryCnt];
1861: // Reset geometryCnt;
1862: geometryCnt = 0;
1863:
1864: } else {
1865: newGA.geometryArray = new GeometryRetained[gSize];
1866: }
1867:
1868: newGA.locale = mS3d.locale;
1869: newGA.visible = visible;
1870: newGA.source = mS3d;
1871:
1872: for (gaCnt = 0; gaCnt < gSize; gaCnt++) {
1873: geometry = (GeometryRetained) geometryList.get(gaCnt);
1874: if (geometry == null) {
1875: newGA.geometryArray[geometryCnt++] = null;
1876: } else {
1877: if (geometry.geoType == GeometryRetained.GEO_TYPE_TEXT3D) {
1878: Text3DRetained t = (Text3DRetained) geometry;
1879: GeometryRetained geo;
1880: for (i = 0; i < t.numChars; i++, geometryCnt++) {
1881: geo = t.geometryList[i];
1882: if (geo != null) {
1883: newGA.geometryArray[geometryCnt] = geo;
1884: newGA.lastLocalTransformArray[geometryCnt] = t.charTransforms[i];
1885:
1886: } else {
1887: newGA.geometryArray[geometryCnt] = null;
1888: newGA.lastLocalTransformArray[geometryCnt] = null;
1889: }
1890:
1891: }
1892:
1893: } else {
1894: newGA.geometryArray[geometryCnt++] = geometry;
1895: }
1896: }
1897: }
1898:
1899: oldGAArray = new GeometryAtom[s3dMSize];
1900: newGAArray = new GeometryAtom[s3dMSize];
1901: oldGAArray[0] = oldGA;
1902: newGAArray[0] = newGA;
1903:
1904: mS3d.geomAtom = newGA;
1905: mS3d.mirrorShape3DLock.writeUnlock();
1906:
1907: // ..... clone the rest of mirrorS3D's GA with the above newGA, but modify
1908: // its source.
1909:
1910: for (i = 1; i < s3dMSize; i++) {
1911: mS3d = (Shape3DRetained) mirrorShape3D.get(i);
1912: mS3d.mirrorShape3DLock.writeLock();
1913: oldGA = mS3d.geomAtom;
1914: newGA = new GeometryAtom();
1915:
1916: if (newGeom != null) {
1917: newGeom.addUser(mS3d);
1918: }
1919:
1920: newGA.geoType = newGAArray[0].geoType;
1921: newGA.locale = mS3d.locale;
1922: newGA.visible = visible;
1923: newGA.source = mS3d;
1924: newGA.alphaEditable = newGAArray[0].alphaEditable;
1925:
1926: newGA.geometryArray = new GeometryRetained[newGAArray[0].geometryArray.length];
1927: for (j = 0; j < newGA.geometryArray.length; j++) {
1928: newGA.geometryArray[j] = newGAArray[0].geometryArray[j];
1929: }
1930:
1931: oldGAArray[i] = oldGA;
1932: newGAArray[i] = newGA;
1933:
1934: mS3d.geomAtom = newGA;
1935: mS3d.mirrorShape3DLock.writeUnlock();
1936: }
1937:
1938: TargetsInterface ti = ((GroupRetained) parent)
1939: .getClosestTargetsInterface(TargetsInterface.TRANSFORM_TARGETS);
1940: CachedTargets[] newCtArr = null;
1941:
1942: if (ti != null) {
1943: CachedTargets ct;
1944: newCtArr = new CachedTargets[s3dMSize];
1945:
1946: for (i = 0; i < s3dMSize; i++) {
1947:
1948: ct = ti.getCachedTargets(
1949: TargetsInterface.TRANSFORM_TARGETS, i, -1);
1950: if (ct != null) {
1951: newCtArr[i] = new CachedTargets();
1952: newCtArr[i].copy(ct);
1953: newCtArr[i].replace(oldGAArray[i], newGAArray[i],
1954: Targets.GEO_TARGETS);
1955: } else {
1956: newCtArr[i] = null;
1957: }
1958: }
1959: ti.resetCachedTargets(TargetsInterface.TRANSFORM_TARGETS,
1960: newCtArr, -1);
1961: }
1962:
1963: J3dMessage changeMessage = new J3dMessage();
1964: changeMessage.type = J3dMessage.SHAPE3D_CHANGED;
1965: // Who to send this message to ?
1966: changeMessage.threads = J3dThread.UPDATE_RENDER
1967: | J3dThread.UPDATE_TRANSFORM
1968: | J3dThread.UPDATE_GEOMETRY;
1969: changeMessage.universe = universe;
1970: changeMessage.args[0] = this ;
1971: changeMessage.args[1] = new Integer(GEOMETRY_CHANGED);
1972: changeMessage.args[2] = oldGAArray;
1973: changeMessage.args[3] = newGAArray;
1974: if (ti != null) {
1975: changeMessage.args[4] = ti;
1976: changeMessage.args[5] = newCtArr;
1977: }
1978: if (boundsAutoCompute) {
1979: getCombineBounds((BoundingBox) localBounds);
1980: }
1981: VirtualUniverse.mc.processMessage(changeMessage);
1982:
1983: }
1984:
1985: // ********** End of New 1.2.1 code ....
1986:
1987: Shape3DRetained getMirrorShape(SceneGraphPath path) {
1988: if (!inSharedGroup) {
1989: return (Shape3DRetained) mirrorShape3D.get(0);
1990: }
1991: HashKey key = new HashKey("");
1992: path.getHashKey(key);
1993: return getMirrorShape(key);
1994: }
1995:
1996: Shape3DRetained getMirrorShape(HashKey key) {
1997: if (key == null) {
1998: return (Shape3DRetained) mirrorShape3D.get(0);
1999: } else {
2000: int i = key.equals(localToVworldKeys, 0,
2001: localToVworldKeys.length);
2002:
2003: if (i >= 0) {
2004: return (Shape3DRetained) mirrorShape3D.get(i);
2005: }
2006: }
2007: // Not possible
2008: throw new RuntimeException(
2009: "Shape3DRetained: MirrorShape Not found!");
2010: }
2011:
2012: void setBoundsAutoCompute(boolean autoCompute) {
2013: GeometryRetained geometry;
2014: if (autoCompute != boundsAutoCompute) {
2015: if (autoCompute) {
2016: // localBounds may not have been set to bbox
2017: localBounds = new BoundingBox((BoundingBox) null);
2018: if (source.isLive() && geometryList != null) {
2019: int size = geometryList.size()
2020: * mirrorShape3D.size();
2021: for (int i = 0; i < size; i++) {
2022: geometry = (GeometryRetained) geometryList
2023: .get(i);
2024: geometry.incrComputeGeoBounds();
2025: }
2026: }
2027:
2028: getCombineBounds((BoundingBox) localBounds);
2029: } else {
2030: if (source.isLive() && geometryList != null) {
2031: int size = geometryList.size()
2032: * mirrorShape3D.size();
2033: for (int i = 0; i < size; i++) {
2034: geometry = (GeometryRetained) geometryList
2035: .get(i);
2036: geometry.decrComputeGeoBounds();
2037: }
2038:
2039: }
2040: }
2041: super .setBoundsAutoCompute(autoCompute);
2042: if (source.isLive()) {
2043: J3dMessage message = new J3dMessage();
2044: message.type = J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED;
2045: message.threads = J3dThread.UPDATE_TRANSFORM
2046: | J3dThread.UPDATE_GEOMETRY
2047: | J3dThread.UPDATE_RENDER;
2048: message.universe = universe;
2049: message.args[0] = getGeomAtomsArray(mirrorShape3D);
2050: // no need to clone localBounds
2051: message.args[1] = localBounds;
2052: VirtualUniverse.mc.processMessage(message);
2053: }
2054: }
2055: }
2056:
2057: // This method is called when coordinates of a geometry in the geometrylist
2058: // changed and autoBoundsCompute is true
2059:
2060: void updateBounds() {
2061: localBounds = new BoundingBox((BoundingBox) null);
2062: getCombineBounds((BoundingBox) localBounds);
2063: synchronized (mirrorShape3D) {
2064: if (source.isLive()) {
2065: J3dMessage message = new J3dMessage();
2066: message.type = J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED;
2067: message.threads = J3dThread.UPDATE_TRANSFORM
2068: | J3dThread.UPDATE_GEOMETRY
2069: | J3dThread.UPDATE_RENDER;
2070: message.universe = universe;
2071: message.args[0] = getGeomAtomsArray(mirrorShape3D);
2072: // no need to clone localBounds
2073: message.args[1] = localBounds;
2074: VirtualUniverse.mc.processMessage(message);
2075: }
2076: }
2077: }
2078:
2079: boolean allowIntersect() {
2080: GeometryRetained ga = null;
2081:
2082: for (int i = 0; i < geometryList.size(); i++) {
2083: ga = (GeometryRetained) geometryList.get(i);
2084: if (ga != null)
2085: if (!ga.source.getCapability(Geometry.ALLOW_INTERSECT)) {
2086: return false;
2087: }
2088: }
2089: return true;
2090: }
2091:
2092: boolean intersectGeometryList(Shape3DRetained otherShape) {
2093: GeometryRetained geom1, geom2;
2094: ArrayList gaList = otherShape.geometryList;
2095: int gaSize = gaList.size();
2096: Transform3D otherLocalToVworld = otherShape
2097: .getCurrentLocalToVworld();
2098: Transform3D this LocalToVworld = getCurrentLocalToVworld();
2099: View views = null;
2100: int primaryViewIdx = -1;
2101:
2102: if (this instanceof OrientedShape3DRetained) {
2103: primaryViewIdx = getPrimaryViewIdx();
2104: this LocalToVworld.mul(((OrientedShape3DRetained) this )
2105: .getOrientedTransform(primaryViewIdx));
2106: }
2107:
2108: if (otherShape instanceof OrientedShape3DRetained) {
2109: if (primaryViewIdx < 0) {
2110: primaryViewIdx = getPrimaryViewIdx();
2111: }
2112: otherLocalToVworld
2113: .mul(((OrientedShape3DRetained) otherShape)
2114: .getOrientedTransform(primaryViewIdx));
2115: }
2116:
2117: for (int i = geometryList.size() - 1; i >= 0; i--) {
2118: geom1 = (GeometryRetained) geometryList.get(i);
2119: if (geom1 != null) {
2120: for (int j = gaSize - 1; j >= 0; j--) {
2121: geom2 = (GeometryRetained) gaList.get(j);
2122: if ((geom2 != null)
2123: && geom1.intersect(this LocalToVworld,
2124: otherLocalToVworld, geom2)) {
2125: return true;
2126: }
2127: }
2128: }
2129: }
2130:
2131: return false;
2132: }
2133:
2134: boolean intersectGeometryList(Transform3D this LocalToVworld,
2135: Bounds targetBound) {
2136:
2137: GeometryRetained geometry;
2138:
2139: if (this instanceof OrientedShape3DRetained) {
2140: Transform3D orientedTransform = ((OrientedShape3DRetained) this )
2141: .getOrientedTransform(getPrimaryViewIdx());
2142: this LocalToVworld.mul(orientedTransform);
2143: }
2144:
2145: for (int i = geometryList.size() - 1; i >= 0; i--) {
2146: geometry = (GeometryRetained) geometryList.get(i);
2147: if ((geometry != null)
2148: && geometry.intersect(this LocalToVworld,
2149: targetBound)) {
2150: return true;
2151: }
2152: }
2153:
2154: return false;
2155:
2156: }
2157:
2158: /**
2159: * This initialize the mirror shape to reflect the state of the
2160: * real Morph.
2161: */
2162: void initMirrorShape3D(SetLiveState s, MorphRetained morph,
2163: int index) {
2164:
2165: GeometryRetained geometry;
2166:
2167: GeometryAtom[] newGeometryAtoms = null;
2168:
2169: universe = morph.universe;
2170: inSharedGroup = morph.inSharedGroup;
2171: inBackgroundGroup = morph.inBackgroundGroup;
2172: geometryBackground = morph.geometryBackground;
2173: parent = morph.parent;
2174: locale = morph.locale;
2175:
2176: OrderedPath op = (OrderedPath) s.orderedPaths.get(index);
2177: if (op.pathElements.size() == 0) {
2178: orderedPath = null;
2179: } else {
2180: orderedPath = op;
2181: }
2182:
2183: staticTransform = morph.staticTransform;
2184: if (morph.boundsAutoCompute) {
2185: localBounds.set(morph.localBounds);
2186: }
2187: bounds = localBounds;
2188: vwcBounds = new BoundingBox((BoundingBox) null);
2189: vwcBounds.transform(bounds, getCurrentLocalToVworld(0));
2190:
2191: if (morph.collisionBound == null) {
2192: collisionBound = null;
2193: collisionVwcBound = vwcBounds;
2194: } else {
2195: collisionBound = morph.collisionBound;
2196: collisionVwcBound = (Bounds) collisionBound.clone();
2197: collisionVwcBound.transform(getCurrentLocalToVworld(0));
2198: }
2199:
2200: appearanceOverrideEnable = morph.appearanceOverrideEnable;
2201:
2202: // mga is the final geometry we're interested.
2203: geometryList = new ArrayList(1);
2204: geometryList
2205: .add((GeometryArrayRetained) morph.morphedGeometryArray.retained);
2206:
2207: GeometryAtom gAtom = new GeometryAtom();
2208: gAtom.geometryArray = new GeometryRetained[1];
2209:
2210: gAtom.locale = locale;
2211: gAtom.visible = morph.visible;
2212: gAtom.source = this ;
2213:
2214: geometry = (GeometryRetained) geometryList.get(0);
2215:
2216: if (geometry == null) {
2217: gAtom.geometryArray[0] = null;
2218: } else {
2219: gAtom.geometryArray[0] = (GeometryArrayRetained) morph.morphedGeometryArray.retained;
2220: gAtom.geoType = gAtom.geometryArray[0].geoType;
2221: }
2222: geomAtom = gAtom;
2223:
2224: // Assign the parent of this mirror shape node
2225: sourceNode = morph;
2226: }
2227:
2228: // geometries in morph object is modified, update the geometry
2229: // list in the mirror shapes and the geometry array in the geometry atom
2230:
2231: void setMorphGeometry(Geometry geometry, ArrayList mirrorShapes) {
2232: GeometryAtom oldGA, newGA;
2233: Shape3DRetained ms;
2234: TransformGroupRetained tg;
2235: int nMirrorShapes = mirrorShapes.size();
2236: int i;
2237:
2238: GeometryAtom oldGAArray[] = new GeometryAtom[nMirrorShapes];
2239: GeometryAtom newGAArray[] = new GeometryAtom[nMirrorShapes];
2240:
2241: for (i = 0; i < nMirrorShapes; i++) {
2242: ms = (Shape3DRetained) mirrorShapes.get(i);
2243:
2244: oldGA = Shape3DRetained.getGeomAtom(ms);
2245:
2246: ms.geometryList = new ArrayList(1);
2247: ms.geometryList
2248: .add((GeometryArrayRetained) geometry.retained);
2249:
2250: newGA = new GeometryAtom();
2251: newGA.geometryArray = new GeometryRetained[1];
2252:
2253: if (geometry == null) {
2254: newGA.geometryArray[0] = null;
2255: } else {
2256: newGA.geometryArray[0] = (GeometryArrayRetained) geometry.retained;
2257: newGA.geoType = newGA.geometryArray[0].geoType;
2258: }
2259:
2260: newGA.locale = locale;
2261: newGA.visible = oldGA.visible;
2262: newGA.source = this ;
2263:
2264: oldGAArray[i] = oldGA;
2265: newGAArray[i] = newGA;
2266:
2267: Shape3DRetained.setGeomAtom(ms, newGA);
2268: }
2269:
2270: TargetsInterface ti = ((GroupRetained) parent)
2271: .getClosestTargetsInterface(TargetsInterface.TRANSFORM_TARGETS);
2272: CachedTargets[] newCtArr = null;
2273:
2274: if (ti != null) {
2275: CachedTargets ct;
2276: newCtArr = new CachedTargets[nMirrorShapes];
2277:
2278: for (i = 0; i < nMirrorShapes; i++) {
2279:
2280: ct = ti.getCachedTargets(
2281: TargetsInterface.TRANSFORM_TARGETS, i, -1);
2282: if (ct != null) {
2283: newCtArr[i] = new CachedTargets();
2284: newCtArr[i].copy(ct);
2285: newCtArr[i].replace(oldGAArray[i], newGAArray[i],
2286: Targets.GEO_TARGETS);
2287: } else {
2288: newCtArr[i] = null;
2289: }
2290: }
2291: }
2292:
2293: // send a Shape GEOMETRY_CHANGED message for all geometry atoms
2294:
2295: J3dMessage changeMessage = new J3dMessage();
2296: changeMessage.type = J3dMessage.SHAPE3D_CHANGED;
2297: changeMessage.threads = J3dThread.UPDATE_RENDER
2298: | J3dThread.UPDATE_TRANSFORM
2299: | J3dThread.UPDATE_GEOMETRY;
2300: changeMessage.universe = universe;
2301: changeMessage.args[0] = this ;
2302: changeMessage.args[1] = new Integer(GEOMETRY_CHANGED);
2303: changeMessage.args[2] = oldGAArray;
2304: changeMessage.args[3] = newGAArray;
2305: if (ti != null) {
2306: changeMessage.args[4] = ti;
2307: changeMessage.args[5] = newCtArr;
2308: }
2309: VirtualUniverse.mc.processMessage(changeMessage);
2310: }
2311:
2312: /**
2313: * Return an array of geometry atoms belongs to userList.
2314: * The input is an arraylist of Shape3DRetained type.
2315: * This is used to send a message of the snapshot of the
2316: * geometry atoms that are affected by this change.
2317: */
2318: final static GeometryAtom[] getGeomAtomsArray(ArrayList userList) {
2319: Shape3DRetained ms = null;
2320: GeometryAtom[] gaArr = null;
2321: int size, nullCnt = 0, i, j;
2322:
2323: synchronized (userList) {
2324: size = userList.size();
2325: gaArr = new GeometryAtom[size];
2326: for (i = 0; i < size; i++) {
2327: ms = (Shape3DRetained) userList.get(i);
2328: ms.mirrorShape3DLock.readLock();
2329: if (ms.geomAtom == null) {
2330: nullCnt++;
2331: }
2332: gaArr[i] = ms.geomAtom;
2333: ms.mirrorShape3DLock.readUnlock();
2334: }
2335: }
2336: if (nullCnt == 0) {
2337: return gaArr;
2338: } else if (nullCnt == size) {
2339: return null;
2340: } else {
2341: GeometryAtom[] newGaArr = new GeometryAtom[size - nullCnt];
2342:
2343: for (i = 0, j = 0; i < size; i++) {
2344: if (gaArr[i] != null) {
2345: newGaArr[j++] = gaArr[i];
2346: }
2347: }
2348: return newGaArr;
2349: }
2350: }
2351:
2352: /**
2353: * Return a list of geometry atoms belongs to userList and places a list of
2354: * universe found in userList in univList.
2355: * The input is an array of Shape3DRetained type.
2356: * univList is assume to be empty.
2357: * This is used to send a message of the snapshot of the
2358: * geometry atoms that are affected by this change.
2359: */
2360: final static ArrayList getGeomAtomsList(ArrayList userList,
2361: ArrayList univList) {
2362: ArrayList listPerUniverse = new ArrayList();
2363: int index;
2364: ArrayList gaList = null;
2365: Shape3DRetained ms = null;
2366: boolean moreThanOneUniv = false;
2367: VirtualUniverse firstFndUniv = null;
2368:
2369: synchronized (userList) {
2370: for (int i = userList.size() - 1; i >= 0; i--) {
2371: ms = (Shape3DRetained) userList.get(i);
2372:
2373: if (moreThanOneUniv == false) {
2374: if (firstFndUniv == null) {
2375: firstFndUniv = ms.universe;
2376: univList.add(ms.universe);
2377:
2378: gaList = new ArrayList();
2379: listPerUniverse.add(gaList);
2380: } else if (firstFndUniv != ms.universe) {
2381: moreThanOneUniv = true;
2382: univList.add(ms.universe);
2383: gaList = new ArrayList();
2384: listPerUniverse.add(gaList);
2385: }
2386: } else {
2387: index = univList.indexOf(ms.universe);
2388: if (index < 0) {
2389: univList.add(ms.universe);
2390: gaList = new ArrayList();
2391: listPerUniverse.add(gaList);
2392: } else {
2393: gaList = (ArrayList) listPerUniverse.get(index);
2394: }
2395: }
2396:
2397: ms.mirrorShape3DLock.readLock();
2398:
2399: if (ms.geomAtom != null) {
2400: gaList.add(ms.geomAtom);
2401: }
2402: ms.mirrorShape3DLock.readUnlock();
2403:
2404: }
2405: }
2406: return listPerUniverse;
2407: }
2408:
2409: final static GeometryAtom getGeomAtom(Shape3DRetained shape) {
2410: GeometryAtom ga;
2411:
2412: shape.mirrorShape3DLock.readLock();
2413: ga = shape.geomAtom;
2414: shape.mirrorShape3DLock.readUnlock();
2415:
2416: return ga;
2417: }
2418:
2419: final static void setGeomAtom(Shape3DRetained shape, GeometryAtom ga) {
2420: shape.mirrorShape3DLock.writeLock();
2421: shape.geomAtom = ga;
2422: shape.mirrorShape3DLock.writeUnlock();
2423: }
2424:
2425: // Alpha is editable due to the appearance
2426: boolean isAlphaEditable(GeometryRetained geo) {
2427:
2428: boolean alphaEditable = false;
2429:
2430: if (appearanceOverrideEnable) {
2431: alphaEditable = true;
2432: } else if (geo != null && appearance != null) {
2433:
2434: AppearanceRetained app = appearance;
2435:
2436: if (source.getCapability(Shape3D.ALLOW_APPEARANCE_WRITE)
2437: || source
2438: .getCapability(Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE)
2439: ||
2440:
2441: app.source
2442: .getCapability(Appearance.ALLOW_RENDERING_ATTRIBUTES_WRITE)
2443: ||
2444:
2445: app.source
2446: .getCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE)
2447: ||
2448:
2449: (app.renderingAttributes != null && (app.renderingAttributes.source
2450: .getCapability(RenderingAttributes.ALLOW_ALPHA_TEST_FUNCTION_WRITE) || app.renderingAttributes.source
2451: .getCapability(RenderingAttributes.ALLOW_IGNORE_VERTEX_COLORS_WRITE)))
2452: ||
2453:
2454: (app.transparencyAttributes != null && (app.transparencyAttributes.source
2455: .getCapability(TransparencyAttributes.ALLOW_MODE_WRITE) || app.transparencyAttributes.source
2456: .getCapability(TransparencyAttributes.ALLOW_VALUE_WRITE)))) {
2457:
2458: alphaEditable = true;
2459:
2460: } else if (geo instanceof GeometryArrayRetained
2461: && (app.source
2462: .getCapability(Appearance.ALLOW_TEXTURE_ATTRIBUTES_WRITE) ||
2463:
2464: (app.textureAttributes != null && app.textureAttributes.source
2465: .getCapability(TextureAttributes.ALLOW_MODE_WRITE)))) {
2466:
2467: alphaEditable = true;
2468:
2469: } else if (geo instanceof RasterRetained) {
2470: if ((((RasterRetained) geo).type & Raster.RASTER_COLOR) != 0
2471: && ((RasterRetained) geo).source
2472: .getCapability(Raster.ALLOW_IMAGE_WRITE)) {
2473:
2474: alphaEditable = true;
2475: }
2476: }
2477: }
2478: return alphaEditable;
2479: }
2480:
2481: // getCombineBounds is faster than computeCombineBounds since it
2482: // does not recompute the geometry.geoBounds
2483: void getCombineBounds(BoundingBox bounds) {
2484:
2485: if (geometryList != null) {
2486: BoundingBox bbox = null;
2487: GeometryRetained geometry;
2488:
2489: if (staticTransform != null) {
2490: bbox = new BoundingBox((BoundingBox) null);
2491: }
2492:
2493: synchronized (bounds) {
2494: bounds.setLower(1.0, 1.0, 1.0);
2495: bounds.setUpper(-1.0, -1.0, -1.0);
2496: for (int i = 0; i < geometryList.size(); i++) {
2497: geometry = (GeometryRetained) geometryList.get(i);
2498: if ((geometry != null)
2499: && (geometry.geoType != GeometryRetained.GEO_TYPE_NONE)) {
2500: synchronized (geometry.geoBounds) {
2501: if (staticTransform != null) {
2502: bbox.set(geometry.geoBounds);
2503: bbox
2504: .transform(staticTransform.transform);
2505: bounds.combine((Bounds) bbox);
2506: } else {
2507: bounds
2508: .combine((Bounds) geometry.geoBounds);
2509: }
2510: }
2511: }
2512: }
2513: }
2514:
2515: // System.err.println("Shape3DRetained - getCombineBounds");
2516: // Enlarge boundingBox to the "minmium bounds" that encompasses all possible
2517: // orientation.
2518: if (this instanceof OrientedShape3DRetained) {
2519: double maxVal = Math.abs(bounds.lower.x);
2520: double tempVal = Math.abs(bounds.upper.x);
2521: if (tempVal > maxVal)
2522: maxVal = tempVal;
2523: tempVal = Math.abs(bounds.lower.y);
2524: if (tempVal > maxVal)
2525: maxVal = tempVal;
2526: tempVal = Math.abs(bounds.upper.y);
2527: if (tempVal > maxVal)
2528: maxVal = tempVal;
2529: tempVal = Math.abs(bounds.lower.z);
2530: if (tempVal > maxVal)
2531: maxVal = tempVal;
2532: tempVal = Math.abs(bounds.upper.z);
2533: if (tempVal > maxVal)
2534: maxVal = tempVal;
2535:
2536: // System.err.println("Shape3DRetained - bounds (Before) " + bounds);
2537: bounds.setLower(-maxVal, -maxVal, -maxVal);
2538: bounds.setUpper(maxVal, maxVal, maxVal);
2539: // System.err.println("Shape3DRetained - bounds (After) " + bounds);
2540: }
2541:
2542: }
2543: }
2544:
2545: boolean isEquivalent(Shape3DRetained shape) {
2546: if (this .appearance != shape.appearance
2547: ||
2548: // Scoping info should be same since they are under same group
2549: this .appearanceOverrideEnable != shape.appearanceOverrideEnable
2550: || this .isPickable != shape.isPickable
2551: || this .isCollidable != shape.isCollidable) {
2552:
2553: return false;
2554: }
2555: if (this .boundsAutoCompute) {
2556: if (!shape.boundsAutoCompute)
2557: return false;
2558: } else {
2559: // If bounds autoCompute is false
2560: // Then check if both bounds are equal
2561: if (this .localBounds != null) {
2562: if (shape.localBounds != null) {
2563: return this .localBounds.equals(shape.localBounds);
2564: }
2565: } else if (shape.localBounds != null) {
2566: return false;
2567: }
2568: }
2569: if (collisionBound != null) {
2570: if (shape.collisionBound == null)
2571: return false;
2572: else
2573: return collisionBound.equals(shape.collisionBound);
2574: } else if (shape.collisionBound != null)
2575: return false;
2576:
2577: return true;
2578: }
2579:
2580: // Bounds can only be set after the geometry is setLived, so has to be done
2581: // here, if we are not using switchVwcBounds
2582: void initializeGAtom(Shape3DRetained ms) {
2583: int i, gaCnt;
2584: int geometryCnt = 0;
2585: int gSize = geometryList.size();
2586: GeometryRetained geometry = null;
2587:
2588: ms.bounds = localBounds;
2589: ms.vwcBounds = new BoundingBox((BoundingBox) null);
2590: ms.vwcBounds
2591: .transform(ms.bounds, ms.getCurrentLocalToVworld(0));
2592:
2593: if (collisionBound == null) {
2594: ms.collisionBound = null;
2595: ms.collisionVwcBound = ms.vwcBounds;
2596: } else {
2597: ms.collisionBound = collisionBound;
2598: ms.collisionVwcBound = (Bounds) ms.collisionBound.clone();
2599: ms.collisionVwcBound.transform(ms
2600: .getCurrentLocalToVworld(0));
2601: }
2602: GeometryAtom gAtom = new GeometryAtom();
2603: for (gaCnt = 0; gaCnt < gSize; gaCnt++) {
2604: geometry = (GeometryRetained) geometryList.get(gaCnt);
2605: if (geometry != null) {
2606: gAtom.geoType = geometry.geoType;
2607: gAtom.alphaEditable = ms.isAlphaEditable(geometry);
2608: break;
2609: }
2610: }
2611: if ((geometry != null)
2612: && (geometry.geoType == GeometryRetained.GEO_TYPE_TEXT3D)) {
2613:
2614: for (gaCnt = 0; gaCnt < gSize; gaCnt++) {
2615: geometry = (GeometryRetained) geometryList.get(gaCnt);
2616: if (geometry != null) {
2617: Text3DRetained tempT3d = (Text3DRetained) geometry;
2618: geometryCnt += tempT3d.numChars;
2619: } else {
2620: // This is slightly wasteful, but not quite worth to optimize yet.
2621: geometryCnt++;
2622: }
2623: }
2624: gAtom.geometryArray = new GeometryRetained[geometryCnt];
2625: gAtom.lastLocalTransformArray = new Transform3D[geometryCnt];
2626: // Reset geometryCnt;
2627: geometryCnt = 0;
2628:
2629: } else {
2630: gAtom.geometryArray = new GeometryRetained[gSize];
2631: }
2632:
2633: for (gaCnt = 0; gaCnt < geometryList.size(); gaCnt++) {
2634: geometry = (GeometryRetained) geometryList.get(gaCnt);
2635: if (geometry == null) {
2636: gAtom.geometryArray[gaCnt] = null;
2637: } else {
2638: if (geometry.geoType == GeometryRetained.GEO_TYPE_TEXT3D) {
2639: Text3DRetained t = (Text3DRetained) geometry;
2640: GeometryRetained geo;
2641: for (i = 0; i < t.numChars; i++, geometryCnt++) {
2642: geo = t.geometryList[i];
2643: if (geo != null) {
2644: gAtom.geometryArray[geometryCnt] = geo;
2645: gAtom.lastLocalTransformArray[geometryCnt] = t.charTransforms[i];
2646: } else {
2647: gAtom.geometryArray[geometryCnt] = null;
2648: gAtom.lastLocalTransformArray[geometryCnt] = null;
2649: }
2650:
2651: }
2652:
2653: } else {
2654: gAtom.geometryArray[gaCnt] = geometry;
2655: }
2656: }
2657: }
2658: gAtom.locale = ms.locale;
2659: gAtom.visible = visible;
2660: gAtom.source = ms;
2661: ms.geomAtom = gAtom;
2662: }
2663:
2664: // Check if geomRetained's class is equivalence with the geometry class.
2665: void checkEquivalenceClass(Geometry geometry, int index) {
2666:
2667: if (geometry != null) {
2668: for (int i = geometryList.size() - 1; i >= 0; i--) {
2669: GeometryRetained geomRetained = (GeometryRetained) geometryList
2670: .get(i);
2671: if ((geomRetained != null) && (index != i)) { // this geometry will replace
2672: // current one so there is no need to check
2673: if (!geomRetained
2674: .isEquivalenceClass((GeometryRetained) geometry.retained)) {
2675: throw new IllegalArgumentException(J3dI18N
2676: .getString("Shape3DRetained5"));
2677: }
2678: break;
2679: }
2680: }
2681: }
2682: }
2683:
2684: int indexOfGeometry(Geometry geometry) {
2685: if (geometry != null)
2686: return geometryList.indexOf(geometry.retained);
2687: else
2688: return geometryList.indexOf(null);
2689: }
2690:
2691: // Removes the specified geometry from this Shape3DRetained's list of geometries
2692: void removeGeometry(Geometry geometry) {
2693: int ind = indexOfGeometry(geometry);
2694: if (ind >= 0)
2695: removeGeometry(ind);
2696: }
2697:
2698: // Removes all the geometries from this node
2699: void removeAllGeometries() {
2700: int n = geometryList.size();
2701:
2702: int i;
2703: Shape3DRetained mShape;
2704: GeometryRetained oldGeom = null;
2705:
2706: if (((Shape3D) this .source).isLive()) {
2707: for (int index = n - 1; index >= 0; index--) {
2708: oldGeom = (GeometryRetained) (geometryList.get(index));
2709: if (oldGeom != null) {
2710: oldGeom.clearLive(refCount);
2711: oldGeom.decRefCnt();
2712: for (i = 0; i < mirrorShape3D.size(); i++) {
2713: mShape = (Shape3DRetained) mirrorShape3D.get(i);
2714: oldGeom.removeUser(mShape);
2715: }
2716: }
2717: geometryList.remove(index);
2718: }
2719: sendDataChangedMessage(null);
2720: } else {
2721: for (int index = n - 1; index >= 0; index--) {
2722: oldGeom = (GeometryRetained) (geometryList.get(index));
2723: if (oldGeom != null) {
2724: oldGeom.decRefCnt();
2725: }
2726: geometryList.remove(index);
2727: }
2728: }
2729: dirtyBoundsCache();
2730: }
2731:
2732: boolean willRemainOpaque(int geoType) {
2733: if (appearance == null
2734: || (appearance.isStatic() && appearance
2735: .isOpaque(geoType))) {
2736: return true;
2737: } else {
2738: return false;
2739: }
2740:
2741: }
2742:
2743: void handleFrequencyChange(int bit) {
2744: int mask = 0;
2745: if (bit == Shape3D.ALLOW_GEOMETRY_WRITE) {
2746: mask = GEOMETRY_CHANGED;
2747: } else if (bit == Shape3D.ALLOW_APPEARANCE_WRITE) {
2748: mask = APPEARANCE_CHANGED;
2749: } else if (bit == Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE) {
2750: mask = APPEARANCEOVERRIDE_CHANGED;
2751: }
2752: if (mask != 0) {
2753: if (source.getCapabilityIsFrequent(bit))
2754: changedFrequent |= mask;
2755: else if (!source.isLive()) {
2756: changedFrequent &= ~mask;
2757: }
2758: }
2759: }
2760:
2761: // Alpha is editable due to the appearance(Called on the MirrorShape3D)
2762: boolean isAlphaFrequentlyEditable(GeometryRetained geo) {
2763:
2764: boolean alphaFrequentlyEditable = false;
2765: if (appearanceOverrideEnable) {
2766: alphaFrequentlyEditable = true;
2767: } else if (geo != null && appearance != null) {
2768: AppearanceRetained app = appearance;
2769:
2770: if (((changedFrequent & (APPEARANCE_CHANGED | APPEARANCEOVERRIDE_CHANGED)) != 0)
2771: || ((app.changedFrequent & (AppearanceRetained.RENDERING | AppearanceRetained.TRANSPARENCY)) != 0)
2772: || (app.renderingAttributes != null && (((app.renderingAttributes.changedFrequent & (RenderingAttributesRetained.IGNORE_VCOLOR | RenderingAttributesRetained.ALPHA_TEST_FUNC)) != 0)))
2773: ||
2774:
2775: (app.transparencyAttributes != null && ((app.transparencyAttributes.changedFrequent != 0)))) {
2776:
2777: alphaFrequentlyEditable = true;
2778:
2779: } else if (geo instanceof GeometryArrayRetained
2780: && ((app.changedFrequent & AppearanceRetained.TEXTURE_ATTR) != 0)
2781: || (app.textureAttributes != null && ((app.textureAttributes.changedFrequent & TextureAttributes.ALLOW_MODE_WRITE) != 0))) {
2782: alphaFrequentlyEditable = true;
2783:
2784: } else if (geo instanceof RasterRetained) {
2785: if (((((RasterRetained) geo).type & Raster.RASTER_COLOR) != 0)
2786: && (((RasterRetained) geo).cachedChangedFrequent != 0)) {
2787:
2788: alphaFrequentlyEditable = true;
2789: }
2790: }
2791: }
2792: // System.err.println("changedFrequent="+changedFrequent+" sourceNode = "+sourceNode+" isAlphaFrequentlyEditable, = "+alphaFrequentlyEditable);
2793: return alphaFrequentlyEditable;
2794: }
2795:
2796: int getPrimaryViewIdx() {
2797: // To avoid MT-safe issues when using View, just clone it.
2798: UnorderList viewList = VirtualUniverse.mc.cloneView();
2799: View views[] = (View[]) viewList.toArray(false);
2800: int size = viewList.arraySize();
2801:
2802: for (int i = 0; i < size; i++) {
2803: if (views[i].primaryView) {
2804: return views[i].viewIndex;
2805: }
2806: }
2807: return 0;
2808: }
2809:
2810: void searchGeometryAtoms(UnorderList list) {
2811: list.add(getGeomAtom(getMirrorShape(key)));
2812: }
2813: }
|