1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
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
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
192
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
209
210
211 if (target instanceof Group) {
212 argTypes[0] = Node.class;
213 ClassUtil.makeObjectPerform(target, "removeChild", args, argTypes);
214 } else {
215
216
217
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
238
239 for (int i = listeners.length - 2; i >= 0; i -= 2) {
240 if (listeners[i] == SceneGraphObjectListener.class) {
241
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 }