001: /*
002: * $RCSfile: AlternateAppearance.java,v $
003: *
004: * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.6 $
028: * $Date: 2008/02/28 20:17:19 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.Enumeration;
035:
036: /**
037: * The AlternateAppearance leaf node is used for overriding the
038: * Appearance component of selected nodes. It defines an Appearance
039: * component object and a region of influence in which this
040: * AlternateAppearance node is active. An AlternateAppearance node
041: * also contains a list of Group nodes that specifies the hierarchical
042: * scope of this AlternateAppearance. If the scope list is empty,
043: * then the AlternateAppearance node has universe scope: all nodes
044: * within the region of influence are affected by this
045: * AlternateAppearance node. If the scope list is non-empty, then
046: * only those Leaf nodes under the Group nodes in the scope list are
047: * affected by this AlternateAppearance node (subject to the
048: * influencing bounds).
049: *
050: * <p>
051: * An AlternateAppearance node affects Shape3D and Morph nodes by
052: * overriding their appearance component with the appearance
053: * component in this AlternateAppearance node. Only those Shape3D and
054: * Morph nodes that explicitly allow their appearance to be
055: * overridden are affected. The AlternateAppearance node has no
056: * effect on Shape3D and Morph nodes that do not allow their
057: * appearance to be overridden.
058: *
059: * <p>
060: * If the regions of influence of multiple AlternateAppearance nodes
061: * overlap, the Java 3D system will choose a single alternate
062: * appearance for those objects that lie in the intersection. This is
063: * done in an implementation-dependent manner, but in general, the
064: * AlternateAppearance node that is "closest" to the object is chosen.
065: *
066: * @since Java 3D 1.2
067: */
068:
069: public class AlternateAppearance extends Leaf {
070: /**
071: * Specifies that this AlternateAppearance node allows read access to its
072: * influencing bounds and bounds leaf information.
073: */
074: public static final int ALLOW_INFLUENCING_BOUNDS_READ = CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_INFLUENCING_BOUNDS_READ;
075:
076: /**
077: * Specifies that this AlternateAppearance node allows write access to its
078: * influencing bounds and bounds leaf information.
079: */
080: public static final int ALLOW_INFLUENCING_BOUNDS_WRITE = CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_INFLUENCING_BOUNDS_WRITE;
081:
082: /**
083: * Specifies that this AlternateAppearance node allows read access to
084: * its appearance information.
085: */
086: public static final int ALLOW_APPEARANCE_READ = CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_APPEARANCE_READ;
087:
088: /**
089: * Specifies that this AlternateAppearance node allows write access to
090: * its appearance information.
091: * information.
092: */
093: public static final int ALLOW_APPEARANCE_WRITE = CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_APPEARANCE_WRITE;
094:
095: /**
096: * Specifies that this AlternateAppearance node allows read access
097: * to its scope information at runtime.
098: */
099: public static final int ALLOW_SCOPE_READ = CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_SCOPE_READ;
100:
101: /**
102: * Specifies that this AlternateAppearance node allows write access
103: * to its scope information at runtime.
104: */
105: public static final int ALLOW_SCOPE_WRITE = CapabilityBits.ALTERNATE_APPEARANCE_ALLOW_SCOPE_WRITE;
106:
107: // Array for setting default read capabilities
108: private static final int[] readCapabilities = {
109: ALLOW_INFLUENCING_BOUNDS_READ, ALLOW_APPEARANCE_READ,
110: ALLOW_SCOPE_READ };
111:
112: /**
113: * Constructs an AlternateAppearance node with default
114: * parameters. The default values are as follows:
115: *
116: * <ul>
117: * appearance : null<br>
118: * scope : empty (universe scope)<br>
119: * influencing bounds : null<br>
120: * influencing bounding leaf : null<br>
121: * </ul>
122: */
123: public AlternateAppearance() {
124: // Just use the defaults
125: // set default read capabilities
126: setDefaultReadCapabilities(readCapabilities);
127:
128: }
129:
130: /**
131: * Constructs an AlternateAppearance node with the specified appearance.
132: * @param appearance the appearance that is used for those nodes affected
133: * by this AlternateAppearance node.
134: */
135: public AlternateAppearance(Appearance appearance) {
136: // set default read capabilities
137: setDefaultReadCapabilities(readCapabilities);
138: ((AlternateAppearanceRetained) retained)
139: .initAppearance(appearance);
140: }
141:
142: /**
143: * Creates the retained mode AlternateAppearanceRetained object that this
144: * Alternate Appearance component object will point to.
145: */
146: void createRetained() {
147: this .retained = new AlternateAppearanceRetained();
148: this .retained.setSource(this );
149: }
150:
151: /**
152: * Sets the appearance of this AlternateAppearance node.
153: * This appearance overrides the appearance in those Shape3D and
154: * Morph nodes affected by this AlternateAppearance node.
155: * @param appearance the new appearance.
156: * @exception CapabilityNotSetException if appropriate capability is
157: * not set and this object is part of live or compiled scene graph
158: */
159: public void setAppearance(Appearance appearance) {
160: if (isLiveOrCompiled())
161: if (!this .getCapability(ALLOW_APPEARANCE_WRITE))
162: throw new CapabilityNotSetException(J3dI18N
163: .getString("AlternateAppearance0"));
164:
165: if (isLive())
166: ((AlternateAppearanceRetained) this .retained)
167: .setAppearance(appearance);
168: else
169: ((AlternateAppearanceRetained) this .retained)
170: .initAppearance(appearance);
171: }
172:
173: /**
174: * Retrieves the appearance from this AlternateAppearance node.
175: * @return the current appearance.
176: * @exception CapabilityNotSetException if appropriate capability is
177: * not set and this object is part of live or compiled scene graph
178: */
179: public Appearance getAppearance() {
180: if (isLiveOrCompiled())
181: if (!this .getCapability(ALLOW_APPEARANCE_READ))
182: throw new CapabilityNotSetException(J3dI18N
183: .getString("AlternateAppearance2"));
184:
185: return ((AlternateAppearanceRetained) this .retained)
186: .getAppearance();
187:
188: }
189:
190: /**
191: * Sets the AlternateAppearance's influencing region to the specified
192: * bounds.
193: * This is used when the influencing bounding leaf is set to null.
194: * @param region the bounds that contains the AlternateAppearance's
195: * new influencing region.
196: * @exception CapabilityNotSetException if appropriate capability is
197: * not set and this object is part of live or compiled scene graph
198: */
199: public void setInfluencingBounds(Bounds region) {
200: if (isLiveOrCompiled())
201: if (!this .getCapability(ALLOW_INFLUENCING_BOUNDS_WRITE))
202: throw new CapabilityNotSetException(J3dI18N
203: .getString("AlternateAppearance3"));
204:
205: if (isLive())
206: ((AlternateAppearanceRetained) this .retained)
207: .setInfluencingBounds(region);
208: else
209: ((AlternateAppearanceRetained) this .retained)
210: .initInfluencingBounds(region);
211: }
212:
213: /**
214: * Retrieves the AlternateAppearance node's influencing bounds.
215: * @return this AlternateAppearance's influencing bounds information
216: * @exception CapabilityNotSetException if appropriate capability is
217: * not set and this object is part of live or compiled scene graph
218: */
219: public Bounds getInfluencingBounds() {
220: if (isLiveOrCompiled())
221: if (!this .getCapability(ALLOW_INFLUENCING_BOUNDS_READ))
222: throw new CapabilityNotSetException(J3dI18N
223: .getString("AlternateAppearance4"));
224:
225: return ((AlternateAppearanceRetained) this .retained)
226: .getInfluencingBounds();
227: }
228:
229: /**
230: * Sets the AlternateAppearance's influencing region to the specified
231: * bounding leaf.
232: * When set to a value other than null, this overrides the influencing
233: * bounds object.
234: * @param region the bounding leaf node used to specify the
235: * AlternateAppearance node's new influencing region.
236: * @exception CapabilityNotSetException if appropriate capability is
237: * not set and this object is part of live or compiled scene graph
238: */
239: public void setInfluencingBoundingLeaf(BoundingLeaf region) {
240: if (isLiveOrCompiled())
241: if (!this .getCapability(ALLOW_INFLUENCING_BOUNDS_WRITE))
242: throw new CapabilityNotSetException(J3dI18N
243: .getString("AlternateAppearance3"));
244:
245: if (isLive())
246: ((AlternateAppearanceRetained) this .retained)
247: .setInfluencingBoundingLeaf(region);
248: else
249: ((AlternateAppearanceRetained) this .retained)
250: .initInfluencingBoundingLeaf(region);
251: }
252:
253: /**
254: * Retrieves the AlternateAppearance node's influencing bounding leaf.
255: * @return this AlternateAppearance's influencing bounding leaf information
256: * @exception CapabilityNotSetException if appropriate capability is
257: * not set and this object is part of live or compiled scene graph
258: */
259: public BoundingLeaf getInfluencingBoundingLeaf() {
260: if (isLiveOrCompiled())
261: if (!this .getCapability(ALLOW_INFLUENCING_BOUNDS_READ))
262: throw new CapabilityNotSetException(J3dI18N
263: .getString("AlternateAppearance4"));
264:
265: return ((AlternateAppearanceRetained) this .retained)
266: .getInfluencingBoundingLeaf();
267: }
268:
269: /**
270: * Replaces the node at the specified index in this
271: * AlternateAppearance node's
272: * list of scopes with the specified Group node.
273: * By default, AlternateAppearance nodes are scoped only by their
274: * influencing
275: * bounds. This allows them to be further scoped by a list of
276: * nodes in the hierarchy.
277: * @param scope the Group node to be stored at the specified index.
278: * @param index the index of the Group node to be replaced.
279: * @exception CapabilityNotSetException if appropriate capability is
280: * not set and this object is part of live or compiled scene graph
281: * @exception RestrictedAccessException if the specified group node
282: * is part of a compiled scene graph
283: */
284: public void setScope(Group scope, int index) {
285: if (isLiveOrCompiled())
286: if (!this .getCapability(ALLOW_SCOPE_WRITE))
287: throw new CapabilityNotSetException(J3dI18N
288: .getString("AlternateAppearance7"));
289:
290: if (isLive())
291: ((AlternateAppearanceRetained) this .retained).setScope(
292: scope, index);
293: else
294: ((AlternateAppearanceRetained) this .retained).initScope(
295: scope, index);
296: }
297:
298: /**
299: * Retrieves the Group node at the specified index from
300: * this AlternateAppearance node's list of scopes.
301: * @param index the index of the Group node to be returned.
302: * @return the Group node at the specified index.
303: * @exception CapabilityNotSetException if appropriate capability is
304: * not set and this object is part of live or compiled scene graph
305: */
306: public Group getScope(int index) {
307: if (isLiveOrCompiled())
308: if (!this .getCapability(ALLOW_SCOPE_READ))
309: throw new CapabilityNotSetException(J3dI18N
310: .getString("AlternateAppearance8"));
311:
312: return ((AlternateAppearanceRetained) this .retained)
313: .getScope(index);
314: }
315:
316: /**
317: * Inserts the specified Group node into this AlternateAppearance node's
318: * list of scopes at the specified index.
319: * By default, AlternateAppearance nodes are scoped only by their
320: * influencing
321: * bounds. This allows them to be further scoped by a list of
322: * nodes in the hierarchy.
323: * @param scope the Group node to be inserted at the specified index.
324: * @param index the index at which the Group node is inserted.
325: * @exception CapabilityNotSetException if appropriate capability is
326: * not set and this object is part of live or compiled scene graph
327: * @exception RestrictedAccessException if the specified group node
328: * is part of a compiled scene graph
329: */
330: public void insertScope(Group scope, int index) {
331: if (isLiveOrCompiled())
332: if (!this .getCapability(ALLOW_SCOPE_WRITE))
333: throw new CapabilityNotSetException(J3dI18N
334: .getString("AlternateAppearance9"));
335:
336: if (isLive())
337: ((AlternateAppearanceRetained) this .retained).insertScope(
338: scope, index);
339: else
340: ((AlternateAppearanceRetained) this .retained)
341: .initInsertScope(scope, index);
342: }
343:
344: /**
345: * Removes the node at the specified index from this AlternateAppearance
346: * node's
347: * list of scopes. If this operation causes the list of scopes to
348: * become empty, then this AlternateAppearance will have universe scope:
349: * all nodes
350: * within the region of influence will be affected by this
351: * AlternateAppearance node.
352: * @param index the index of the Group node to be removed.
353: * @exception CapabilityNotSetException if appropriate capability is
354: * not set and this object is part of live or compiled scene graph
355: * @exception RestrictedAccessException if the group node at the
356: * specified index is part of a compiled scene graph
357: */
358: public void removeScope(int index) {
359: if (isLiveOrCompiled())
360: if (!this .getCapability(ALLOW_SCOPE_WRITE))
361: throw new CapabilityNotSetException(J3dI18N
362: .getString("AlternateAppearance10"));
363:
364: if (isLive())
365: ((AlternateAppearanceRetained) this .retained)
366: .removeScope(index);
367: else
368: ((AlternateAppearanceRetained) this .retained)
369: .initRemoveScope(index);
370: }
371:
372: /**
373: * Returns an enumeration of this AlternateAppearance node's list
374: * of scopes.
375: * @return an Enumeration object containing all nodes in this
376: * AlternateAppearance node's list of scopes.
377: * @exception CapabilityNotSetException if appropriate capability is
378: * not set and this object is part of live or compiled scene graph
379: */
380: public Enumeration getAllScopes() {
381: if (isLiveOrCompiled())
382: if (!this .getCapability(ALLOW_SCOPE_READ))
383: throw new CapabilityNotSetException(J3dI18N
384: .getString("AlternateAppearance11"));
385:
386: return (Enumeration) ((AlternateAppearanceRetained) this .retained)
387: .getAllScopes();
388: }
389:
390: /**
391: * Appends the specified Group node to this AlternateAppearance node's
392: * list of scopes.
393: * By default, AlternateAppearance nodes are scoped only by their
394: * influencing
395: * bounds. This allows them to be further scoped by a list of
396: * nodes in the hierarchy.
397: * @param scope the Group node to be appended.
398: * @exception CapabilityNotSetException if appropriate capability is
399: * not set and this object is part of live or compiled scene graph
400: * @exception RestrictedAccessException if the specified group node
401: * is part of a compiled scene graph
402: */
403: public void addScope(Group scope) {
404: if (isLiveOrCompiled())
405: if (!this .getCapability(ALLOW_SCOPE_WRITE))
406: throw new CapabilityNotSetException(J3dI18N
407: .getString("AlternateAppearance12"));
408:
409: if (isLive())
410: ((AlternateAppearanceRetained) this .retained)
411: .addScope(scope);
412: else
413: ((AlternateAppearanceRetained) this .retained)
414: .initAddScope(scope);
415: }
416:
417: /**
418: * Returns the number of nodes in this AlternateAppearance node's list
419: * of scopes.
420: * If this number is 0, then the list of scopes is empty and this
421: * AlternateAppearance node has universe scope: all nodes within the
422: * region of
423: * influence are affected by this AlternateAppearance node.
424: * @return the number of nodes in this AlternateAppearance node's list
425: * of scopes.
426: * @exception CapabilityNotSetException if appropriate capability is
427: * not set and this object is part of live or compiled scene graph
428: */
429: public int numScopes() {
430: if (isLiveOrCompiled())
431: if (!this .getCapability(ALLOW_SCOPE_READ))
432: throw new CapabilityNotSetException(J3dI18N
433: .getString("AlternateAppearance11"));
434:
435: return ((AlternateAppearanceRetained) this .retained)
436: .numScopes();
437: }
438:
439: /**
440: * Retrieves the index of the specified Group node in this
441: * AlternateAppearance node's list of scopes.
442: *
443: * @param scope the Group node to be looked up.
444: * @return the index of the specified Group node;
445: * returns -1 if the object is not in the list.
446: * @exception CapabilityNotSetException if appropriate capability is
447: * not set and this object is part of live or compiled scene graph
448: *
449: * @since Java 3D 1.3
450: */
451: public int indexOfScope(Group scope) {
452: if (isLiveOrCompiled())
453: if (!this .getCapability(ALLOW_SCOPE_READ))
454: throw new CapabilityNotSetException(J3dI18N
455: .getString("AlternateAppearance8"));
456:
457: return ((AlternateAppearanceRetained) this .retained)
458: .indexOfScope(scope);
459: }
460:
461: /**
462: * Removes the specified Group node from this AlternateAppearance
463: * node's list of scopes. If the specified object is not in the
464: * list, the list is not modified. If this operation causes the
465: * list of scopes to become empty, then this AlternateAppearance
466: * will have universe scope: all nodes within the region of
467: * influence will be affected by this AlternateAppearance node.
468: *
469: * @param scope the Group node to be removed.
470: * @exception CapabilityNotSetException if appropriate capability is
471: * not set and this object is part of live or compiled scene graph
472: * @exception RestrictedAccessException if the specified group node
473: * is part of a compiled scene graph
474: *
475: * @since Java 3D 1.3
476: */
477: public void removeScope(Group scope) {
478: if (isLiveOrCompiled())
479: if (!this .getCapability(ALLOW_SCOPE_WRITE))
480: throw new CapabilityNotSetException(J3dI18N
481: .getString("AlternateAppearance10"));
482:
483: if (isLive())
484: ((AlternateAppearanceRetained) this .retained)
485: .removeScope(scope);
486: else
487: ((AlternateAppearanceRetained) this .retained)
488: .initRemoveScope(scope);
489: }
490:
491: /**
492: * Removes all Group nodes from this AlternateAppearance node's
493: * list of scopes. The AlternateAppearance node will then have
494: * universe scope: all nodes within the region of influence will
495: * be affected by this AlternateAppearance node.
496: *
497: * @exception CapabilityNotSetException if appropriate capability is
498: * not set and this object is part of live or compiled scene graph
499: * @exception RestrictedAccessException if any group node in this
500: * node's list of scopes is part of a compiled scene graph
501: *
502: * @since Java 3D 1.3
503: */
504: public void removeAllScopes() {
505: if (isLiveOrCompiled())
506: if (!this .getCapability(ALLOW_SCOPE_WRITE))
507: throw new CapabilityNotSetException(J3dI18N
508: .getString("AlternateAppearance10"));
509: if (isLive())
510: ((AlternateAppearanceRetained) this .retained)
511: .removeAllScopes();
512: else
513: ((AlternateAppearanceRetained) this .retained)
514: .initRemoveAllScopes();
515: }
516:
517: /**
518: * Copies all AlternateAppearance information from
519: * <code>originalNode</code> into
520: * the current node. This method is called from the
521: * <code>cloneNode</code> method which is, in turn, called by the
522: * <code>cloneTree</code> method.<P>
523: *
524: * @param originalNode the original node to duplicate.
525: * @param forceDuplicate when set to <code>true</code>, causes the
526: * <code>duplicateOnCloneTree</code> flag to be ignored. When
527: * <code>false</code>, the value of each node's
528: * <code>duplicateOnCloneTree</code> variable determines whether
529: * NodeComponent data is duplicated or copied.
530: *
531: * @exception RestrictedAccessException if this object is part of a live
532: * or compiled scenegraph.
533: *
534: * @see Node#duplicateNode
535: * @see Node#cloneTree
536: * @see NodeComponent#setDuplicateOnCloneTree
537: */
538: void duplicateAttributes(Node originalNode, boolean forceDuplicate) {
539: super .duplicateAttributes(originalNode, forceDuplicate);
540:
541: AlternateAppearanceRetained attr = (AlternateAppearanceRetained) originalNode.retained;
542: AlternateAppearanceRetained rt = (AlternateAppearanceRetained) retained;
543:
544: rt.initAppearance((Appearance) getNodeComponent(attr
545: .getAppearance(), forceDuplicate,
546: originalNode.nodeHashtable));
547:
548: rt.initInfluencingBounds(attr.getInfluencingBounds());
549:
550: Enumeration elm = attr.getAllScopes();
551: while (elm.hasMoreElements()) {
552: // this reference will set correctly in updateNodeReferences() callback
553: rt.initAddScope((Group) elm.nextElement());
554: }
555:
556: // correct value will set in updateNodeReferences
557: rt.initInfluencingBoundingLeaf(attr
558: .getInfluencingBoundingLeaf());
559:
560: }
561:
562: /**
563: * Callback used to allow a node to check if any nodes referenced
564: * by that node have been duplicated via a call to <code>cloneTree</code>.
565: * This method is called by <code>cloneTree</code> after all nodes in
566: * the sub-graph have been duplicated. The cloned Leaf node's method
567: * will be called and the Leaf node can then look up any node references
568: * by using the <code>getNewObjectReference</code> method found in the
569: * <code>NodeReferenceTable</code> object. If a match is found, a
570: * reference to the corresponding Node in the newly cloned sub-graph
571: * is returned. If no corresponding reference is found, either a
572: * DanglingReferenceException is thrown or a reference to the original
573: * node is returned depending on the value of the
574: * <code>allowDanglingReferences</code> parameter passed in the
575: * <code>cloneTree</code> call.
576: * <p>
577: * NOTE: Applications should <i>not</i> call this method directly.
578: * It should only be called by the cloneTree method.
579: *
580: * @param referenceTable a NodeReferenceTableObject that contains the
581: * <code>getNewObjectReference</code> method needed to search for
582: * new object instances.
583: * @see NodeReferenceTable
584: * @see Node#cloneTree
585: * @see DanglingReferenceException
586: */
587: public void updateNodeReferences(NodeReferenceTable referenceTable) {
588:
589: AlternateAppearanceRetained rt = (AlternateAppearanceRetained) retained;
590:
591: BoundingLeaf bl = rt.getInfluencingBoundingLeaf();
592:
593: if (bl != null) {
594: Object o = referenceTable.getNewObjectReference(bl);
595: rt.initInfluencingBoundingLeaf((BoundingLeaf) o);
596: }
597:
598: int num = rt.numScopes();
599: for (int i = 0; i < num; i++) {
600: rt.initScope((Group) referenceTable
601: .getNewObjectReference(rt.getScope(i)), i);
602: }
603: }
604:
605: /**
606: * Used to create a new instance of the node. This routine is called
607: * by <code>cloneTree</code> to duplicate the current node.
608: * @param forceDuplicate when set to <code>true</code>, causes the
609: * <code>duplicateOnCloneTree</code> flag to be ignored. When
610: * <code>false</code>, the value of each node's
611: * <code>duplicateOnCloneTree</code> variable determines whether
612: * NodeComponent data is duplicated or copied.
613: *
614: * @see Node#cloneTree
615: * @see Node#cloneNode
616: * @see Node#duplicateNode
617: * @see NodeComponent#setDuplicateOnCloneTree
618: */
619: public Node cloneNode(boolean forceDuplicate) {
620: AlternateAppearance app = new AlternateAppearance();
621: app.duplicateNode(this, forceDuplicate);
622: return app;
623: }
624: }
|