1 /* 2 * $RCSfile: Shape3DRetained.java,v $ 3 * 4 * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Sun designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Sun in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 24 * CA 95054 USA or visit www.sun.com if you need additional information or 25 * have any questions. 26 * 27 * $Revision: 1.12 $ 28 * $Date: 2008/02/28 20:17:30 $ 29 * $State: Exp $ 30 */ 31 32 package javax.media.j3d; 33 34 import javax.vecmath.*; 35 import java.util.ArrayList; 36 import java.util.Enumeration; 37 import java.util.Vector; 38 39 /** 40 * A shape leaf node consisting of geometry and appearance properties. 41 */ 42 43 class Shape3DRetained extends LeafRetained { 44 45 static final int GEOMETRY_CHANGED = 0x00001; 46 static final int APPEARANCE_CHANGED = 0x00002; 47 static final int COLLISION_CHANGED = 0x00004; 48 static final int BOUNDS_CHANGED = 0x00008; 49 static final int APPEARANCEOVERRIDE_CHANGED = 0x00010; 50 static final int LAST_DEFINED_BIT = 0x00010; 51 52 53 // Target threads to be notified when light changes 54 static final int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | 55 J3dThread.UPDATE_RENDER; 56 57 /** 58 * The appearance component of the shape node. 59 */ 60 AppearanceRetained appearance = null; 61 62 /** 63 * The arraylist of geometry component of the shape node. 64 */ 65 ArrayList geometryList = null; 66 67 /** 68 * A 2D storage of all geometry atoms associated with this shape node. 69 * There may be more than one geometry for a Shape3D node. 70 * Do not change the following private variables to public, its access need to synchronize 71 * via mirrorShape3DLock. 72 */ 73 74 // geomAtomArr should always be a 1 element array, unless S3D contains multiple Text3Ds. 75 private GeometryAtom geomAtom = null; 76 77 /** 78 * To sychronize access of the mirrorShape3D's geomAtomArray*. 79 * A multiple read single write Lock to sychronize access into mirrorShape3D. 80 * To prevent deadlock a call to read/write lock must end with a read/write unlock 81 * respectively. 82 */ 83 private MRSWLock mirrorShape3DLock = null; 84 85 /** 86 * The mirror Shape3DRetained nodes for this object. There is one 87 * mirror for each instance of this Shape3D node. If it is not in 88 * a SharedGroup, only index 0 is valid. 89 * Do not change the following private variables to public, its access need to synchronize 90 * via mirrorShape3DLock. 91 */ 92 ArrayList mirrorShape3D = new ArrayList(1); 93 94 /** 95 * This field is used for mirror Shape3D nodes accessing their 96 * original nodes. It is a NodeRetained because the original 97 * node may be a Shape3DRetained or a MorphRetained node. 98 */ 99 NodeRetained sourceNode = null; 100 101 /** 102 * The hashkey for this Shape3DRetained mirror object 103 */ 104 HashKey key = null; 105 106 // This is true when this geometry is referenced in an IMM mode context 107 boolean inImmCtx = false; 108 109 // A bitmask to indicate when something has changed 110 int isDirty = 0xffff; 111 112 // The list of lights that are scoped to this node 113 LightRetained[] lights =null; 114 115 // The number of lights in the above array, may be less than lights.length 116 int numlights = 0; 117 118 // The list of fogs that are scoped to this node 119 FogRetained[] fogs = null; 120 121 // The number of fogs in the above array, may be less than fogs.length 122 int numfogs = 0; 123 124 // The list of modelClips that are scoped to this node 125 ModelClipRetained[] modelClips = null; 126 127 // The number of modelClips in the above array, may be less than modelClips.length 128 int numModelClips = 0; 129 130 // The list of alt app that are scoped to this node 131 AlternateAppearanceRetained[] altApps = null; 132 133 //The number of alt app in the above array, may be less than alt app.length 134 int numAltApps = 0; 135 136 /** 137 * Reference to the BranchGroup path of this mirror shape 138 * This is used for picking and GeometryStructure only. 139 */ 140 BranchGroupRetained branchGroupPath[]; 141 142 // cache value for picking in mirror shape. 143 // True if all the node of the path from this to root are all pickable 144 boolean isPickable = true; 145 146 // cache value for collidable in mirror shape. 147 // True if all the node of the path from this to root are all collidable 148 boolean isCollidable = true; 149 150 // closest switch parent 151 SwitchRetained closestSwitchParent = null; 152 153 // the child index from the closest switch parent 154 int closestSwitchIndex = -1; 155 156 // Is this S3D visible ? The default is true. 157 boolean visible = true; 158 159 // Whether the normal appearance is overrided by the alternate app 160 boolean appearanceOverrideEnable = false; 161 162 // AlternateAppearance retained that is applicable to this 163 // mirror shape when the override flag is true 164 AppearanceRetained otherAppearance = null; 165 166 // geometry Bounds in local coordinate 167 Bounds bounds = null; 168 169 // geometry Bounds in virtual world coordinate 170 BoundingBox vwcBounds = null; 171 172 // collision Bounds in local coordinate 173 Bounds collisionBound = null; 174 175 // collision Bounds in virtual world coordinate 176 Bounds collisionVwcBound = null; 177 178 // a path of OrderedGroup, childrenId pairs which leads to this node 179 OrderedPath orderedPath = null; 180 181 // List of views that a mirror object is scoped to 182 ArrayList viewList = null; 183 184 int changedFrequent = 0; 185 Shape3DRetained()186 Shape3DRetained() { 187 super(); 188 this.nodeType = NodeRetained.SHAPE; 189 numlights = 0; 190 numfogs = 0; 191 numModelClips = 0; 192 numAltApps = 0; 193 localBounds = new BoundingBox((BoundingBox) null); 194 195 mirrorShape3DLock = new MRSWLock(); 196 geometryList = new ArrayList(1); 197 geometryList.add(null); 198 } 199 200 /** 201 * Sets the collision bounds of a node. 202 * @param bounds the bounding object for the node 203 */ setCollisionBounds(Bounds bounds)204 void setCollisionBounds(Bounds bounds) { 205 if (bounds == null) { 206 this.collisionBound = null; 207 } else { 208 this.collisionBound = (Bounds)bounds.clone(); 209 } 210 211 if (source.isLive()) { 212 // Notify Geometry Structure to check for collision 213 J3dMessage message = new J3dMessage(); 214 message.type = J3dMessage.COLLISION_BOUND_CHANGED; 215 message.threads = J3dThread.UPDATE_TRANSFORM; 216 message.universe = universe; 217 message.args[0] = getGeomAtomsArray(mirrorShape3D); 218 // no need to clone collisionBound 219 message.args[1] = collisionBound; 220 VirtualUniverse.mc.processMessage(message); 221 } 222 } 223 getLocalBounds(Bounds bounds)224 Bounds getLocalBounds(Bounds bounds) { 225 if(localBounds != null) { 226 localBounds.set(bounds); 227 } 228 else { 229 localBounds = new BoundingBox(bounds); 230 } 231 return localBounds; 232 } 233 234 235 /** 236 * Sets the geometric bounds of a node. 237 * @param bounds the bounding object for the node 238 */ setBounds(Bounds bounds)239 void setBounds(Bounds bounds) { 240 super.setBounds(bounds); 241 242 if (source.isLive() && !boundsAutoCompute) { 243 J3dMessage message = new J3dMessage(); 244 message.type = J3dMessage.REGION_BOUND_CHANGED; 245 message.threads = J3dThread.UPDATE_TRANSFORM | 246 J3dThread.UPDATE_GEOMETRY | 247 J3dThread.UPDATE_RENDER; 248 249 message.universe = universe; 250 message.args[0] = getGeomAtomsArray(mirrorShape3D); 251 // no need to clone localBounds 252 message.args[1] = localBounds; 253 VirtualUniverse.mc.processMessage(message); 254 } 255 } 256 257 /** 258 * Gets the collision bounds of a node. 259 * @return the node's bounding object 260 */ getCollisionBounds(int id)261 Bounds getCollisionBounds(int id) { 262 return (collisionBound == null ? 263 null: (Bounds)collisionBound.clone()); 264 } 265 266 /** 267 * Appends the specified geometry component to this Shape3D 268 * node's list of geometry components. 269 * If there are existing geometry components in the list, the new 270 * geometry component must be of the same equivalence class 271 * (point, line, polygon, CompressedGeometry, Raster, Text3D) as 272 * the others. 273 * @param geometry the geometry component to be appended. 274 * @exception IllegalArgumentException if the new geometry 275 * component is not of of the same equivalence class as the 276 * existing geometry components. 277 * 278 * @since Java 3D 1.2 279 */ addGeometry(Geometry geometry)280 void addGeometry(Geometry geometry) { 281 int i; 282 Shape3DRetained s; 283 GeometryRetained newGeom = null; 284 285 checkEquivalenceClass(geometry, -1); 286 287 if(((Shape3D)this.source).isLive()) { 288 if (geometry != null) { 289 290 newGeom = ((GeometryRetained)geometry.retained); 291 newGeom.setLive(inBackgroundGroup, refCount); 292 293 geometryList.add(newGeom); 294 295 } else { 296 geometryList.add(null); 297 newGeom = null; 298 } 299 sendDataChangedMessage(newGeom); 300 301 } else { 302 if (geometry != null) { 303 geometryList.add((GeometryRetained) geometry.retained); 304 } else { 305 geometryList.add(null); 306 } 307 } 308 dirtyBoundsCache(); 309 } 310 311 /** 312 * Replaces the geometry component at the specified index in this 313 * Shape3D node's list of geometry components with the specified 314 * geometry component. 315 * If there are existing geometry components in the list (besides 316 * the one being replaced), the new geometry component must be of 317 * the same equivalence class (point, line, polygon, CompressedGeometry, 318 * Raster, Text3D) as the others. 319 * @param geometry the geometry component to be stored at the 320 * specified index. 321 * @param index the index of the geometry component to be replaced. 322 * @exception IllegalArgumentException if the new geometry 323 * component is not of of the same equivalence class as the 324 * existing geometry components. 325 * 326 * @since Java 3D 1.2 327 */ setGeometry(Geometry geometry, int index)328 void setGeometry(Geometry geometry, int index) { 329 int i; 330 Shape3DRetained mShape; 331 GeometryRetained newGeom = null; 332 GeometryRetained oldGeom = null; 333 334 checkEquivalenceClass(geometry, index); 335 336 if (((Shape3D)this.source).isLive()) { 337 338 oldGeom = (GeometryRetained) (geometryList.get(index)); 339 if (oldGeom != null) { 340 oldGeom.clearLive(refCount); 341 for (i=0; i<mirrorShape3D.size(); i++) { 342 mShape = (Shape3DRetained)mirrorShape3D.get(i); 343 oldGeom.removeUser(mShape); 344 } 345 oldGeom.decRefCnt(); 346 } 347 348 if (geometry != null) { 349 newGeom = (GeometryRetained) geometry.retained; 350 newGeom.incRefCnt(); 351 newGeom.setLive(inBackgroundGroup, refCount); 352 geometryList.set(index, newGeom); 353 sendDataChangedMessage(newGeom); 354 } else { 355 geometryList.set(index, null); 356 sendDataChangedMessage(null); 357 } 358 359 } else { 360 361 oldGeom = (GeometryRetained) (geometryList.get(index)); 362 if (oldGeom != null) { 363 oldGeom.decRefCnt(); 364 } 365 if (geometry != null) { 366 geometryList.set(index,(GeometryRetained) geometry.retained); 367 ((GeometryRetained)geometry.retained).incRefCnt(); 368 } else { 369 geometryList.set(index,null); 370 } 371 } 372 dirtyBoundsCache(); 373 } 374 375 /** 376 * Inserts the specified geometry component into this Shape3D 377 * node's list of geometry components at the specified index. 378 * If there are existing geometry components in the list, the new 379 * geometry component must be of the same equivalence class 380 * (point, line, polygon, CompressedGeometry, Raster, Text3D) as 381 * the others. 382 * @param geometry the geometry component to be inserted at the 383 * specified index. 384 * @param index the index at which the geometry component is inserted. 385 * 386 * @since Java 3D 1.2 387 */ insertGeometry(Geometry geometry, int index)388 void insertGeometry(Geometry geometry, int index) { 389 int i; 390 Shape3DRetained mShape; 391 GeometryRetained newGeom = null; 392 GeometryRetained oldGeom = null; 393 394 checkEquivalenceClass(geometry, -1); 395 396 if (((Shape3D)this.source).isLive()) { 397 398 if (geometry != null) { 399 // Note : The order of the statements in important. Want ArrayList class to do index bounds 400 // check before creating internal object. 401 newGeom = (GeometryRetained) geometry.retained; 402 newGeom.incRefCnt(); 403 geometryList.add(index, newGeom); 404 newGeom.setLive(inBackgroundGroup, refCount); 405 sendDataChangedMessage(newGeom); 406 } else { 407 geometryList.add(index, null); 408 sendDataChangedMessage(null); 409 } 410 411 } else { 412 413 if (geometry != null) { 414 geometryList.add(index,(GeometryRetained) geometry.retained); 415 ((GeometryRetained)geometry.retained).incRefCnt(); 416 } else { 417 geometryList.add(index,null); 418 } 419 } 420 dirtyBoundsCache(); 421 } 422 423 /** 424 * Removes the geometry component at the specified index from 425 * this Shape3D node's list of geometry components. 426 * @param index the index of the geometry component to be removed. 427 * 428 * @since Java 3D 1.2 429 */ removeGeometry(int index)430 void removeGeometry(int index) { 431 int i; 432 Shape3DRetained mShape; 433 GeometryRetained oldGeom = null; 434 435 if (((Shape3D)this.source).isLive()) { 436 437 oldGeom = (GeometryRetained) (geometryList.get(index)); 438 if (oldGeom != null) { 439 oldGeom.clearLive(refCount); 440 oldGeom.decRefCnt(); 441 for (i=0; i<mirrorShape3D.size(); i++) { 442 mShape = (Shape3DRetained)mirrorShape3D.get(i); 443 oldGeom.removeUser(mShape); 444 445 } 446 } 447 448 geometryList.remove(index); 449 sendDataChangedMessage(null); 450 451 } else { 452 oldGeom = (GeometryRetained) (geometryList.get(index)); 453 if (oldGeom != null) { 454 oldGeom.decRefCnt(); 455 } 456 geometryList.remove(index); 457 } 458 459 dirtyBoundsCache(); 460 461 } 462 463 /** 464 * Retrieves the geometry component of this Shape3D node. 465 * @return the geometry component of this shape node 466 * 467 * @since Java 3D 1.2 468 */ getGeometry(int index, int id)469 Geometry getGeometry(int index, int id) { 470 GeometryRetained ga = (GeometryRetained) geometryList.get(index); 471 return (ga == null ? null : (Geometry)ga.source); 472 } 473 474 475 /** 476 * Returns an enumeration of this Shape3D node's list of geometry 477 * components. 478 * @return an Enumeration object containing all geometry components in 479 * this Shape3D node's list of geometry components. 480 * 481 * @since Java 3D 1.2 482 */ getAllGeometries(int id)483 Enumeration getAllGeometries(int id) { 484 GeometryRetained ga = null; 485 Vector geomList = new Vector(geometryList.size()); 486 487 for(int i=0; i<geometryList.size(); i++) { 488 ga = (GeometryRetained) geometryList.get(i); 489 if(ga != null) 490 geomList.add((Geometry)ga.source); 491 else 492 geomList.add(null); 493 } 494 495 return geomList.elements(); 496 } 497 498 /** 499 * Returns the number of geometry components in this Shape3D node's 500 * list of geometry components. 501 * @return the number of geometry components in this Shape3D node's 502 * list of geometry components. 503 * 504 * @since Java 3D 1.2 505 */ numGeometries(int id)506 int numGeometries(int id) { 507 508 return geometryList.size(); 509 } 510 511 /** 512 * Sets the appearance component of this Shape3D node. 513 * @param appearance the new apearance component for this shape node 514 */ setAppearance(Appearance newAppearance)515 void setAppearance(Appearance newAppearance) { 516 517 Shape3DRetained s; 518 boolean visibleIsDirty = false; 519 520 if (((Shape3D)this.source).isLive()) { 521 if (appearance != null) { 522 appearance.clearLive(refCount); 523 for (int i=0; i<mirrorShape3D.size(); i++) { 524 s = (Shape3DRetained)mirrorShape3D.get(i); 525 appearance.removeAMirrorUser(s); 526 } 527 } 528 529 if (newAppearance != null) { 530 ((AppearanceRetained)newAppearance.retained).setLive(inBackgroundGroup, refCount); 531 appearance = ((AppearanceRetained)newAppearance.retained); 532 for (int i=0; i<mirrorShape3D.size(); i++) { 533 s = (Shape3DRetained)mirrorShape3D.get(i); 534 appearance.addAMirrorUser(s); 535 } 536 if((appearance.renderingAttributes != null) && 537 (visible != appearance.renderingAttributes.visible)) { 538 visible = appearance.renderingAttributes.visible; 539 visibleIsDirty = true; 540 } 541 } 542 else { 543 if(visible == false) { 544 visible = true; 545 visibleIsDirty = true; 546 } 547 } 548 int size = 0; 549 if (visibleIsDirty) 550 size = 2; 551 else 552 size = 1; 553 J3dMessage[] createMessage = new J3dMessage[size]; 554 // Send a message 555 createMessage[0] = new J3dMessage(); 556 createMessage[0].threads = targetThreads; 557 createMessage[0].type = J3dMessage.SHAPE3D_CHANGED; 558 createMessage[0].universe = universe; 559 createMessage[0].args[0] = this; 560 createMessage[0].args[1]= new Integer(APPEARANCE_CHANGED); 561 Shape3DRetained[] s3dArr = new Shape3DRetained[mirrorShape3D.size()]; 562 mirrorShape3D.toArray(s3dArr); 563 createMessage[0].args[2] = s3dArr; 564 Object[] obj = new Object[2]; 565 if (newAppearance == null) { 566 obj[0] = null; 567 } 568 else { 569 obj[0] = appearance.mirror; 570 } 571 obj[1] = new Integer(changedFrequent); 572 createMessage[0].args[3] = obj; 573 createMessage[0].args[4] = getGeomAtomsArray(mirrorShape3D); 574 if(visibleIsDirty) { 575 createMessage[1] = new J3dMessage(); 576 createMessage[1].threads = J3dThread.UPDATE_GEOMETRY; 577 createMessage[1].type = J3dMessage.SHAPE3D_CHANGED; 578 createMessage[1].universe = universe; 579 createMessage[1].args[0] = this; 580 createMessage[1].args[1]= new Integer(APPEARANCE_CHANGED); 581 createMessage[1].args[2]= visible?Boolean.TRUE:Boolean.FALSE; 582 createMessage[1].args[3]= createMessage[0].args[4]; 583 } 584 VirtualUniverse.mc.processMessage(createMessage); 585 586 } 587 else { // not live. 588 if (newAppearance == null) { 589 appearance = null; 590 } else { 591 appearance = (AppearanceRetained) newAppearance.retained; 592 } 593 } 594 } 595 596 /** 597 * Retrieves the shape node's appearance component. 598 * @return the shape node's appearance 599 */ getAppearance()600 Appearance getAppearance() { 601 return (appearance == null ? null: (Appearance) appearance.source); 602 } 603 setAppearanceOverrideEnable(boolean flag)604 void setAppearanceOverrideEnable(boolean flag) { 605 if (((Shape3D)this.source).isLive()) { 606 607 // Send a message 608 J3dMessage createMessage = new J3dMessage(); 609 createMessage.threads = targetThreads; 610 createMessage.type = J3dMessage.SHAPE3D_CHANGED; 611 createMessage.universe = universe; 612 createMessage.args[0] = this; 613 createMessage.args[1]= new Integer(APPEARANCEOVERRIDE_CHANGED); 614 Shape3DRetained[] s3dArr = new Shape3DRetained[mirrorShape3D.size()]; 615 mirrorShape3D.toArray(s3dArr); 616 createMessage.args[2] = s3dArr; 617 Object[] obj = new Object[2]; 618 if (flag) { 619 obj[0] = Boolean.TRUE; 620 } 621 else { 622 obj[0] = Boolean.FALSE; 623 } 624 obj[1] = new Integer(changedFrequent); 625 createMessage.args[3] = obj; 626 createMessage.args[4] = getGeomAtomsArray(mirrorShape3D); 627 628 VirtualUniverse.mc.processMessage(createMessage); 629 } 630 appearanceOverrideEnable = flag; 631 } 632 getAppearanceOverrideEnable()633 boolean getAppearanceOverrideEnable() { 634 return appearanceOverrideEnable; 635 } 636 intersect(PickInfo pickInfo, PickShape pickShape, int flags )637 boolean intersect(PickInfo pickInfo, PickShape pickShape, int flags ) { 638 639 Transform3D localToVworld = pickInfo.getLocalToVWorldRef(); 640 641 // Support OrientedShape3D here. 642 // Note - BugId : 4363899 - APIs issue : OrientedShape3D's intersect needs view 643 // info. temp. fix use the primary view. 644 if (this instanceof OrientedShape3DRetained) { 645 Transform3D orientedTransform = ((OrientedShape3DRetained)this). 646 getOrientedTransform(getPrimaryViewIdx()); 647 localToVworld.mul(orientedTransform); 648 } 649 650 Transform3D t3d = new Transform3D(); 651 t3d.invert(localToVworld); 652 PickShape newPS = pickShape.transform(t3d); 653 654 // Note: For optimization - Should do a geobounds check of 655 // each geometry first. But this doesn't work for 656 // OrientedShape3D case... 657 int geomListSize = geometryList.size(); 658 GeometryRetained geometry; 659 660 if (((flags & PickInfo.CLOSEST_INTERSECTION_POINT) == 0) && 661 ((flags & PickInfo.CLOSEST_DISTANCE) == 0) && 662 ((flags & PickInfo.CLOSEST_GEOM_INFO) == 0) && 663 ((flags & PickInfo.ALL_GEOM_INFO) == 0)) { 664 665 for (int i=0; i < geomListSize; i++) { 666 geometry = (GeometryRetained) geometryList.get(i); 667 if (geometry != null) { 668 if (geometry.mirrorGeometry != null) { 669 geometry = geometry.mirrorGeometry; 670 } 671 if (geometry.intersect(newPS, null, 0, null, null, 0)) { 672 return true; 673 } 674 } 675 } 676 } else { 677 double distance; 678 double minDist = Double.POSITIVE_INFINITY; 679 Point3d closestIPnt = new Point3d(); 680 Point3d iPnt = new Point3d(); 681 Point3d iPntVW = new Point3d(); 682 683 for (int i=0; i < geomListSize; i++) { 684 geometry = (GeometryRetained) geometryList.get(i); 685 if (geometry != null) { 686 if (geometry.mirrorGeometry != null) { 687 geometry = geometry.mirrorGeometry; 688 } 689 //if (geometry.intersect(newPS, intersectionInfo, flags, iPnt)) { 690 if(geometry.intersect(newPS, pickInfo, flags, iPnt, geometry, i)) { 691 692 iPntVW.set(iPnt); 693 localToVworld.transform(iPntVW); 694 distance = pickShape.distance(iPntVW); 695 696 if (minDist > distance) { 697 minDist = distance; 698 closestIPnt.set(iPnt); 699 } 700 } 701 } 702 } 703 704 if (minDist < Double.POSITIVE_INFINITY) { 705 if ((flags & PickInfo.CLOSEST_DISTANCE) != 0) { 706 pickInfo.setClosestDistance(minDist); 707 } 708 if((flags & PickInfo.CLOSEST_INTERSECTION_POINT) != 0) { 709 pickInfo.setClosestIntersectionPoint(closestIPnt); 710 } 711 return true; 712 } 713 } 714 715 return false; 716 717 } 718 719 720 /** 721 * Check if the geometry component of this shape node under path 722 * intersects with the pickShape. 723 * This is an expensive method. It should only be called if and only 724 * if the path's bound intersects pickShape. 725 * @exception IllegalArgumentException if <code>path</code> is 726 * invalid. 727 */ 728 intersect(SceneGraphPath path, PickShape pickShape, double[] dist)729 boolean intersect(SceneGraphPath path, 730 PickShape pickShape, double[] dist) { 731 732 int flags; 733 PickInfo pickInfo = new PickInfo(); 734 735 Transform3D localToVworld = path.getTransform(); 736 if (localToVworld == null) { 737 throw new IllegalArgumentException(J3dI18N.getString("Shape3DRetained3")); 738 } 739 pickInfo.setLocalToVWorldRef( localToVworld); 740 //System.err.println("Shape3DRetained.intersect() : "); 741 if (dist == null) { 742 //System.err.println(" no dist request ...."); 743 return intersect(pickInfo, pickShape, 0); 744 } 745 746 flags = PickInfo.CLOSEST_DISTANCE; 747 if (intersect(pickInfo, pickShape, flags)) { 748 dist[0] = pickInfo.getClosestDistance(); 749 return true; 750 } 751 752 return false; 753 754 } 755 756 /** 757 * This sets the immedate mode context flag 758 */ setInImmCtx(boolean inCtx)759 void setInImmCtx(boolean inCtx) { 760 inImmCtx = inCtx; 761 } 762 763 /** 764 * This gets the immedate mode context flag 765 */ getInImmCtx()766 boolean getInImmCtx() { 767 return (inImmCtx); 768 } 769 770 /** 771 * This updates the mirror shape to reflect the state of the 772 * real shape3d. 773 */ initMirrorShape3D(SetLiveState s, Shape3DRetained ms, int index)774 private void initMirrorShape3D(SetLiveState s, Shape3DRetained ms, int index) { 775 776 // New 1.2.1 code 777 778 ms.inBackgroundGroup = inBackgroundGroup; 779 ms.geometryBackground = geometryBackground; 780 ms.source = source; 781 ms.universe = universe; 782 // Has to be false. We have a instance of mirror for every link to the shape3d. 783 ms.inSharedGroup = false; 784 ms.locale = locale; 785 ms.parent = parent; 786 787 // New 1.3.2 788 // Used when user supplied their own bounds for transparency sorting 789 // GeometryAtom uses this to change how it computes the centroid 790 ms.boundsAutoCompute = boundsAutoCompute; 791 ms.localBounds = localBounds; 792 // End new 1.3.2 793 794 OrderedPath op = (OrderedPath)s.orderedPaths.get(index); 795 if (op.pathElements.size() == 0) { 796 ms.orderedPath = null; 797 } else { 798 ms.orderedPath = op; 799 /* 800 System.err.println("initMirrorShape3D ms.orderedPath "); 801 ms.orderedPath.printPath(); 802 */ 803 } 804 805 // all mirror shapes point to the same transformGroupRetained 806 // for the static transform 807 ms.staticTransform = staticTransform; 808 809 810 ms.appearanceOverrideEnable = appearanceOverrideEnable; 811 812 ms.geometryList = geometryList; 813 814 // Assign the parent of this mirror shape node 815 ms.sourceNode = this; 816 817 if (this instanceof OrientedShape3DRetained) { 818 OrientedShape3DRetained os = (OrientedShape3DRetained)this; 819 OrientedShape3DRetained oms = (OrientedShape3DRetained)ms; 820 oms.initAlignmentMode(os.mode); 821 oms.initAlignmentAxis(os.axis); 822 oms.initRotationPoint(os.rotationPoint); 823 oms.initConstantScaleEnable(os.constantScale); 824 oms.initScale(os.scaleFactor); 825 } 826 827 } 828 updateImmediateMirrorObject(Object[] objs)829 void updateImmediateMirrorObject(Object[] objs) { 830 int component = ((Integer)objs[1]).intValue(); 831 GeometryArrayRetained ga; 832 833 Shape3DRetained[] msArr = (Shape3DRetained[]) objs[2]; 834 int i, j; 835 if ((component & APPEARANCE_CHANGED) != 0) { 836 Object[] arg = (Object[])objs[3]; 837 int val = ((Integer)arg[1]).intValue(); 838 for ( i = msArr.length-1; i >=0; i--) { 839 msArr[i].appearance = (AppearanceRetained)arg[0]; 840 msArr[i].changedFrequent = val; 841 } 842 } 843 if ((component & APPEARANCEOVERRIDE_CHANGED) != 0) { 844 Object[] arg = (Object[])objs[3]; 845 int val = ((Integer)arg[1]).intValue(); 846 for ( i = msArr.length-1; i >=0; i--) { 847 msArr[i].appearanceOverrideEnable = ((Boolean)arg[0]).booleanValue(); 848 msArr[i].changedFrequent = val; 849 } 850 } 851 } 852 853 /** 854 * Gets the bounding object of a node. 855 * @return the node's bounding object 856 */ 857 getBounds()858 Bounds getBounds() { 859 860 if(boundsAutoCompute) { 861 // System.err.println("getBounds ---- localBounds is " + localBounds); 862 // Issue 514 : NPE in Wonderland : triggered in cached bounds computation 863 if (validCachedBounds) { 864 return (Bounds) cachedBounds.clone(); 865 } 866 867 if(geometryList != null) { 868 BoundingBox bbox = new BoundingBox((Bounds) null); 869 GeometryRetained geometry; 870 for(int i=0; i<geometryList.size(); i++) { 871 geometry = (GeometryRetained) geometryList.get(i); 872 if ((geometry != null) && 873 (geometry.geoType != GeometryRetained.GEO_TYPE_NONE)) { 874 geometry.computeBoundingBox(); 875 synchronized(geometry.geoBounds) { 876 bbox.combine(geometry.geoBounds); 877 } 878 } 879 } 880 return (Bounds) bbox; 881 882 } else { 883 return null; 884 } 885 886 } else { 887 return super.getBounds(); 888 } 889 } 890 getEffectiveBounds()891 Bounds getEffectiveBounds() { 892 if(boundsAutoCompute) { 893 return getBounds(); 894 } 895 else { 896 return super.getEffectiveBounds(); 897 } 898 } 899 900 901 /** 902 * ONLY needed for SHAPE, MORPH, and LINK node type. 903 * Compute the combine bounds of bounds and its localBounds. 904 */ computeCombineBounds(Bounds bounds)905 void computeCombineBounds(Bounds bounds) { 906 907 if(boundsAutoCompute) { 908 if(geometryList != null) { 909 GeometryRetained geometry; 910 BoundingBox bbox = null; 911 912 if (staticTransform != null) { 913 bbox = new BoundingBox((BoundingBox) null); 914 } 915 916 if (!VirtualUniverse.mc.cacheAutoComputedBounds) { 917 for(int i=0; i<geometryList.size(); i++) { 918 geometry = (GeometryRetained) geometryList.get(i); 919 if ((geometry != null) && 920 (geometry.geoType != GeometryRetained.GEO_TYPE_NONE)) { 921 geometry.computeBoundingBox(); 922 // Should this be lock too ? ( MT safe ? ) 923 synchronized(geometry.geoBounds) { 924 if (staticTransform != null) { 925 bbox.set(geometry.geoBounds); 926 bbox.transform(staticTransform.transform); 927 bounds.combine((Bounds)bbox); 928 } else { 929 bounds.combine((Bounds)geometry.geoBounds); 930 } 931 } 932 } 933 } 934 } else { 935 // Issue 514 : NPE in Wonderland : triggered in cached bounds computation 936 if (!validCachedBounds) { 937 validCachedBounds = true; 938 cachedBounds = new BoundingBox((BoundingBox) null); 939 940 for(int i=0; i<geometryList.size(); i++) { 941 geometry = (GeometryRetained) geometryList.get(i); 942 if ((geometry != null) && 943 (geometry.geoType != GeometryRetained.GEO_TYPE_NONE)) { 944 geometry.computeBoundingBox(); 945 // Should this be lock too ? ( MT safe ? ) 946 synchronized(geometry.geoBounds) { 947 if (staticTransform != null) { 948 bbox.set(geometry.geoBounds); 949 bbox.transform(staticTransform.transform); 950 cachedBounds.combine((Bounds)bbox); 951 } else { 952 cachedBounds.combine((Bounds)geometry.geoBounds); 953 } 954 } 955 } 956 } 957 } 958 bounds.combine(cachedBounds); 959 } 960 } 961 } else { 962 963 // Should this be lock too ? ( MT safe ? ) 964 synchronized(localBounds) { 965 bounds.combine((Bounds) localBounds); 966 } 967 } 968 } 969 970 /** 971 * assign a name to this node when it is made live. 972 */ 973 setLive(SetLiveState s)974 void setLive(SetLiveState s) { 975 doSetLive(s); 976 markAsLive(); 977 } 978 doSetLive(SetLiveState s)979 void doSetLive(SetLiveState s) { 980 // System.err.println("S3DRetained : setLive " + s); 981 Shape3DRetained shape; 982 GeometryRetained geometry; 983 int i, j, k, gaCnt; 984 ArrayList msList = new ArrayList(); 985 986 super.doSetLive(s); 987 988 nodeId = universe.getNodeId(); 989 990 991 if (inSharedGroup) { 992 for (i=0; i<s.keys.length; i++) { 993 if (this instanceof OrientedShape3DRetained) { 994 shape = new OrientedShape3DRetained(); 995 } else { 996 shape = new Shape3DRetained(); 997 } 998 shape.key = s.keys[i]; 999 shape.localToVworld = new Transform3D[1][]; 1000 shape.localToVworldIndex = new int[1][]; 1001 1002 j = s.keys[i].equals(localToVworldKeys, 0, 1003 localToVworldKeys.length); 1004 /* 1005 System.err.print("s.keys[i] = "+s.keys[i]+" j = "+j); 1006 if(j < 0) { 1007 System.err.println("Shape3dRetained : Can't find hashKey"); 1008 } 1009 */ 1010 shape.localToVworld[0] = localToVworld[j]; 1011 shape.localToVworldIndex[0] = localToVworldIndex[j]; 1012 shape.branchGroupPath = (BranchGroupRetained []) branchGroupPaths.get(j); 1013 shape.isPickable = s.pickable[i]; 1014 shape.isCollidable = s.collidable[i]; 1015 1016 initMirrorShape3D(s, shape, j); 1017 1018 if (s.switchTargets != null && 1019 s.switchTargets[i] != null) { 1020 s.switchTargets[i].addNode(shape, Targets.GEO_TARGETS); 1021 shape.closestSwitchParent = s.closestSwitchParents[i]; 1022 shape.closestSwitchIndex = s.closestSwitchIndices[i]; 1023 } 1024 shape.switchState = (SwitchState)s.switchStates.get(j); 1025 1026 1027 // Add any scoped lights to the mirror shape 1028 if (s.lights != null) { 1029 ArrayList l = (ArrayList)s.lights.get(j); 1030 if (l != null) { 1031 for (int m = 0; m < l.size(); m++) { 1032 shape.addLight((LightRetained)l.get(m)); 1033 } 1034 } 1035 } 1036 1037 // Add any scoped fog 1038 if (s.fogs != null) { 1039 ArrayList l = (ArrayList)s.fogs.get(j); 1040 if (l != null) { 1041 for (int m = 0; m < l.size(); m++) { 1042 shape.addFog((FogRetained)l.get(m)); 1043 } 1044 } 1045 } 1046 1047 // Add any scoped modelClip 1048 if (s.modelClips != null) { 1049 ArrayList l = (ArrayList)s.modelClips.get(j); 1050 if (l != null) { 1051 for (int m = 0; m < l.size(); m++) { 1052 shape.addModelClip((ModelClipRetained)l.get(m)); 1053 } 1054 } 1055 } 1056 1057 // Add any scoped alt app 1058 if (s.altAppearances != null) { 1059 ArrayList l = (ArrayList)s.altAppearances.get(j); 1060 if (l != null) { 1061 for (int m = 0; m < l.size(); m++) { 1062 shape.addAltApp((AlternateAppearanceRetained)l.get(m)); 1063 } 1064 } 1065 } 1066 synchronized(mirrorShape3D) { 1067 mirrorShape3D.add(j,shape); 1068 } 1069 1070 msList.add(shape); 1071 if (s.viewLists != null) { 1072 shape.viewList = (ArrayList)s.viewLists.get(j); 1073 } else { 1074 shape.viewList = null; 1075 } 1076 } 1077 } else { 1078 if (this instanceof OrientedShape3DRetained) { 1079 shape = new OrientedShape3DRetained(); 1080 } else { 1081 shape = new Shape3DRetained(); 1082 } 1083 1084 shape.localToVworld = new Transform3D[1][]; 1085 shape.localToVworldIndex = new int[1][]; 1086 shape.localToVworld[0] = localToVworld[0]; 1087 shape.localToVworldIndex[0] = localToVworldIndex[0]; 1088 shape.branchGroupPath = (BranchGroupRetained []) branchGroupPaths.get(0); 1089 shape.isPickable = s.pickable[0]; 1090 shape.isCollidable = s.collidable[0]; 1091 initMirrorShape3D(s, shape, 0); 1092 1093 // Add any scoped lights to the mirror shape 1094 if (s.lights != null) { 1095 ArrayList l = (ArrayList)s.lights.get(0); 1096 for (i = 0; i < l.size(); i++) { 1097 shape.addLight((LightRetained)l.get(i)); 1098 } 1099 } 1100 1101 // Add any scoped fog 1102 if (s.fogs != null) { 1103 ArrayList l = (ArrayList)s.fogs.get(0); 1104 for (i = 0; i < l.size(); i++) { 1105 shape.addFog((FogRetained)l.get(i)); 1106 } 1107 } 1108 1109 // Add any scoped modelClip 1110 if (s.modelClips != null) { 1111 ArrayList l = (ArrayList)s.modelClips.get(0); 1112 for (i = 0; i < l.size(); i++) { 1113 shape.addModelClip((ModelClipRetained)l.get(i)); 1114 } 1115 1116 } 1117 1118 // Add any scoped alt app 1119 if (s.altAppearances != null) { 1120 ArrayList l = (ArrayList)s.altAppearances.get(0); 1121 for (i = 0; i < l.size(); i++) { 1122 shape.addAltApp((AlternateAppearanceRetained)l.get(i)); 1123 } 1124 } 1125 synchronized(mirrorShape3D) { 1126 mirrorShape3D.add(shape); 1127 } 1128 1129 msList.add(shape); 1130 if (s.viewLists != null) 1131 shape.viewList = (ArrayList)s.viewLists.get(0); 1132 else 1133 shape.viewList = null; 1134 1135 if (s.switchTargets != null && 1136 s.switchTargets[0] != null) { 1137 s.switchTargets[0].addNode(shape, Targets.GEO_TARGETS); 1138 shape.closestSwitchParent = s.closestSwitchParents[0]; 1139 shape.closestSwitchIndex = s.closestSwitchIndices[0]; 1140 } 1141 shape.switchState = (SwitchState)s.switchStates.get(0); 1142 } 1143 1144 for (k = 0; k < msList.size(); k++) { 1145 Shape3DRetained sh = (Shape3DRetained)msList.get(k); 1146 1147 if (appearance != null) { 1148 synchronized(appearance.liveStateLock) { 1149 if (k == 0) { // Do only first time 1150 appearance.setLive(inBackgroundGroup, s.refCount); 1151 appearance.initMirrorObject(); 1152 if (appearance.renderingAttributes != null) 1153 visible = appearance.renderingAttributes.visible; 1154 } 1155 sh.appearance = (AppearanceRetained)appearance.mirror; 1156 appearance.addAMirrorUser(sh); 1157 1158 } 1159 } 1160 else { 1161 sh.appearance = null; 1162 } 1163 1164 if (geometryList != null) { 1165 for(gaCnt=0; gaCnt<geometryList.size(); gaCnt++) { 1166 geometry = (GeometryRetained) geometryList.get(gaCnt); 1167 if(geometry != null) { 1168 synchronized(geometry.liveStateLock) { 1169 if (k == 0) { // Do only first time 1170 geometry.setLive(inBackgroundGroup, s.refCount); 1171 } 1172 geometry.addUser(sh); 1173 } 1174 } 1175 } 1176 1177 } 1178 1179 // after the geometry has been setLived and bounds computed 1180 if (k== 0 && boundsAutoCompute) { // Do only once 1181 // user may call setBounds with a bounds other than boundingBox 1182 if (! (localBounds instanceof BoundingBox)) { 1183 localBounds = new BoundingBox((BoundingBox) null); 1184 } 1185 getCombineBounds((BoundingBox)localBounds); 1186 1187 } 1188 // Assign GAtom and set the bounds if we are not using switch 1189 initializeGAtom(sh); 1190 1191 GeometryAtom ga = getGeomAtom(sh); 1192 1193 // Add the geometry atom for this shape to the nodeList 1194 s.nodeList.add(ga); 1195 1196 if (s.transformTargets != null && 1197 s.transformTargets[k] != null) { 1198 // Add the geometry atom for this shape to the transformTargets 1199 1200 s.transformTargets[k].addNode(ga, Targets.GEO_TARGETS); 1201 } 1202 } 1203 1204 s.notifyThreads |= (J3dThread.UPDATE_GEOMETRY | 1205 J3dThread.UPDATE_TRANSFORM | 1206 J3dThread.UPDATE_RENDER | 1207 J3dThread.UPDATE_RENDERING_ENVIRONMENT); 1208 1209 } 1210 1211 /** 1212 * This clears all references in a mirror shape 1213 */ 1214 // This is call in RenderingEnvironmentStructure.removeNode() because that is the 1215 // last point that will reference this ms. 1216 // called on the mirror shape .. clearMirrorShape()1217 void clearMirrorShape() { 1218 int i; 1219 1220 source = null; 1221 sourceNode = null; 1222 parent = null; 1223 1224 if (otherAppearance != null) { 1225 otherAppearance.sgApp.removeAMirrorUser(this); 1226 otherAppearance = null; 1227 } 1228 1229 appearance = null; 1230 1231 branchGroupPath = null; 1232 isPickable = true; 1233 isCollidable = true; 1234 branchGroupPath = null; 1235 // No locking needed. Owner, s3dR, has already been destory. 1236 // DO NOT clear geometryList, ie. geometryList.clear(). 1237 // It is referred by the source s3DRetained. 1238 geometryList = null; 1239 1240 // Clear the mirror scoping info 1241 // Remove all the fogs 1242 for (i = 0; i < numfogs; i++) 1243 fogs[i] = null; 1244 numfogs = 0; 1245 1246 // Remove all the modelClips 1247 for (i = 0; i < numModelClips; i++) 1248 modelClips[i] = null; 1249 numModelClips = 0; 1250 1251 // Remove all the lights 1252 for (i = 0; i < numlights; i++) 1253 lights[i] = null; 1254 numlights = 0; 1255 1256 // Remove all the al app 1257 for (i = 0; i < numAltApps; i++) 1258 altApps[i] = null; 1259 numAltApps = 0; 1260 1261 viewList = null; 1262 1263 } 1264 1265 /** 1266 * assign a name to this node when it is made live. 1267 */ clearLive(SetLiveState s)1268 void clearLive(SetLiveState s) { 1269 1270 //System.err.println("S3DRetained : clearLive " + s); 1271 1272 int i, j, gaCnt; 1273 Shape3DRetained shape; 1274 GeometryRetained geometry; 1275 Object[] shapes; 1276 ArrayList msList = new ArrayList(); 1277 1278 super.clearLive(s); 1279 1280 1281 1282 if (inSharedGroup) { 1283 synchronized(mirrorShape3D) { 1284 shapes = mirrorShape3D.toArray(); 1285 for (i=0; i<s.keys.length; i++) { 1286 for (j=0; j<shapes.length; j++) { 1287 shape = (Shape3DRetained)shapes[j]; 1288 if (shape.key.equals(s.keys[i])) { 1289 mirrorShape3D.remove(mirrorShape3D.indexOf(shape)); 1290 if (s.switchTargets != null && 1291 s.switchTargets[i] != null) { 1292 s.switchTargets[i].addNode( 1293 shape, Targets.GEO_TARGETS); 1294 } 1295 msList.add(shape); 1296 GeometryAtom ga = getGeomAtom(shape); 1297 1298 // Add the geometry atom for this shape to the nodeList 1299 s.nodeList.add(ga); 1300 if (s.transformTargets != null && 1301 s.transformTargets[i] != null) { 1302 s.transformTargets[i].addNode(ga, Targets.GEO_TARGETS); 1303 } 1304 } 1305 } 1306 } 1307 } 1308 } else { 1309 // Only entry 0 is valid 1310 shape = (Shape3DRetained)mirrorShape3D.get(0); 1311 synchronized(mirrorShape3D) { 1312 mirrorShape3D.remove(0); 1313 } 1314 1315 if (s.switchTargets != null && 1316 s.switchTargets[0] != null) { 1317 s.switchTargets[0].addNode(shape, Targets.GEO_TARGETS); 1318 } 1319 1320 1321 msList.add(shape); 1322 1323 GeometryAtom ga = getGeomAtom(shape); 1324 1325 // Add the geometry atom for this shape to the nodeList 1326 s.nodeList.add(ga); 1327 if (s.transformTargets != null && 1328 s.transformTargets[0] != null) { 1329 s.transformTargets[0].addNode(ga, Targets.GEO_TARGETS); 1330 } 1331 } 1332 1333 1334 for (int k = 0; k < msList.size(); k++) { 1335 Shape3DRetained sh = (Shape3DRetained)msList.get(k); 1336 if (appearance != null) { 1337 synchronized(appearance.liveStateLock) { 1338 if (k == 0) { 1339 appearance.clearLive(s.refCount); 1340 } 1341 appearance.removeAMirrorUser(sh); 1342 } 1343 } 1344 if (geometryList != null) { 1345 for(gaCnt=0; gaCnt<geometryList.size(); gaCnt++) { 1346 geometry = (GeometryRetained) geometryList.get(gaCnt); 1347 if(geometry != null) { 1348 synchronized(geometry.liveStateLock) { 1349 if (k == 0) { 1350 geometry.clearLive(s.refCount); 1351 } 1352 geometry.removeUser(sh); 1353 } 1354 } 1355 } 1356 } 1357 } 1358 1359 s.notifyThreads |= (J3dThread.UPDATE_GEOMETRY | 1360 J3dThread.UPDATE_TRANSFORM | 1361 // This is used to clear the scope info 1362 // of all the mirror shapes 1363 J3dThread.UPDATE_RENDERING_ENVIRONMENT | 1364 J3dThread.UPDATE_RENDER); 1365 1366 if (!source.isLive()) { 1367 // Clear the mirror scoping info 1368 // Remove all the fogs 1369 for (i = 0; i < numfogs; i++) 1370 fogs[i] = null; 1371 numfogs = 0; 1372 1373 // Remove all the modelClips 1374 for (i = 0; i < numModelClips; i++) 1375 modelClips[i] = null; 1376 numModelClips = 0; 1377 1378 // Remove all the lights 1379 for (i = 0; i < numlights; i++) 1380 lights[i] = null; 1381 numlights = 0; 1382 1383 // Remove all the al app 1384 for (i = 0; i < numAltApps; i++) 1385 altApps[i] = null; 1386 numAltApps = 0; 1387 } 1388 } 1389 isStatic()1390 boolean isStatic() { 1391 if (source.getCapability(Shape3D.ALLOW_APPEARANCE_WRITE) || 1392 source.getCapability(Shape3D.ALLOW_GEOMETRY_WRITE) || 1393 source.getCapability(Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE)) { 1394 return false; 1395 } else { 1396 return true; 1397 } 1398 } 1399 staticXformCanBeApplied()1400 boolean staticXformCanBeApplied() { 1401 1402 // static xform can be applied if 1403 // . shape is not pickable or collidable 1404 // . geometry is not being shared by more than one shape nodes 1405 // . geometry will be put in display list 1406 // . geometry is not readable 1407 1408 // no static xform if shape is pickable or collidable because 1409 // otherwise the static xform will have to be applied to the 1410 // currentLocalToVworld in the intersect test, it will then 1411 // be more costly and really beat the purpose of eliminating 1412 // the static transform group 1413 if (isPickable || isCollidable || 1414 source.getCapability(Shape3D.ALLOW_PICKABLE_WRITE) || 1415 source.getCapability(Shape3D.ALLOW_COLLIDABLE_WRITE)) { 1416 return false; 1417 } 1418 1419 if (appearance != null && 1420 (appearance.transparencyAttributes != null && appearance.transparencyAttributes.transparencyMode != TransparencyAttributes.NONE)) 1421 return false; 1422 1423 GeometryRetained geo; 1424 boolean alphaEditable; 1425 1426 for (int i=0; i<geometryList.size(); i++) { 1427 geo = (GeometryRetained) geometryList.get(i); 1428 if (geo != null) { 1429 if (geo.refCnt > 1) { 1430 return false; 1431 } 1432 alphaEditable = isAlphaEditable(geo); 1433 if (geo instanceof GeometryArrayRetained) { 1434 geo.isEditable = !((GeometryArrayRetained)geo).isWriteStatic(); 1435 1436 // TODO: for now if vertex data can be returned, then 1437 // don't apply static transform 1438 if (geo.source.getCapability( 1439 GeometryArray.ALLOW_COORDINATE_READ) || 1440 geo.source.getCapability( 1441 GeometryArray.ALLOW_NORMAL_READ)) 1442 return false; 1443 1444 } 1445 1446 if (!geo.canBeInDisplayList(alphaEditable)) { 1447 return false; 1448 } 1449 } 1450 } 1451 return true; 1452 } 1453 1454 compile(CompileState compState)1455 void compile(CompileState compState) { 1456 AppearanceRetained newApp; 1457 1458 super.compile(compState); 1459 1460 if (isStatic() && staticXformCanBeApplied()) { 1461 mergeFlag = SceneGraphObjectRetained.MERGE; 1462 if (J3dDebug.devPhase && J3dDebug.debug) { 1463 compState.numShapesWStaticTG++; 1464 } 1465 } else 1466 { 1467 mergeFlag = SceneGraphObjectRetained.DONT_MERGE; 1468 compState.keepTG = true; 1469 } 1470 1471 if (J3dDebug.devPhase && J3dDebug.debug) { 1472 compState.numShapes++; 1473 } 1474 1475 if (appearance != null) { 1476 appearance.compile(compState); 1477 // Non-static apperanace can still be compiled, since in compile 1478 // state we will be grouping all shapes that have same appearance 1479 // so, when the appearance changes, all the shapes will be affected 1480 // For non-static appearances, we don't get an equivalent appearance 1481 // from the compile state 1482 if (appearance.isStatic()) { 1483 newApp = compState.getAppearance(appearance); 1484 appearance = newApp; 1485 } 1486 } 1487 1488 for (int i = 0; i < geometryList.size(); i++) { 1489 GeometryRetained geo = (GeometryRetained)geometryList.get(i); 1490 if (geo != null) 1491 geo.compile(compState); 1492 } 1493 1494 } 1495 merge(CompileState compState)1496 void merge(CompileState compState) { 1497 1498 1499 if (mergeFlag == SceneGraphObjectRetained.DONT_MERGE) { 1500 1501 // no need to save the staticTransform here 1502 1503 TransformGroupRetained saveStaticTransform = 1504 compState.staticTransform; 1505 compState.staticTransform = null; 1506 super.merge(compState); 1507 compState.staticTransform = saveStaticTransform; 1508 } else { 1509 super.merge(compState); 1510 } 1511 1512 if (shapeIsMergeable(compState)) { 1513 compState.addShape(this); 1514 } 1515 } 1516 1517 shapeIsMergeable(CompileState compState)1518 boolean shapeIsMergeable(CompileState compState) { 1519 boolean mergeable = true; 1520 AppearanceRetained newApp; 1521 int i; 1522 1523 GeometryRetained geometry = null; 1524 int index = 0; 1525 i = 0; 1526 /* 1527 if (isPickable) 1528 return false; 1529 */ 1530 1531 // For now, don't merge if the shape has static transform 1532 if (staticTransform != null) 1533 return false; 1534 1535 // If this shape's to be immediate parent is orderedGroup or a switchNode 1536 // this shape is not mergerable 1537 if (parent instanceof OrderedGroupRetained || 1538 parent instanceof SwitchRetained) 1539 return false; 1540 1541 // Get the first geometry that is non-null 1542 while (geometry == null && index < geometryList.size()) { 1543 geometry = (GeometryRetained) geometryList.get(index); 1544 index++; 1545 } 1546 1547 if (!(geometry instanceof GeometryArrayRetained)) { 1548 return false; 1549 } 1550 1551 GeometryArrayRetained firstGeo = (GeometryArrayRetained) geometry; 1552 1553 for(i=index; (i<geometryList.size() && mergeable); i++) { 1554 geometry = (GeometryRetained) geometryList.get(i); 1555 if (geometry != null) { 1556 GeometryArrayRetained geo = (GeometryArrayRetained)geometry; 1557 1558 if (! geo.isWriteStatic()) 1559 mergeable = false; 1560 1561 if (geo.vertexFormat != firstGeo.vertexFormat) 1562 mergeable = false; 1563 1564 1565 } 1566 } 1567 1568 // For now, turn off lots of capability bits 1569 if (source.getCapability(Shape3D.ALLOW_COLLISION_BOUNDS_WRITE) || 1570 source.getCapability(Shape3D.ALLOW_APPEARANCE_WRITE) || 1571 source.getCapability(Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE) || 1572 source.getCapability(Shape3D.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE) || 1573 source.getCapability(Shape3D.ALLOW_BOUNDS_WRITE) || 1574 source.getCapability(Shape3D.ALLOW_COLLIDABLE_WRITE) || 1575 source.getCapability(Shape3D.ALLOW_PICKABLE_WRITE) || 1576 source.getCapability(Shape3D.ALLOW_GEOMETRY_WRITE)) { 1577 mergeable = false; 1578 } 1579 1580 return mergeable; 1581 1582 } 1583 1584 getMirrorObjects( ArrayList list, HashKey k)1585 void getMirrorObjects( ArrayList list, HashKey k) { 1586 Shape3DRetained ms; 1587 if (inSharedGroup) { 1588 if (k.count == 0) { 1589 // System.err.println("===> CAN NEVER BE TRUE"); 1590 return; 1591 } 1592 else { 1593 ms = getMirrorShape(k); 1594 } 1595 } 1596 else { 1597 ms = (Shape3DRetained)mirrorShape3D.get(0); 1598 } 1599 1600 list.add(getGeomAtom(ms)); 1601 1602 } 1603 1604 1605 // Called on the mirror Object addLight(LightRetained light)1606 void addLight(LightRetained light) { 1607 LightRetained[] newlights; 1608 int i, n; 1609 Shape3DRetained ms; 1610 1611 if (lights == null) { 1612 lights = new LightRetained[10]; 1613 } 1614 else if (lights.length == numlights) { 1615 newlights = new LightRetained[numlights*2]; 1616 for (i=0; i<numlights; i++) { 1617 newlights[i] = lights[i]; 1618 } 1619 lights = newlights; 1620 } 1621 lights[numlights] = light; 1622 numlights++; 1623 } 1624 1625 // called on the mirror object removeLight(LightRetained light)1626 void removeLight(LightRetained light) { 1627 int i; 1628 1629 for (i=0; i<numlights; i++) { 1630 if (lights[i] == light) { 1631 lights[i] = null; 1632 break; 1633 } 1634 } 1635 1636 // Shift everyone down one. 1637 for (i++; i<numlights; i++) { 1638 lights[i-1] = lights[i]; 1639 } 1640 numlights--; 1641 } 1642 1643 // Called on the mirror object addFog(FogRetained fog)1644 void addFog(FogRetained fog) { 1645 FogRetained[] newfogs; 1646 int i; 1647 1648 if (fogs == null) { 1649 fogs = new FogRetained[10]; 1650 } 1651 else if (fogs.length == numfogs) { 1652 newfogs = new FogRetained[numfogs*2]; 1653 for (i=0; i<numfogs; i++) { 1654 newfogs[i] = fogs[i]; 1655 } 1656 fogs = newfogs; 1657 } 1658 fogs[numfogs] = fog; 1659 numfogs++; 1660 } 1661 1662 // called on the mirror object removeFog(FogRetained fog)1663 void removeFog(FogRetained fog) { 1664 int i; 1665 1666 for (i=0; i<numfogs; i++) { 1667 if (fogs[i] == fog) { 1668 fogs[i] = null; 1669 break; 1670 } 1671 } 1672 1673 // Shift everyone down one. 1674 for (i++; i<numfogs; i++) { 1675 fogs[i-1] = fogs[i]; 1676 } 1677 numfogs--; 1678 1679 } 1680 1681 // Called on the mirror object addModelClip(ModelClipRetained modelClip)1682 void addModelClip(ModelClipRetained modelClip) { 1683 ModelClipRetained[] newModelClips; 1684 int i; 1685 1686 1687 if (modelClips == null) { 1688 modelClips = new ModelClipRetained[10]; 1689 } 1690 else if (modelClips.length == numModelClips) { 1691 newModelClips = new ModelClipRetained[numModelClips*2]; 1692 for (i=0; i<numModelClips; i++) { 1693 newModelClips[i] = modelClips[i]; 1694 } 1695 modelClips = newModelClips; 1696 } 1697 modelClips[numModelClips] = modelClip; 1698 numModelClips++; 1699 } 1700 1701 // called on the mirror object removeModelClip(ModelClipRetained modelClip)1702 void removeModelClip(ModelClipRetained modelClip) { 1703 int i; 1704 1705 for (i=0; i<numModelClips; i++) { 1706 if (modelClips[i] == modelClip) { 1707 modelClips[i] = null; 1708 break; 1709 } 1710 } 1711 1712 // Shift everyone down one. 1713 for (i++; i<numModelClips; i++) { 1714 modelClips[i-1] = modelClips[i]; 1715 } 1716 numModelClips--; 1717 1718 } 1719 1720 // Called on the mirror object addAltApp(AlternateAppearanceRetained aApp)1721 void addAltApp(AlternateAppearanceRetained aApp) { 1722 AlternateAppearanceRetained[] newAltApps; 1723 int i; 1724 if (altApps == null) { 1725 altApps = new AlternateAppearanceRetained[10]; 1726 } 1727 else if (altApps.length == numAltApps) { 1728 newAltApps = new AlternateAppearanceRetained[numAltApps*2]; 1729 for (i=0; i<numAltApps; i++) { 1730 newAltApps[i] = altApps[i]; 1731 } 1732 altApps = newAltApps; 1733 } 1734 altApps[numAltApps] = aApp; 1735 numAltApps++; 1736 } 1737 1738 // called on the mirror object removeAltApp(AlternateAppearanceRetained aApp)1739 void removeAltApp(AlternateAppearanceRetained aApp) { 1740 int i; 1741 1742 for (i=0; i<numAltApps; i++) { 1743 if (altApps[i] == aApp) { 1744 altApps[i] = null; 1745 break; 1746 } 1747 } 1748 1749 // Shift everyone down one. 1750 for (i++; i<numAltApps; i++) { 1751 altApps[i-1] = altApps[i]; 1752 } 1753 numAltApps--; 1754 1755 } 1756 1757 1758 updatePickable(HashKey keys[], boolean pick[])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 updateCollidable(HashKey keys[], boolean collide[])1782 void updateCollidable(HashKey keys[], boolean collide[]) { 1783 super.updateCollidable(keys, collide); 1784 Shape3DRetained shape; 1785 1786 if (!inSharedGroup) { 1787 shape = (Shape3DRetained) mirrorShape3D.get(0); 1788 shape.isCollidable = collide[0]; 1789 } else { 1790 int size = mirrorShape3D.size(); 1791 for (int j=0; j< keys.length; j++) { 1792 for (int i=0; i < size; i++) { 1793 shape = (Shape3DRetained) mirrorShape3D.get(i); 1794 if (keys[j].equals(shape.key)) { 1795 shape.isCollidable = collide[j]; 1796 break; 1797 } 1798 1799 } 1800 } 1801 } 1802 } 1803 1804 1805 1806 1807 // New 1.2.1 code .... 1808 1809 // Remove the old geometry atoms and reInsert 1810 // the new geometry atoms and update the transform 1811 // target list 1812 sendDataChangedMessage( GeometryRetained newGeom )1813 private void sendDataChangedMessage( GeometryRetained newGeom ) { 1814 1815 int i, j, gaCnt; 1816 GeometryAtom[] newGAArray = null; 1817 GeometryAtom[] oldGAArray = null; 1818 GeometryAtom[] newGeometryAtoms = null; 1819 int geometryCnt = 0; 1820 GeometryRetained geometry = null; 1821 1822 int s3dMSize = mirrorShape3D.size(); 1823 1824 if(s3dMSize < 1) 1825 return; 1826 1827 Shape3DRetained mS3d = (Shape3DRetained) mirrorShape3D.get(0); 1828 1829 mS3d.mirrorShape3DLock.writeLock(); 1830 1831 GeometryAtom oldGA = mS3d.geomAtom; 1832 1833 GeometryAtom newGA = new GeometryAtom(); 1834 1835 if(newGeom != null) { 1836 newGeom.addUser(mS3d); 1837 } 1838 1839 int gSize = geometryList.size(); 1840 1841 for(i=0; i<gSize; i++) { 1842 geometry = (GeometryRetained) geometryList.get(i); 1843 if(geometry != null) { 1844 newGA.geoType = geometry.geoType; 1845 newGA.alphaEditable = mS3d.isAlphaEditable(geometry); 1846 break; 1847 } 1848 } 1849 1850 if((geometry != null) && 1851 (geometry.geoType == GeometryRetained.GEO_TYPE_TEXT3D)) { 1852 1853 for(i = 0; i<gSize; i++) { 1854 geometry = (GeometryRetained) geometryList.get(i); 1855 if(geometry != null) { 1856 Text3DRetained tempT3d = (Text3DRetained)geometry; 1857 geometryCnt += tempT3d.numChars; 1858 } 1859 else { 1860 // This is slightly wasteful, but not quite worth to optimize yet. 1861 geometryCnt++; 1862 } 1863 } 1864 newGA.geometryArray = new GeometryRetained[geometryCnt]; 1865 newGA.lastLocalTransformArray = new Transform3D[geometryCnt]; 1866 // Reset geometryCnt; 1867 geometryCnt = 0; 1868 1869 } 1870 else { 1871 newGA.geometryArray = new GeometryRetained[gSize]; 1872 } 1873 1874 newGA.locale = mS3d.locale; 1875 newGA.visible = visible; 1876 newGA.source = mS3d; 1877 1878 1879 for(gaCnt = 0; gaCnt<gSize; gaCnt++) { 1880 geometry = (GeometryRetained) geometryList.get(gaCnt); 1881 if(geometry == null) { 1882 newGA.geometryArray[geometryCnt++] = null; 1883 } 1884 else { 1885 if (geometry.geoType == GeometryRetained.GEO_TYPE_TEXT3D) { 1886 Text3DRetained t = (Text3DRetained)geometry; 1887 GeometryRetained geo; 1888 for (i=0; i<t.numChars; i++, geometryCnt++) { 1889 geo = t.geometryList[i]; 1890 if (geo!= null) { 1891 newGA.geometryArray[geometryCnt] = geo; 1892 newGA.lastLocalTransformArray[geometryCnt] = 1893 t.charTransforms[i]; 1894 1895 } else { 1896 newGA.geometryArray[geometryCnt] = null; 1897 newGA.lastLocalTransformArray[geometryCnt] = null; 1898 } 1899 1900 } 1901 1902 } else { 1903 newGA.geometryArray[geometryCnt++] = geometry; 1904 } 1905 } 1906 } 1907 1908 oldGAArray = new GeometryAtom[s3dMSize]; 1909 newGAArray = new GeometryAtom[s3dMSize]; 1910 oldGAArray[0] = oldGA; 1911 newGAArray[0] = newGA; 1912 1913 mS3d.geomAtom = newGA; 1914 mS3d.mirrorShape3DLock.writeUnlock(); 1915 1916 // ..... clone the rest of mirrorS3D's GA with the above newGA, but modify 1917 // its source. 1918 1919 for (i = 1; i < s3dMSize; i++) { 1920 mS3d = (Shape3DRetained) mirrorShape3D.get(i); 1921 mS3d.mirrorShape3DLock.writeLock(); 1922 oldGA = mS3d.geomAtom; 1923 newGA = new GeometryAtom(); 1924 1925 if(newGeom != null) { 1926 newGeom.addUser(mS3d); 1927 } 1928 1929 newGA.geoType = newGAArray[0].geoType; 1930 newGA.locale = mS3d.locale; 1931 newGA.visible = visible; 1932 newGA.source = mS3d; 1933 newGA.alphaEditable = newGAArray[0].alphaEditable; 1934 1935 newGA.geometryArray = new GeometryRetained[newGAArray[0].geometryArray.length]; 1936 for(j=0; j<newGA.geometryArray.length; j++) { 1937 newGA.geometryArray[j] = newGAArray[0].geometryArray[j]; 1938 } 1939 1940 oldGAArray[i] = oldGA; 1941 newGAArray[i] = newGA; 1942 1943 mS3d.geomAtom = newGA; 1944 mS3d.mirrorShape3DLock.writeUnlock(); 1945 } 1946 1947 TargetsInterface ti = 1948 ((GroupRetained)parent).getClosestTargetsInterface( 1949 TargetsInterface.TRANSFORM_TARGETS); 1950 CachedTargets[] newCtArr = null; 1951 1952 if (ti != null) { 1953 CachedTargets ct; 1954 newCtArr = new CachedTargets[s3dMSize]; 1955 1956 for (i=0; i<s3dMSize; i++) { 1957 1958 ct = ti.getCachedTargets( 1959 TargetsInterface.TRANSFORM_TARGETS, i, -1); 1960 if (ct != null) { 1961 newCtArr[i] = new CachedTargets(); 1962 newCtArr[i].copy(ct); 1963 newCtArr[i].replace(oldGAArray[i], newGAArray[i], 1964 Targets.GEO_TARGETS); 1965 } else { 1966 newCtArr[i] = null; 1967 } 1968 } 1969 ti.resetCachedTargets(TargetsInterface.TRANSFORM_TARGETS, 1970 newCtArr, -1); 1971 } 1972 1973 1974 J3dMessage changeMessage = new J3dMessage(); 1975 changeMessage.type = J3dMessage.SHAPE3D_CHANGED; 1976 // Who to send this message to ? 1977 changeMessage.threads = J3dThread.UPDATE_RENDER | 1978 J3dThread.UPDATE_TRANSFORM | 1979 J3dThread.UPDATE_GEOMETRY; 1980 changeMessage.universe = universe; 1981 changeMessage.args[0] = this; 1982 changeMessage.args[1] = new Integer(GEOMETRY_CHANGED); 1983 changeMessage.args[2] = oldGAArray; 1984 changeMessage.args[3] = newGAArray; 1985 if (ti != null) { 1986 changeMessage.args[4] = ti; 1987 changeMessage.args[5] = newCtArr; 1988 } 1989 if (boundsAutoCompute) { 1990 getCombineBounds((BoundingBox)localBounds); 1991 } 1992 VirtualUniverse.mc.processMessage(changeMessage); 1993 1994 } 1995 1996 1997 // ********** End of New 1.2.1 code .... 1998 1999 2000 2001 2002 getMirrorShape(SceneGraphPath path)2003 Shape3DRetained getMirrorShape(SceneGraphPath path) { 2004 if (!inSharedGroup) { 2005 return (Shape3DRetained) mirrorShape3D.get(0); 2006 } 2007 HashKey key = new HashKey(""); 2008 path.getHashKey(key); 2009 return getMirrorShape(key); 2010 } 2011 getMirrorShape(HashKey key)2012 Shape3DRetained getMirrorShape(HashKey key) { 2013 if (key == null) { 2014 return (Shape3DRetained) mirrorShape3D.get(0); 2015 } else { 2016 int i = key.equals(localToVworldKeys, 0, localToVworldKeys.length); 2017 2018 if (i>=0) { 2019 return (Shape3DRetained) mirrorShape3D.get(i); 2020 } 2021 } 2022 // Not possible 2023 throw new RuntimeException("Shape3DRetained: MirrorShape Not found!"); 2024 } 2025 setBoundsAutoCompute(boolean autoCompute)2026 void setBoundsAutoCompute(boolean autoCompute) { 2027 GeometryRetained geometry; 2028 if (autoCompute != boundsAutoCompute) { 2029 if (autoCompute) { 2030 // localBounds may not have been set to bbox 2031 localBounds = new BoundingBox((BoundingBox) null); 2032 if (source.isLive() && geometryList != null) { 2033 int size = geometryList.size()*mirrorShape3D.size(); 2034 for (int i=0; i<size; i++) { 2035 geometry = (GeometryRetained) geometryList.get(i); 2036 geometry.incrComputeGeoBounds(); 2037 } 2038 } 2039 2040 getCombineBounds((BoundingBox)localBounds); 2041 } 2042 else { 2043 if (source.isLive() && geometryList != null) { 2044 int size = geometryList.size()*mirrorShape3D.size(); 2045 for (int i=0; i<size; i++) { 2046 geometry = (GeometryRetained) geometryList.get(i); 2047 geometry.decrComputeGeoBounds(); 2048 } 2049 2050 } 2051 } 2052 super.setBoundsAutoCompute(autoCompute); 2053 if (source.isLive()) { 2054 J3dMessage message = new J3dMessage(); 2055 message.type = J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED; 2056 message.threads = J3dThread.UPDATE_TRANSFORM | 2057 J3dThread.UPDATE_GEOMETRY | 2058 J3dThread.UPDATE_RENDER; 2059 message.universe = universe; 2060 message.args[0] = getGeomAtomsArray(mirrorShape3D); 2061 // no need to clone localBounds 2062 message.args[1] = localBounds; 2063 VirtualUniverse.mc.processMessage(message); 2064 } 2065 } 2066 } 2067 // This method is called when coordinates of a geometry in the geometrylist 2068 // changed and autoBoundsCompute is true 2069 updateBounds()2070 void updateBounds() { 2071 localBounds = new BoundingBox((BoundingBox) null); 2072 getCombineBounds((BoundingBox)localBounds); 2073 synchronized(mirrorShape3D) { 2074 if (source.isLive()) { 2075 J3dMessage message = new J3dMessage(); 2076 message.type = J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED; 2077 message.threads = J3dThread.UPDATE_TRANSFORM | 2078 J3dThread.UPDATE_GEOMETRY | 2079 J3dThread.UPDATE_RENDER; 2080 message.universe = universe; 2081 message.args[0] = getGeomAtomsArray(mirrorShape3D); 2082 // no need to clone localBounds 2083 message.args[1] = localBounds; 2084 VirtualUniverse.mc.processMessage(message); 2085 } 2086 } 2087 } 2088 allowIntersect()2089 boolean allowIntersect() { 2090 GeometryRetained ga = null; 2091 2092 for(int i=0; i<geometryList.size(); i++) { 2093 ga = (GeometryRetained) geometryList.get(i); 2094 if(ga != null) 2095 if (!ga.source.getCapability(Geometry.ALLOW_INTERSECT)) { 2096 return false; 2097 } 2098 } 2099 return true; 2100 } intersectGeometryList(Shape3DRetained otherShape)2101 boolean intersectGeometryList(Shape3DRetained otherShape) { 2102 GeometryRetained geom1, geom2; 2103 ArrayList gaList = otherShape.geometryList; 2104 int gaSize = gaList.size(); 2105 Transform3D otherLocalToVworld = otherShape.getCurrentLocalToVworld(); 2106 Transform3D thisLocalToVworld = getCurrentLocalToVworld(); 2107 View views = null; 2108 int primaryViewIdx = -1; 2109 2110 2111 if (this instanceof OrientedShape3DRetained) { 2112 primaryViewIdx = getPrimaryViewIdx(); 2113 thisLocalToVworld.mul(((OrientedShape3DRetained)this). 2114 getOrientedTransform(primaryViewIdx)); 2115 } 2116 2117 if (otherShape instanceof OrientedShape3DRetained) { 2118 if (primaryViewIdx < 0) { 2119 primaryViewIdx = getPrimaryViewIdx(); 2120 } 2121 otherLocalToVworld.mul(((OrientedShape3DRetained)otherShape). 2122 getOrientedTransform(primaryViewIdx)); 2123 } 2124 2125 for (int i=geometryList.size()-1; i >=0; i--) { 2126 geom1 = (GeometryRetained) geometryList.get(i); 2127 if (geom1 != null) { 2128 for (int j=gaSize-1; j >=0; j--) { 2129 geom2 = (GeometryRetained) gaList.get(j); 2130 if ((geom2 != null) && 2131 geom1.intersect(thisLocalToVworld, 2132 otherLocalToVworld, geom2)) { 2133 return true; 2134 } 2135 } 2136 } 2137 } 2138 2139 return false; 2140 } 2141 intersectGeometryList(Transform3D thisLocalToVworld, Bounds targetBound)2142 boolean intersectGeometryList(Transform3D thisLocalToVworld, Bounds targetBound) { 2143 2144 GeometryRetained geometry; 2145 2146 if (this instanceof OrientedShape3DRetained) { 2147 Transform3D orientedTransform = 2148 ((OrientedShape3DRetained)this). 2149 getOrientedTransform(getPrimaryViewIdx()); 2150 thisLocalToVworld.mul(orientedTransform); 2151 } 2152 2153 for (int i=geometryList.size() - 1; i >=0; i--) { 2154 geometry = (GeometryRetained) geometryList.get(i); 2155 if ((geometry != null) && 2156 geometry.intersect(thisLocalToVworld, targetBound)) { 2157 return true; 2158 } 2159 } 2160 2161 return false; 2162 2163 } 2164 2165 2166 /** 2167 * This initialize the mirror shape to reflect the state of the 2168 * real Morph. 2169 */ initMirrorShape3D(SetLiveState s, MorphRetained morph, int index)2170 void initMirrorShape3D(SetLiveState s, MorphRetained morph, int index) { 2171 2172 GeometryRetained geometry; 2173 2174 GeometryAtom[] newGeometryAtoms = null; 2175 2176 universe = morph.universe; 2177 inSharedGroup = morph.inSharedGroup; 2178 inBackgroundGroup = morph.inBackgroundGroup; 2179 geometryBackground = morph.geometryBackground; 2180 parent = morph.parent; 2181 locale = morph.locale; 2182 2183 OrderedPath op = (OrderedPath)s.orderedPaths.get(index); 2184 if (op.pathElements.size() == 0) { 2185 orderedPath = null; 2186 } else { 2187 orderedPath = op; 2188 } 2189 2190 staticTransform = morph.staticTransform; 2191 if (morph.boundsAutoCompute) { 2192 localBounds.set(morph.localBounds); 2193 } 2194 bounds = localBounds; 2195 vwcBounds = new BoundingBox((BoundingBox) null); 2196 vwcBounds.transform(bounds, getCurrentLocalToVworld(0)); 2197 2198 if (morph.collisionBound == null) { 2199 collisionBound = null; 2200 collisionVwcBound = vwcBounds; 2201 } else { 2202 collisionBound = morph.collisionBound; 2203 collisionVwcBound = (Bounds)collisionBound.clone(); 2204 collisionVwcBound.transform(getCurrentLocalToVworld(0)); 2205 } 2206 2207 appearanceOverrideEnable = morph.appearanceOverrideEnable; 2208 2209 // mga is the final geometry we're interested. 2210 geometryList = new ArrayList(1); 2211 geometryList.add((GeometryArrayRetained)morph.morphedGeometryArray.retained); 2212 2213 GeometryAtom gAtom = new GeometryAtom(); 2214 gAtom.geometryArray = new GeometryRetained[1]; 2215 2216 gAtom.locale = locale; 2217 gAtom.visible = morph.visible; 2218 gAtom.source = this; 2219 2220 geometry = (GeometryRetained) geometryList.get(0); 2221 2222 if(geometry ==null) { 2223 gAtom.geometryArray[0] = null; 2224 } else { 2225 gAtom.geometryArray[0] = (GeometryArrayRetained)morph. 2226 morphedGeometryArray.retained; 2227 gAtom.geoType = gAtom.geometryArray[0].geoType; 2228 } 2229 geomAtom = gAtom; 2230 2231 // Assign the parent of this mirror shape node 2232 sourceNode = morph; 2233 } 2234 2235 // geometries in morph object is modified, update the geometry 2236 // list in the mirror shapes and the geometry array in the geometry atom 2237 setMorphGeometry(Geometry geometry, ArrayList mirrorShapes)2238 void setMorphGeometry(Geometry geometry, ArrayList mirrorShapes) { 2239 GeometryAtom oldGA, newGA; 2240 Shape3DRetained ms; 2241 TransformGroupRetained tg; 2242 int nMirrorShapes = mirrorShapes.size(); 2243 int i; 2244 2245 GeometryAtom oldGAArray[] = new GeometryAtom[nMirrorShapes]; 2246 GeometryAtom newGAArray[] = new GeometryAtom[nMirrorShapes]; 2247 2248 2249 for (i = 0; i < nMirrorShapes; i++) { 2250 ms = (Shape3DRetained) mirrorShapes.get(i); 2251 2252 oldGA = Shape3DRetained.getGeomAtom(ms); 2253 2254 ms.geometryList = new ArrayList(1); 2255 ms.geometryList.add((GeometryArrayRetained)geometry.retained); 2256 2257 newGA = new GeometryAtom(); 2258 newGA.geometryArray = new GeometryRetained[1]; 2259 2260 if (geometry ==null) { 2261 newGA.geometryArray[0] = null; 2262 } else { 2263 newGA.geometryArray[0] = 2264 (GeometryArrayRetained)geometry.retained; 2265 newGA.geoType = newGA.geometryArray[0].geoType; 2266 } 2267 2268 newGA.locale = locale; 2269 newGA.visible = oldGA.visible; 2270 newGA.source = this; 2271 2272 oldGAArray[i] = oldGA; 2273 newGAArray[i] = newGA; 2274 2275 Shape3DRetained.setGeomAtom(ms, newGA); 2276 } 2277 2278 TargetsInterface ti = 2279 ((GroupRetained)parent).getClosestTargetsInterface( 2280 TargetsInterface.TRANSFORM_TARGETS); 2281 CachedTargets[] newCtArr = null; 2282 2283 if (ti != null) { 2284 CachedTargets ct; 2285 newCtArr = new CachedTargets[nMirrorShapes]; 2286 2287 for (i=0; i<nMirrorShapes; i++) { 2288 2289 ct = ti.getCachedTargets( 2290 TargetsInterface.TRANSFORM_TARGETS, i, -1); 2291 if (ct != null) { 2292 newCtArr[i] = new CachedTargets(); 2293 newCtArr[i].copy(ct); 2294 newCtArr[i].replace(oldGAArray[i], newGAArray[i], 2295 Targets.GEO_TARGETS); 2296 } else { 2297 newCtArr[i] = null; 2298 } 2299 } 2300 } 2301 2302 // send a Shape GEOMETRY_CHANGED message for all geometry atoms 2303 2304 J3dMessage changeMessage = new J3dMessage(); 2305 changeMessage.type = J3dMessage.SHAPE3D_CHANGED; 2306 changeMessage.threads = J3dThread.UPDATE_RENDER | 2307 J3dThread.UPDATE_TRANSFORM | 2308 J3dThread.UPDATE_GEOMETRY; 2309 changeMessage.universe = universe; 2310 changeMessage.args[0] = this; 2311 changeMessage.args[1] = new Integer(GEOMETRY_CHANGED); 2312 changeMessage.args[2] = oldGAArray; 2313 changeMessage.args[3] = newGAArray; 2314 if (ti != null) { 2315 changeMessage.args[4] = ti; 2316 changeMessage.args[5] = newCtArr; 2317 } 2318 VirtualUniverse.mc.processMessage(changeMessage); 2319 } 2320 2321 2322 /** 2323 * Return an array of geometry atoms belongs to userList. 2324 * The input is an arraylist of Shape3DRetained type. 2325 * This is used to send a message of the snapshot of the 2326 * geometry atoms that are affected by this change. 2327 */ getGeomAtomsArray(ArrayList userList)2328 final static GeometryAtom[] getGeomAtomsArray(ArrayList userList) { 2329 Shape3DRetained ms = null; 2330 GeometryAtom[] gaArr = null; 2331 int size, nullCnt=0, i, j; 2332 2333 synchronized(userList) { 2334 size = userList.size(); 2335 gaArr = new GeometryAtom[size]; 2336 for (i = 0; i < size; i++) { 2337 ms = (Shape3DRetained) userList.get(i); 2338 ms.mirrorShape3DLock.readLock(); 2339 if(ms.geomAtom == null) { 2340 nullCnt++; 2341 } 2342 gaArr[i] = ms.geomAtom; 2343 ms.mirrorShape3DLock.readUnlock(); 2344 } 2345 } 2346 if(nullCnt == 0) { 2347 return gaArr; 2348 } 2349 else if(nullCnt == size) { 2350 return null; 2351 } 2352 else { 2353 GeometryAtom[] newGaArr = new GeometryAtom[size - nullCnt]; 2354 2355 for (i=0, j=0; i < size; i++) { 2356 if(gaArr[i] != null) { 2357 newGaArr[j++] = gaArr[i]; 2358 } 2359 } 2360 return newGaArr; 2361 } 2362 } 2363 2364 /** 2365 * Return a list of geometry atoms belongs to userList and places a list of 2366 * universe found in userList in univList. 2367 * The input is an array of Shape3DRetained type. 2368 * univList is assume to be empty. 2369 * This is used to send a message of the snapshot of the 2370 * geometry atoms that are affected by this change. 2371 */ getGeomAtomsList(ArrayList userList, ArrayList univList)2372 final static ArrayList getGeomAtomsList(ArrayList userList, ArrayList univList) { 2373 ArrayList listPerUniverse = new ArrayList(); 2374 int index; 2375 ArrayList gaList = null; 2376 Shape3DRetained ms = null; 2377 boolean moreThanOneUniv = false; 2378 VirtualUniverse firstFndUniv = null; 2379 2380 synchronized(userList) { 2381 for (int i = userList.size()-1; i >=0; i--) { 2382 ms = (Shape3DRetained) userList.get(i); 2383 2384 if(moreThanOneUniv == false) { 2385 if(firstFndUniv == null) { 2386 firstFndUniv = ms.universe; 2387 univList.add(ms.universe); 2388 2389 gaList = new ArrayList(); 2390 listPerUniverse.add(gaList); 2391 } 2392 else if(firstFndUniv != ms.universe) { 2393 moreThanOneUniv = true; 2394 univList.add(ms.universe); 2395 gaList = new ArrayList(); 2396 listPerUniverse.add(gaList); 2397 } 2398 } 2399 else { 2400 index = univList.indexOf(ms.universe); 2401 if (index < 0) { 2402 univList.add(ms.universe); 2403 gaList = new ArrayList(); 2404 listPerUniverse.add(gaList); 2405 } 2406 else { 2407 gaList = (ArrayList) listPerUniverse.get(index); 2408 } 2409 } 2410 2411 2412 ms.mirrorShape3DLock.readLock(); 2413 2414 if(ms.geomAtom != null) { 2415 gaList.add(ms.geomAtom); 2416 } 2417 ms.mirrorShape3DLock.readUnlock(); 2418 2419 } 2420 } 2421 return listPerUniverse; 2422 } 2423 getGeomAtom(Shape3DRetained shape)2424 final static GeometryAtom getGeomAtom(Shape3DRetained shape) { 2425 GeometryAtom ga; 2426 2427 shape.mirrorShape3DLock.readLock(); 2428 ga = shape.geomAtom; 2429 shape.mirrorShape3DLock.readUnlock(); 2430 2431 return ga; 2432 } 2433 setGeomAtom(Shape3DRetained shape, GeometryAtom ga)2434 final static void setGeomAtom(Shape3DRetained shape, GeometryAtom ga) { 2435 shape.mirrorShape3DLock.writeLock(); 2436 shape.geomAtom = ga; 2437 shape.mirrorShape3DLock.writeUnlock(); 2438 } 2439 2440 2441 // Alpha is editable due to the appearance isAlphaEditable(GeometryRetained geo)2442 boolean isAlphaEditable(GeometryRetained geo) { 2443 2444 boolean alphaEditable = false; 2445 2446 if (appearanceOverrideEnable) { 2447 alphaEditable = true; 2448 } else if (geo != null && 2449 appearance != null) { 2450 2451 AppearanceRetained app = appearance; 2452 2453 if (source.getCapability( 2454 Shape3D.ALLOW_APPEARANCE_WRITE) || 2455 source.getCapability( 2456 Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE) || 2457 2458 app.source.getCapability( 2459 Appearance.ALLOW_RENDERING_ATTRIBUTES_WRITE) || 2460 2461 app.source.getCapability( 2462 Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE) || 2463 2464 (app.renderingAttributes != null && 2465 (app.renderingAttributes.source.getCapability( 2466 RenderingAttributes.ALLOW_ALPHA_TEST_FUNCTION_WRITE) || 2467 app.renderingAttributes.source.getCapability( 2468 RenderingAttributes.ALLOW_IGNORE_VERTEX_COLORS_WRITE))) || 2469 2470 (app.transparencyAttributes != null && 2471 (app.transparencyAttributes.source.getCapability( 2472 TransparencyAttributes.ALLOW_MODE_WRITE) || 2473 app.transparencyAttributes.source.getCapability( 2474 TransparencyAttributes.ALLOW_VALUE_WRITE)))) { 2475 2476 alphaEditable = true; 2477 2478 } else if (geo instanceof GeometryArrayRetained && 2479 (app.source.getCapability( 2480 Appearance.ALLOW_TEXTURE_ATTRIBUTES_WRITE) || 2481 2482 (app.textureAttributes != null && 2483 app.textureAttributes.source.getCapability( 2484 TextureAttributes.ALLOW_MODE_WRITE)))) { 2485 2486 alphaEditable = true; 2487 2488 } else if (geo instanceof RasterRetained) { 2489 if ((((RasterRetained)geo).type & Raster.RASTER_COLOR) != 2490 0 2491 && ((RasterRetained)geo).source.getCapability( 2492 Raster.ALLOW_IMAGE_WRITE)) { 2493 2494 alphaEditable = true; 2495 } 2496 } 2497 } 2498 return alphaEditable; 2499 } 2500 2501 // getCombineBounds is faster than computeCombineBounds since it 2502 // does not recompute the geometry.geoBounds getCombineBounds(BoundingBox bounds)2503 void getCombineBounds(BoundingBox bounds) { 2504 2505 if(geometryList != null) { 2506 BoundingBox bbox = null; 2507 GeometryRetained geometry; 2508 2509 if (staticTransform != null) { 2510 bbox = new BoundingBox((BoundingBox) null); 2511 } 2512 2513 synchronized(bounds) { 2514 bounds.setLower( 1.0, 1.0, 1.0); 2515 bounds.setUpper(-1.0,-1.0,-1.0); 2516 for(int i=0; i<geometryList.size(); i++) { 2517 geometry = (GeometryRetained) geometryList.get(i); 2518 if ((geometry != null) && 2519 (geometry.geoType != GeometryRetained.GEO_TYPE_NONE)) { 2520 synchronized(geometry.geoBounds) { 2521 if (staticTransform != null) { 2522 bbox.set(geometry.geoBounds); 2523 bbox.transform(staticTransform.transform); 2524 bounds.combine((Bounds)bbox); 2525 } else { 2526 bounds.combine((Bounds)geometry.geoBounds); 2527 } 2528 } 2529 } 2530 } 2531 } 2532 2533 // System.err.println("Shape3DRetained - getCombineBounds"); 2534 // Enlarge boundingBox to the "minmium bounds" that encompasses all possible 2535 // orientation. 2536 if (this instanceof OrientedShape3DRetained) { 2537 double maxVal = Math.abs(bounds.lower.x); 2538 double tempVal = Math.abs(bounds.upper.x); 2539 if(tempVal > maxVal) 2540 maxVal = tempVal; 2541 tempVal = Math.abs(bounds.lower.y); 2542 if(tempVal > maxVal) 2543 maxVal = tempVal; 2544 tempVal = Math.abs(bounds.upper.y); 2545 if(tempVal > maxVal) 2546 maxVal = tempVal; 2547 tempVal = Math.abs(bounds.lower.z); 2548 if(tempVal > maxVal) 2549 maxVal = tempVal; 2550 tempVal = Math.abs(bounds.upper.z); 2551 if(tempVal > maxVal) 2552 maxVal = tempVal; 2553 2554 // System.err.println("Shape3DRetained - bounds (Before) " + bounds); 2555 bounds.setLower(-maxVal, -maxVal, -maxVal); 2556 bounds.setUpper(maxVal, maxVal, maxVal); 2557 // System.err.println("Shape3DRetained - bounds (After) " + bounds); 2558 } 2559 2560 } 2561 } 2562 2563 isEquivalent(Shape3DRetained shape)2564 boolean isEquivalent(Shape3DRetained shape) { 2565 if (this.appearance != shape.appearance || 2566 // Scoping info should be same since they are under same group 2567 this.appearanceOverrideEnable != shape.appearanceOverrideEnable || 2568 this.isPickable != shape.isPickable || 2569 this.isCollidable != shape.isCollidable) { 2570 2571 return false; 2572 } 2573 if (this.boundsAutoCompute) { 2574 if (!shape.boundsAutoCompute) 2575 return false; 2576 } 2577 else { 2578 // If bounds autoCompute is false 2579 // Then check if both bounds are equal 2580 if (this.localBounds != null) { 2581 if (shape.localBounds != null) { 2582 return this.localBounds.equals(shape.localBounds); 2583 } 2584 } 2585 else if (shape.localBounds != null) { 2586 return false; 2587 } 2588 } 2589 if (collisionBound != null) { 2590 if (shape.collisionBound == null) 2591 return false; 2592 else 2593 return collisionBound.equals(shape.collisionBound); 2594 } 2595 else if (shape.collisionBound != null) 2596 return false; 2597 2598 return true; 2599 } 2600 2601 // Bounds can only be set after the geometry is setLived, so has to be done 2602 // here, if we are not using switchVwcBounds initializeGAtom(Shape3DRetained ms)2603 void initializeGAtom(Shape3DRetained ms) { 2604 int i, gaCnt; 2605 int geometryCnt = 0; 2606 int gSize = geometryList.size(); 2607 GeometryRetained geometry = null; 2608 2609 ms.bounds = localBounds; 2610 ms.vwcBounds = new BoundingBox((BoundingBox) null); 2611 ms.vwcBounds.transform(ms.bounds, ms.getCurrentLocalToVworld(0)); 2612 2613 if (collisionBound == null) { 2614 ms.collisionBound = null; 2615 ms.collisionVwcBound = ms.vwcBounds; 2616 } else { 2617 ms.collisionBound = collisionBound; 2618 ms.collisionVwcBound = (Bounds)ms.collisionBound.clone(); 2619 ms.collisionVwcBound.transform(ms.getCurrentLocalToVworld(0)); 2620 } 2621 GeometryAtom gAtom = new GeometryAtom(); 2622 for(gaCnt=0; gaCnt<gSize; gaCnt++) { 2623 geometry = (GeometryRetained) geometryList.get(gaCnt); 2624 if(geometry != null) { 2625 gAtom.geoType = geometry.geoType; 2626 gAtom.alphaEditable = ms.isAlphaEditable(geometry); 2627 break; 2628 } 2629 } 2630 if((geometry != null) && 2631 (geometry.geoType == GeometryRetained.GEO_TYPE_TEXT3D)) { 2632 2633 for(gaCnt = 0; gaCnt<gSize; gaCnt++) { 2634 geometry = (GeometryRetained) geometryList.get(gaCnt); 2635 if(geometry != null) { 2636 Text3DRetained tempT3d = (Text3DRetained)geometry; 2637 geometryCnt += tempT3d.numChars; 2638 } 2639 else { 2640 // This is slightly wasteful, but not quite worth to optimize yet. 2641 geometryCnt++; 2642 } 2643 } 2644 gAtom.geometryArray = new GeometryRetained[geometryCnt]; 2645 gAtom.lastLocalTransformArray = new Transform3D[geometryCnt]; 2646 // Reset geometryCnt; 2647 geometryCnt = 0; 2648 2649 } 2650 else { 2651 gAtom.geometryArray = new GeometryRetained[gSize]; 2652 } 2653 2654 2655 for(gaCnt = 0; gaCnt<geometryList.size(); gaCnt++) { 2656 geometry = (GeometryRetained) geometryList.get(gaCnt); 2657 if(geometry == null) { 2658 gAtom.geometryArray[gaCnt] = null; 2659 } 2660 else { 2661 if (geometry.geoType == GeometryRetained.GEO_TYPE_TEXT3D) { 2662 Text3DRetained t = (Text3DRetained)geometry; 2663 GeometryRetained geo; 2664 for (i=0; i<t.numChars; i++, geometryCnt++) { 2665 geo = t.geometryList[i]; 2666 if (geo != null) { 2667 gAtom.geometryArray[geometryCnt] = geo; 2668 gAtom.lastLocalTransformArray[geometryCnt] = 2669 t.charTransforms[i]; 2670 } else { 2671 gAtom.geometryArray[geometryCnt] = null; 2672 gAtom.lastLocalTransformArray[geometryCnt] = null; 2673 } 2674 2675 } 2676 2677 } else { 2678 gAtom.geometryArray[gaCnt] = geometry; 2679 } 2680 } 2681 } 2682 gAtom.locale = ms.locale; 2683 gAtom.visible = visible; 2684 gAtom.source = ms; 2685 ms.geomAtom = gAtom; 2686 } 2687 2688 // Check if geomRetained's class is equivalence with the geometry class. checkEquivalenceClass(Geometry geometry, int index)2689 void checkEquivalenceClass(Geometry geometry, int index) { 2690 2691 if (geometry != null) { 2692 for (int i=geometryList.size()-1; i >= 0; i--) { 2693 GeometryRetained geomRetained = (GeometryRetained) geometryList.get(i); 2694 if ((geomRetained != null) && 2695 (index != i)) { // this geometry will replace 2696 // current one so there is no need to check 2697 if (!geomRetained.isEquivalenceClass((GeometryRetained)geometry.retained)) { 2698 throw new IllegalArgumentException(J3dI18N.getString("Shape3DRetained5")); 2699 } 2700 break; 2701 } 2702 } 2703 } 2704 } 2705 indexOfGeometry(Geometry geometry)2706 int indexOfGeometry(Geometry geometry) { 2707 if(geometry != null) 2708 return geometryList.indexOf(geometry.retained); 2709 else 2710 return geometryList.indexOf(null); 2711 } 2712 2713 2714 // Removes the specified geometry from this Shape3DRetained's list of geometries removeGeometry(Geometry geometry)2715 void removeGeometry(Geometry geometry) { 2716 int ind = indexOfGeometry(geometry); 2717 if(ind >= 0) 2718 removeGeometry(ind); 2719 } 2720 2721 // Removes all the geometries from this node removeAllGeometries()2722 void removeAllGeometries() { 2723 int n = geometryList.size(); 2724 2725 int i; 2726 Shape3DRetained mShape; 2727 GeometryRetained oldGeom = null; 2728 2729 if (((Shape3D)this.source).isLive()) { 2730 for(int index = n-1; index >= 0; index--) { 2731 oldGeom = (GeometryRetained) (geometryList.get(index)); 2732 if (oldGeom != null) { 2733 oldGeom.clearLive(refCount); 2734 oldGeom.decRefCnt(); 2735 for (i=0; i<mirrorShape3D.size(); i++) { 2736 mShape = (Shape3DRetained)mirrorShape3D.get(i); 2737 oldGeom.removeUser(mShape); 2738 } 2739 } 2740 geometryList.remove(index); 2741 } 2742 sendDataChangedMessage(null); 2743 } else { 2744 for(int index = n-1; index >= 0; index--) { 2745 oldGeom = (GeometryRetained) (geometryList.get(index)); 2746 if (oldGeom != null) { 2747 oldGeom.decRefCnt(); 2748 } 2749 geometryList.remove(index); 2750 } 2751 } 2752 dirtyBoundsCache(); 2753 } 2754 willRemainOpaque(int geoType)2755 boolean willRemainOpaque(int geoType) { 2756 if (appearance == null || 2757 (appearance.isStatic() && 2758 appearance.isOpaque(geoType))) { 2759 return true; 2760 } 2761 else { 2762 return false; 2763 } 2764 2765 } 2766 handleFrequencyChange(int bit)2767 void handleFrequencyChange(int bit) { 2768 int mask = 0; 2769 if (bit == Shape3D.ALLOW_GEOMETRY_WRITE) { 2770 mask = GEOMETRY_CHANGED; 2771 } 2772 else if (bit == Shape3D.ALLOW_APPEARANCE_WRITE) { 2773 mask = APPEARANCE_CHANGED; 2774 } 2775 else if (bit == Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE) { 2776 mask = APPEARANCEOVERRIDE_CHANGED; 2777 } 2778 if (mask != 0) { 2779 if (source.getCapabilityIsFrequent(bit)) 2780 changedFrequent |= mask; 2781 else if (!source.isLive()) { 2782 changedFrequent &= ~mask; 2783 } 2784 } 2785 } 2786 2787 2788 // Alpha is editable due to the appearance(Called on the MirrorShape3D) isAlphaFrequentlyEditable(GeometryRetained geo)2789 boolean isAlphaFrequentlyEditable(GeometryRetained geo) { 2790 2791 boolean alphaFrequentlyEditable = false; 2792 if (appearanceOverrideEnable) { 2793 alphaFrequentlyEditable = true; 2794 } else if (geo != null && 2795 appearance != null) { 2796 AppearanceRetained app = appearance; 2797 2798 if (((changedFrequent &(APPEARANCE_CHANGED|APPEARANCEOVERRIDE_CHANGED)) != 0)|| 2799 ((app.changedFrequent &(AppearanceRetained.RENDERING|AppearanceRetained.TRANSPARENCY)) != 0) || 2800 (app.renderingAttributes != null && 2801 (((app.renderingAttributes.changedFrequent & (RenderingAttributesRetained.IGNORE_VCOLOR |RenderingAttributesRetained.ALPHA_TEST_FUNC)) != 0))) || 2802 2803 (app.transparencyAttributes != null && 2804 ((app.transparencyAttributes.changedFrequent != 0)))) { 2805 2806 alphaFrequentlyEditable = true; 2807 2808 } else if (geo instanceof GeometryArrayRetained && 2809 ((app.changedFrequent & AppearanceRetained.TEXTURE_ATTR) != 0) || 2810 (app.textureAttributes != null && 2811 ((app.textureAttributes.changedFrequent & TextureAttributes.ALLOW_MODE_WRITE) != 0))) { 2812 alphaFrequentlyEditable = true; 2813 2814 } else if (geo instanceof RasterRetained) { 2815 if (((((RasterRetained)geo).type & Raster.RASTER_COLOR) != 2816 0) 2817 && (((RasterRetained)geo).cachedChangedFrequent != 0)) { 2818 2819 alphaFrequentlyEditable = true; 2820 } 2821 } 2822 } 2823 // System.err.println("changedFrequent="+changedFrequent+" sourceNode = "+sourceNode+" isAlphaFrequentlyEditable, = "+alphaFrequentlyEditable); 2824 return alphaFrequentlyEditable; 2825 } 2826 2827 getPrimaryViewIdx()2828 int getPrimaryViewIdx() { 2829 // To avoid MT-safe issues when using View, just clone it. 2830 UnorderList viewList = VirtualUniverse.mc.cloneView(); 2831 View views[] = (View []) viewList.toArray(false); 2832 int size = viewList.arraySize(); 2833 2834 for (int i=0; i < size; i++) { 2835 if (views[i].primaryView) { 2836 return views[i].viewIndex; 2837 } 2838 } 2839 return 0; 2840 } 2841 searchGeometryAtoms(UnorderList list)2842 void searchGeometryAtoms(UnorderList list) { 2843 list.add(getGeomAtom(getMirrorShape(key))); 2844 } 2845 } 2846 2847