View Javadoc

1   /* -------------------------------------------------------------------
2    * Java source file for the class SceneModeler
3    * 
4    * Copyright (c), 2003, Masahiro Takatsuka.
5    * All Rights Researved.
6    * 
7    * Original Author: Masahiro Takatsuka (masa@jbeans.net)
8    * $Author: takatsukam $
9    * 
10   * $Date: 2004/03/03 11:53:06 $
11   * 
12   * $Id: SceneModeler.java,v 1.3 2004/03/03 11:53:06 takatsukam Exp $
13   * 
14   * Reference:		Document no:
15   * ___				___
16   * 
17   * To Do:
18   * ___
19   * 
20  ------------------------------------------------------------------- */
21  
22  /* --------------------------- Package ---------------------------- */
23  package net.jbeans.j3d.modeler.scene;
24  
25  /* ------------------ Import classes (packages) ------------------- *//package-summary/html">class="comment"> ------------------ Import classes (packages) ------------------- *//package-summary.html">class="comment">/* ------------------ Import classes (packages) ------------------- *//package-summary.html">class="comment"> ------------------ Import classes (packages) ------------------- */
26  import java.io.*;
27  import java.lang.reflect.*;
28  import java.util.*;
29  import javax.media.j3d.*;
30  import javax.swing.event.*;
31  
32  import net.jbeans.j3d.event.*;
33  
34  import net.jbeans.bean.adapter.*;
35  import net.jbeans.lang.*;
36  import net.jbeans.util.debug.*;
37  
38  /*====================================================================
39                   Implementation of class SceneModeler                 
40  ====================================================================*/
41  /***
42   * SceneModeler is an abstract and super class of all modelers to create
43   * javax.media.j3d.BranchGroup object from data.
44   * 
45   * @version $Revision: 1.3 $
46   * @author Masahiro Takatsuka (masa@jbeans.net)
47   * @see Serializable
48   */
49  
50  public abstract class SceneModeler implements Serializable {
51  	private static final boolean DEBUG = Debug.getDebugFlag(SceneModeler.class);
52  
53  	/* ------------------------ not serialized ------------------------ */
54      transient protected EventListenerList sceneListeners = new EventListenerList();
55  	transient protected double[] bounds;
56  	transient protected double[] center;
57  
58  	/***
59  	 * A Vector object containing the scene graph(s) representing the scene.
60  	 */
61  	transient protected Vector scenes;
62  
63  	/***
64  	 * a null-constructor.
65  	 */
66  	public SceneModeler() {
67  		super();
68  		this.bounds = new double[6];
69  		this.bounds[0] = this.bounds[2] = this.bounds[4] = -1.0;
70  		this.bounds[1] = this.bounds[3] = this.bounds[5] = 1.0;
71  		this.center = new double[3];
72  		this.center[0] = this.center[1] = this.center[2] = 0.0;
73  		initialize();
74  	}
75  
76  	private void initialize() {
77  		this.sceneListeners = new EventListenerList();
78  		this.scenes = new Vector();
79  	}
80  
81  	protected abstract void modelScene();
82  	protected abstract void updateScene();
83  
84  	/***
85  	 * Construct a javax.media.j3d.Node object.
86  	 */
87  	protected void model() {
88  		modelScene();
89  		fireSceneCreated();
90  	}
91  
92  	/***
93  	 * Update a javax.media.j3d.BranchGroup object.
94  	*/
95    	protected void update() {
96  		updateScene();
97  		boolean needNotify = false;
98  		try {
99  			BranchGroup bg = getScene();
100 			if (bg == null) {
101 				if (DEBUG) {
102 					System.out.println("scene null.");
103 				}
104 				return;
105 			}
106   			if (bg.getParent() == null) {
107   				needNotify = true;
108   				if (DEBUG) {
109   					System.out.println("parent null.");
110   				}
111   			}
112 		} catch (RestrictedAccessException e) {
113 			if (DEBUG) {
114 				System.out.println("RestrictedAccessException.");
115 			}
116 			needNotify = false;
117 		}
118 		
119 		if (needNotify) {
120 			fireSceneCreated();
121 		}
122   	}
123 
124 	protected void clearScene() {
125 		detachScene();
126 		this.scenes.clear();
127 	}
128 	
129 	protected void setScene(BranchGroup bGroup) {
130 		addScene(0, bGroup);
131 	}
132 
133 	protected void addScene(BranchGroup bGroup) {
134 		this.scenes.add(this.scenes.size(), bGroup);
135 	}
136 
137 	protected void addScene(int index, BranchGroup bGroup) {
138 		bGroup.setCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
139 		bGroup.setCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);
140 		bGroup.setCapability(Node.ALLOW_BOUNDS_READ);
141 		bGroup.setCapability(Node.ALLOW_BOUNDS_WRITE);
142 		bGroup.setCapability(Node.ALLOW_COLLIDABLE_READ);
143 		bGroup.setCapability(Node.ALLOW_COLLIDABLE_WRITE);
144 		bGroup.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ);
145 		bGroup.setCapability(Node.ALLOW_PICKABLE_READ);
146 		bGroup.setCapability(Node.ALLOW_PICKABLE_WRITE);
147 		bGroup.setCapability(Node.ENABLE_COLLISION_REPORTING);
148 		bGroup.setCapability(Node.ENABLE_PICK_REPORTING);
149 		
150 		this.scenes.add(index, bGroup);
151 	}
152 	
153 	/***
154 	* Returns the current shape object.
155 	*/
156 	public BranchGroup getScene() {
157 		BranchGroup bg = null;
158 		if (this.scenes.size() > 0) {
159 			bg = (BranchGroup) this.scenes.get(0);
160 		}
161 		return bg;
162 	}
163 
164 	/***
165 	* Returns the current shape object.
166 	*/
167 	public BranchGroup[] getScenes() {
168 		return (BranchGroup[]) this.scenes.toArray(new BranchGroup[]{});
169 	}
170 	
171     /***
172      * Serialization methods
173      */
174     private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
175 		s.defaultReadObject();
176  		initialize();
177     }
178 
179     /***
180      * adds an GeometryListener to the shape
181      */
182     public void addSceneListener(SceneGraphObjectListener l) {
183         this.sceneListeners.add(SceneGraphObjectListener.class, l);
184     }
185 
186     /***
187      * removes an GeometryListener from the shape.
188      */
189     public void removeSceneListener(SceneGraphObjectListener l) {
190         this.sceneListeners.remove(SceneGraphObjectListener.class, l);
191 		/* the lister "l" might have a reference of this object.
192 		   so, remove it!
193 		*/
194 		if (l instanceof Proxy) {
195 			InvocationHandler handler = Proxy.getInvocationHandler(l);
196 			Object target = AdapterHandler.getTarget(handler);
197 			detachSceneFrom(target);
198 		}
199     }
200 
201 	private void  detachSceneFrom(Object target) {
202 		if (target != null) {
203 			Class[] argTypes = {null};
204 			for (int i = 0; i < this.scenes.size(); i++) {
205 				Object[] args = {this.scenes.get(i)};
206 				try {
207 					/*
208 					* SceneModeler normally be connected to BranchGroup,
209 					* Masahiro Takatsuka/2001-Oct-19
210 					*/
211 					if (target instanceof Group) {
212 						argTypes[0] = Node.class;
213 						ClassUtil.makeObjectPerform(target, "removeChild", args, argTypes);
214 					} else {
215 						/*
216 						* This is for case a user connected it to Renderer.
217 						* Masahiro Takatsuka/2001-Oct-19
218 						*/
219 						argTypes[0] = BranchGroup.class;
220 						ClassUtil.makeObjectPerform(target, "detachBranchGraph", args, argTypes);
221 					}
222 				} catch (Exception e) {
223 					if (DEBUG) {
224 						e.printStackTrace();
225 					}
226 				}
227 			}
228 		}
229 	}
230 	
231     /***
232      * Notify all listeners that have registered interest for
233      * notification on this event type.
234      */
235     private void fireSceneCreated() {
236         Object[] listeners = this.sceneListeners.getListenerList();
237         // Process the listeners last to first, notifying
238         // those that are interested in this event
239         for (int i = listeners.length - 2; i >= 0; i -= 2) {
240             if (listeners[i] == SceneGraphObjectListener.class) {
241                 // Lazily create the event:
242                 ((SceneGraphObjectListener)listeners[i+1]).objectCreated(new EventObject(this));
243             }
244         }
245     }
246 
247 	/***
248 	* detach the all BranchGroup in this.scenes from listeners.
249 	*/
250 	protected void detachScene() {
251         Object[] listeners = this.sceneListeners.getListenerList();
252 		Class[] argTypes = {BranchGroup.class};
253         for (int i = listeners.length - 2; i >= 0; i -= 2) {
254 			if (listeners[i] instanceof Proxy) {
255 				InvocationHandler handler = Proxy.getInvocationHandler(listeners[i]);
256 				Object target = AdapterHandler.getTarget(handler);
257 				detachSceneFrom(target);
258 			} else if (ClassUtil.respondsToMethod(listeners[i],
259 												  "detachBranchGraph",
260 												  argTypes)) {
261 				detachSceneFrom(listeners[i]);				
262 			}
263 		}
264 		for (int i = 0; i < this.scenes.size(); i++) {
265 			BranchGroup bg = (BranchGroup) this.scenes.get(i);
266 			if (bg != null && bg.isLive()) {
267 				bg.detach();
268 			}
269 		}
270 	}
271 
272 	
273 	public double[] getBounds() {
274 		double[] bounds = {-1.0,1.0, -1.0,1.0, -1.0,1.0};
275 		return bounds;
276 	}
277 
278 	/***
279 	 * Get the bounds for this Prop as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
280 	 */
281 	public void getBounds(double[] bounds) {
282 		getBounds();
283 		for (int i = 0; i < 6; i++) {
284 			bounds[i] = this.bounds[i];
285 		}
286 	}
287 
288 	public double[] getCenter() {
289 		getBounds();
290 		for (int i = 0; i < 3; i++) {
291 			this.center[i] = (this.bounds[2*i+1] + this.bounds[2*i]) / 2.0;
292 		}
293 		return this.center;
294 	}
295 
296 	public double getLength() {
297 		double diff, l = 0.0;
298 
299 		getBounds();
300 		for (int i = 0; i < 3; i++) {
301 			diff = this.bounds[2*i+1] - this.bounds[2*i];
302 			l += diff * diff;
303 		}
304 
305 		return Math.sqrt(l);
306 	}
307 }