001: /*
002: * $RCSfile: TransparencyOrderController.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.3 $
041: * $Date: 2007/02/09 17:17:01 $
042: * $State: Exp $
043: */
044:
045: package org.jdesktop.j3d.utils.scenegraph.transparency;
046:
047: import com.sun.j3d.utils.scenegraph.transparency.TransparencySortController;
048: import java.util.ArrayList;
049: import java.util.Enumeration;
050: import java.util.HashMap;
051: import javax.media.j3d.Behavior;
052: import javax.media.j3d.BoundingSphere;
053: import javax.media.j3d.BranchGroup;
054: import javax.media.j3d.GraphStructureChangeListener;
055: import javax.media.j3d.Group;
056: import javax.media.j3d.Locale;
057: import javax.media.j3d.Node;
058: import javax.media.j3d.Shape3D;
059: import javax.media.j3d.SharedGroup;
060: import javax.media.j3d.View;
061: import javax.media.j3d.VirtualUniverse;
062: import javax.media.j3d.WakeupCondition;
063: import javax.media.j3d.WakeupOnElapsedFrames;
064: import javax.vecmath.Point3d;
065: import org.jdesktop.j3d.utils.scenegraph.traverser.ProcessNodeInterface;
066: import org.jdesktop.j3d.utils.scenegraph.traverser.TreeScan;
067:
068: /**
069: * Provides the mechanisms required to support the TransparencyOrderedGroup
070: * node. This class must be instantiated and attached to the scene graph
071: * for the TransparencyOrderedGroup to function. This node can be attached
072: * anywhere in the graph as long it remains live. No children need to be added
073: * to this node.
074: * <br><br>
075: * The node could be attached thus
076: * <br>
077: * locale.addBranchGraph(new TransparencyOrderController(view));
078: *<br><br>
079: * Note : this feature is only supported for a single view at the moment.
080: *
081: * @param view The view on which Transparency sorting will take place.
082: *
083: * @author paulby
084: */
085: public class TransparencyOrderController extends BranchGroup {
086:
087: private static TransparencyOrderController controller = null;
088: private HashMap<Shape3D, Shape3DRecord> shapeMap = new HashMap();
089:
090: /**
091: * Create the TransparencyOrderedController
092: *
093: * The TransparencySortingPolicy of view will be set to TRANSPARENCY_SORT_GEOMETRY
094: */
095: public TransparencyOrderController(View view) {
096: if (controller != null)
097: throw new RuntimeException(
098: "TransparencyOrderering is only supported for a single view at this time");
099: controller = this ;
100: view
101: .setTransparencySortingPolicy(View.TRANSPARENCY_SORT_GEOMETRY);
102: TransparencySortController.setComparator(view,
103: new OrderingComparator());
104: this .addChild(new TogBehavior());
105: }
106:
107: static TransparencyOrderController getController() {
108: return controller;
109: }
110:
111: /**
112: * The tog child index for the graph that contains shape has changed. Update
113: * the internal structure to reflect this.
114: */
115: void adjustChildIndex(Shape3D shape3D, int indexAdjustment,
116: TransparencyOrderedGroup tog) {
117: Shape3DRecord record = shapeMap.get(shape3D);
118: boolean done = false;
119:
120: for (int i = 0; i < record.togs.length && !done; i++) {
121: //System.out.println("record.togs "+record.togs[i]);
122: if (record.togs[i] == tog) {
123: record.childIndicies[i] += indexAdjustment;
124: //System.out.println("Adjust child index of "+shape3D+" to "+record.childIndicies[i]);
125: done = true;
126: }
127: }
128: }
129:
130: /**
131: * The comparitor used to determine the rendering order of two shapes.
132: *
133: * Determine the order in which s1 and s2 should be rendered
134: *
135: * @ returns -1 if s2 should be rendered first, 1 if s1 should be rendered first and
136: * 0 if the shapes share the same TransparencyOrderedGroup or don't have a
137: * common TransparencyOrderedGroup parent
138: */
139: int compare(Shape3D s1, Shape3D s2) {
140: Shape3DRecord r1 = shapeMap.get(s1);
141: Shape3DRecord r2 = shapeMap.get(s2);
142:
143: TransparencyOrderedGroup tog = null;
144: int i;
145:
146: if (r1 == null || r2 == null) {
147: System.err
148: .println("SEVERE : Unknown Shape in TransparencyOrderController.compare "
149: + s1 + " " + s2);
150: return 0;
151: }
152:
153: // Find common TOG (if any)
154: for (i = Math.min(r1.togs.length, r2.togs.length) - 1; i >= 0
155: && tog == null; i--) {
156: //System.out.println(i+" "+r1.togs[i]+" "+r2.togs[i]);
157: if (r1.togs[i] == r2.togs[i]) {
158: tog = r1.togs[i];
159: }
160: }
161:
162: //System.out.println("Here "+s1.getName()+" "+s2.getName()+" "+r1.togs.length+" "+r2.togs.length+" tog "+tog);
163:
164: if (tog == null)
165: return 0;
166:
167: return tog.getRenderingOrderForChild(r2.childIndicies[i + 1])
168: - tog
169: .getRenderingOrderForChild(r1.childIndicies[i + 1]);
170: }
171:
172: class Shape3DRecord {
173: Shape3D shape;
174: TransparencyOrderedGroup[] togs; // Togs between root and this shape
175: int[] childIndicies; // Index in Tog of the graph containing this shape
176:
177: public Shape3DRecord(Shape3D shape, Object parent) {
178: this .shape = shape;
179: //System.out.println("Shape "+shape);
180: findTogs(shape, 0, parent);
181: }
182:
183: /**
184: * Traverse up the graph from node recording all Togs that are
185: * a parent
186: */
187: private void findTogs(Node node, int depth, Object graphParent) {
188: int nextIndex = 0;
189: Node parent = node.getParent();
190: int childIndexInParent = -1;
191:
192: if (parent == null && graphParent != null) {
193: if (graphParent instanceof Node) {
194: parent = (Node) graphParent;
195: // children are always added as the last child
196: // (because insertChild and setChild are not supported).
197: if (parent instanceof TransparencyOrderedGroup)
198: childIndexInParent = ((Group) parent)
199: .numChildren();
200: }
201: graphParent = null;
202: } else if (parent instanceof TransparencyOrderedGroup)
203: childIndexInParent = ((Group) parent)
204: .indexOfChild(node);
205:
206: //System.out.println("Node "+node+" parent "+parent+" depth "+depth);
207: if (parent != null) {
208: if (parent instanceof SharedGroup) {
209: throw new RuntimeException(
210: "TransparencySort utility does not support SharedGroups");
211: } else if (parent instanceof TransparencyOrderedGroup) {
212: findTogs(parent, depth + 1, graphParent);
213: } else
214: findTogs(parent, depth, graphParent);
215: } else {
216: //System.out.println("Reached Locale "+depth);
217: togs = new TransparencyOrderedGroup[depth];
218: childIndicies = new int[depth];
219: }
220:
221: if (parent instanceof TransparencyOrderedGroup) {
222: //System.out.println("togs["+(togs.length-depth-1)+"] = "+parent+" childIndex "+childIndexInParent);
223: togs[togs.length - depth - 1] = (TransparencyOrderedGroup) parent;
224: childIndicies[togs.length - depth - 1] = childIndexInParent;
225: }
226:
227: }
228: }
229:
230: /**
231: * Behavior for initialisation and to add the required
232: * frame delay between removeChild of the graph and the
233: * actual removal of Shapes from the RenderBin
234: */
235: class TogBehavior extends Behavior implements
236: GraphStructureChangeListener {
237: private WakeupCondition wakeup = new WakeupOnElapsedFrames(0,
238: false);
239: private ArrayList<Shape3D> currentFrameRemoveList = new ArrayList();
240: private ArrayList<Shape3D> lastFrameRemoveList = new ArrayList(
241: 1);
242:
243: public void initialize() {
244: shapeMap.clear();
245:
246: // Find the universe and attach the graph change listener
247: getLocale().getVirtualUniverse()
248: .addGraphStructureChangeListener(this );
249:
250: // Traverse the entire universe and note all Shape3Ds that are
251: // currently attached
252: Enumeration en = getLocale().getAllBranchGraphs();
253: while (en.hasMoreElements())
254: graphAdded(getLocale(), (BranchGroup) en.nextElement());
255:
256: setSchedulingBounds(new BoundingSphere(new Point3d(),
257: Double.POSITIVE_INFINITY));
258: wakeupOn(wakeup);
259: }
260:
261: public synchronized void processStimulus(Enumeration e) {
262: if (lastFrameRemoveList != null)
263: for (Shape3D s : lastFrameRemoveList)
264: shapeMap.remove(s);
265:
266: lastFrameRemoveList = currentFrameRemoveList;
267: currentFrameRemoveList = new ArrayList();
268: wakeupOn(wakeup);
269: }
270:
271: private synchronized void graphAdded(final Object parent,
272: BranchGroup child) {
273: TreeScan.findNode(child, Shape3D.class,
274: new ProcessNodeInterface() {
275: public boolean processNode(Node node) {
276: //System.out.println("Adding Shape "+node);
277: shapeMap.put((Shape3D) node,
278: new Shape3DRecord((Shape3D) node,
279: parent));
280:
281: // Make sure added item is not on remove list
282: currentFrameRemoveList
283: .remove((Shape3D) node);
284: lastFrameRemoveList.remove((Shape3D) node);
285:
286: return true;
287: }
288:
289: }, false, true);
290: }
291:
292: private synchronized void graphRemoved(BranchGroup child) {
293: TreeScan.findNode(child, Shape3D.class,
294: new ProcessNodeInterface() {
295: public boolean processNode(Node node) {
296: Object ret = currentFrameRemoveList
297: .add((Shape3D) node);
298:
299: //System.out.println("Removed "+node);
300: if (ret == null)
301: throw new RuntimeException(
302: "Unknown Shape3D found during graphRemoval");
303:
304: return true;
305: }
306:
307: }, false, true);
308: }
309:
310: public void branchGroupAdded(java.lang.Object parent,
311: BranchGroup child) {
312: graphAdded(parent, child);
313: }
314:
315: public void branchGroupMoved(java.lang.Object oldParent,
316: java.lang.Object newParent, BranchGroup child) {
317: // Add will replace existing entry
318: graphAdded(newParent, child);
319: }
320:
321: public void branchGroupRemoved(java.lang.Object parent,
322: BranchGroup child) {
323: graphRemoved(child);
324: }
325: }
326: }
|