001: /*
002: * $RCSfile: ViewPlatformRetained.java,v $
003: *
004: * Copyright 1997-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.8 $
028: * $Date: 2008/02/28 20:17:33 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import javax.vecmath.*;
035: import java.util.ArrayList;
036:
037: /**
038: * ViewPlatform object (retained side)
039: */
040:
041: class ViewPlatformRetained extends LeafRetained {
042:
043: // different types of IndexedUnorderedSet that use in BehaviorStructure
044: static final int VP_IN_BS_LIST = 0;
045:
046: // total number of different IndexedUnorderedSet types
047: static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 1;
048:
049: /**
050: * This variable specifies the policy Java 3D will use in placing the
051: * user's eye point as a function of head position. The variable can
052: * contain one of NOMINAL_SCREEN, NOMINAL_HEAD, or NOMINAL_FEET.
053: */
054: int viewAttachPolicy = View.NOMINAL_HEAD;
055:
056: /**
057: * The list of views associated with this view platform.
058: * Use getViewList() to access this variable.
059: */
060: private ArrayList viewList = new ArrayList();
061:
062: /**
063: * Cached list of viewList for synchronization
064: */
065: private View views[] = null;
066:
067: // The locale that this node is decended from
068: Locale locale = null;
069:
070: // dirty flag for viewList
071: boolean viewListDirty = true;
072:
073: /**
074: * The current cached view platform transform (vworldToVpc) and
075: * its inverse (vpcToVworld).
076: */
077: Transform3D vworldToVpc = null;
078: Transform3D vpcToVworld = new Transform3D();
079:
080: /**
081: * The activation radius. The value is chosen so that when using a
082: * default screen scale and field of view, the entire view frustum
083: * is enclosed.
084: */
085:
086: /**
087: * Position used for placing this view platform.
088: */
089: BoundingSphere sphere = new BoundingSphere(new Point3d(0.0, 0.0,
090: 0.0), 62.0f);
091:
092: /**
093: * This is the cached bounding sphere used for the activation volume.
094: */
095: BoundingSphere schedSphere;
096: Point3d center = new Point3d();
097: final static Point3d zeroPoint = new Point3d();
098:
099: // Mask that indicates this ViewPlatformRetained's view dependence info. has changed,
100: // and CanvasViewCache may need to recompute the final view matries.
101: int vprDirtyMask = (View.VPR_VIEW_ATTACH_POLICY_DIRTY | View.VPR_VIEWPLATFORM_DIRTY);
102:
103: static final Object emptyObj[] = new Object[0];
104: static final Transform3D identity = new Transform3D();
105:
106: ViewPlatformRetained() {
107: this .nodeType = NodeRetained.VIEWPLATFORM;
108: localBounds = new BoundingBox();
109: ((BoundingBox) localBounds).setLower(1.0, 1.0, 1.0);
110: ((BoundingBox) localBounds).setUpper(-1.0, -1.0, -1.0);
111: IndexedUnorderSet.init(this , TOTAL_INDEXED_UNORDER_SET_TYPES);
112: schedSphere = (BoundingSphere) sphere.clone();
113: }
114:
115: /**
116: * Sets the coexistence center in virtual world policy.
117: * This setting determines how Java 3D places the
118: * user's eye point as a function of head position. The variable can
119: * contain one of NOMINAL_SCREEN, NOMINAL_HEAD, or NOMINAL_FEET.
120: * @param policy the new policy, one of NOMINAL_SCREEN, NOMINAL_HEAD,
121: * or NOMINAL_FEET
122: */
123: void setViewAttachPolicy(int policy) {
124: synchronized (this ) {
125: this .viewAttachPolicy = policy;
126: vprDirtyMask |= View.VPR_VIEW_ATTACH_POLICY_DIRTY;
127: }
128:
129: if (source != null && source.isLive()) {
130: repaint();
131: }
132: }
133:
134: void repaint() {
135: View views[] = getViewList();
136: for (int i = views.length - 1; i >= 0; i--) {
137: views[i].repaint();
138: }
139: }
140:
141: /**
142: * Returns the current coexistence center in virtual-world policy.
143: * @return one of: NOMINAL_SCREEN, NOMINAL_HEAD, or NOMINAL_FEET
144: */
145: int getViewAttachPolicy() {
146: return this .viewAttachPolicy;
147: }
148:
149: /**
150: * Set the ViewPlatform's activation radius
151: */
152: void setActivationRadius(float activationRadius) {
153: sphere.setRadius(activationRadius);
154:
155: if (source != null && source.isLive()) {
156: repaint();
157: }
158: // Notify behavior scheduler & RenderBin
159: if (source.isLive()) {
160: J3dMessage message = new J3dMessage();
161: message.type = J3dMessage.UPDATE_VIEWPLATFORM;
162: message.threads = J3dThread.UPDATE_RENDER
163: | J3dThread.UPDATE_BEHAVIOR;
164: message.universe = universe;
165: message.args[0] = this ;
166: message.args[1] = new Float(activationRadius);
167: VirtualUniverse.mc.processMessage(message);
168: } else {
169: schedSphere.setRadius(activationRadius);
170: }
171:
172: }
173:
174: /**
175: * Get the ViewPlatform's activation radius
176: */
177: float getActivationRadius() {
178: return (float) sphere.getRadius();
179: }
180:
181: /**
182: * This sets the view that is associated with this view platform.
183: */
184: void setView(View v) {
185: synchronized (viewList) {
186: if (!viewList.contains(v)) {
187: viewList.add(v);
188: }
189: viewListDirty = true;
190: }
191: }
192:
193: void removeView(View v) {
194: synchronized (viewList) {
195: if (viewList.contains(v)) {
196: viewList.remove(viewList.indexOf(v));
197: }
198: viewListDirty = true;
199: }
200: }
201:
202: Transform3D getVworldToVpc() {
203: if (vworldToVpc == null)
204: vworldToVpc = new Transform3D();
205: vworldToVpc.set(getCurrentLocalToVworld(null));
206: vworldToVpc.invert();
207: return vworldToVpc;
208: }
209:
210: Transform3D getVpcToVworld() {
211: vpcToVworld.set(getCurrentLocalToVworld(null));
212: return vpcToVworld;
213: }
214:
215: void evaluateViewPlatformTransform() {
216: // clear cache so that next time getVworldToVpc() can recompute
217: vworldToVpc = null;
218: }
219:
220: /**
221: * Evaluate the view platform transform by traversing *up* the tree from
222: * this ViewPlatform node, computing the composite model transform
223: * along the way. Because we are traversing bottom to top, we must
224: * multiply each TransformGroup's matrix on the left by the
225: * composite transform on the right (rather than the other way
226: * around as is usually done). Once we have the composite model
227: * transform for this ViewPlatform--the vpcToVworld transform--we
228: * simply invert it to get the vworldToVpc transform.
229: */
230: void evaluateInitViewPlatformTransform(NodeRetained node,
231: Transform3D trans) {
232: if (node instanceof TransformGroupRetained) {
233: Transform3D tmpTrans = new Transform3D();
234: TransformGroupRetained tgr = (TransformGroupRetained) node;
235: tgr.transform.getWithLock(tmpTrans);
236: trans.mul(tmpTrans, trans);
237: }
238:
239: NodeRetained parent = node.getParent();
240: if (parent != null) {
241: // Not at the top yet.
242: evaluateInitViewPlatformTransform(parent, trans);
243: }
244: }
245:
246: void evaluateInitViewPlatformTransform() {
247:
248: Transform3D lastLocalToVworld;
249:
250: synchronized (this ) {
251: lastLocalToVworld = getLastLocalToVworld();
252:
253: if (lastLocalToVworld.equals(identity)) {
254: // lastLocalToVworld not yet updated
255: // for Renderer viewCache when startup
256: evaluateInitViewPlatformTransform((NodeRetained) this ,
257: lastLocalToVworld);
258: }
259: }
260: }
261:
262: // This is invoke from BehaviorStructure
263: void updateActivationRadius(float radius) {
264: schedSphere.setCenter(zeroPoint);
265: schedSphere.setRadius(radius);
266: schedSphere.transform(getCurrentLocalToVworld(null));
267: }
268:
269: // This is invoke from BehaviorStructure when TransformGroup
270: // above this viewplatform changed
271: void updateTransformRegion() {
272: Transform3D tr = getCurrentLocalToVworld(null);
273: schedSphere.setCenter(zeroPoint);
274: schedSphere.transform(tr);
275: tr.transform(zeroPoint, center);
276: }
277:
278: /**
279: * This setLive routine first calls the superclass's method, then
280: * it evaluates the view platform transform, and then it activates
281: * all canvases that are associated with the attached view.
282: */
283: void setLive(SetLiveState s) {
284: View views[] = getViewList();
285:
286: for (int i = views.length - 1; i >= 0; i--) {
287: views[i].checkView();
288: }
289:
290: super .doSetLive(s);
291:
292: if (inBackgroundGroup) {
293: throw new IllegalSceneGraphException(J3dI18N
294: .getString("ViewPlatformRetained1"));
295: }
296:
297: if (inSharedGroup) {
298: throw new IllegalSharingException(J3dI18N
299: .getString("ViewPlatformRetained2"));
300: }
301:
302: if (s.viewLists != null) {
303: throw new IllegalSceneGraphException(J3dI18N
304: .getString("ViewPlatformRetained3"));
305: }
306: /*
307: if (false) {
308: System.err.println("setLive: vworldToVpc = ");
309: System.err.println(this.vworldToVpc);
310: System.err.println("setLive: vpcToVworld = ");
311: System.err.println(this.vpcToVworld);
312: }
313: */
314: this .locale = s.locale;
315:
316: if (s.transformTargets != null && s.transformTargets[0] != null) {
317: s.transformTargets[0].addNode(this , Targets.VPF_TARGETS);
318: s.notifyThreads |= J3dThread.UPDATE_TRANSFORM;
319: }
320: // process switch leaf
321: if (s.switchTargets != null && s.switchTargets[0] != null) {
322: s.switchTargets[0].addNode(this , Targets.VPF_TARGETS);
323: }
324: switchState = (SwitchState) s.switchStates.get(0);
325: s.nodeList.add(this );
326: s.notifyThreads |= (J3dThread.UPDATE_BEHAVIOR);
327: super .markAsLive();
328: for (int i = views.length - 1; i >= 0; i--) {
329: views[i].setUniverse(s.universe);
330: views[i].evaluateActive();
331: }
332:
333: universe.addViewPlatform(this );
334: s.traverseFlags |= NodeRetained.CONTAINS_VIEWPLATFORM;
335: }
336:
337: /**
338: * This clearLive routine first calls the superclass's method, then
339: * it deactivates all canvases that are associated with the attached
340: * view.
341: */
342: void clearLive(SetLiveState s) {
343: super .clearLive(s);
344: if (s.switchTargets != null && s.switchTargets[0] != null) {
345: s.switchTargets[0].addNode(this , Targets.VPF_TARGETS);
346: }
347:
348: View views[] = getViewList();
349: for (int i = views.length - 1; i >= 0; i--) {
350: views[i].evaluateActive();
351: }
352: s.nodeList.add(this );
353: if (s.transformTargets != null && s.transformTargets[0] != null) {
354: s.transformTargets[0].addNode(this , Targets.VPF_TARGETS);
355: s.notifyThreads |= J3dThread.UPDATE_TRANSFORM;
356:
357: }
358: s.notifyThreads |= (J3dThread.UPDATE_BEHAVIOR | J3dThread.SOUND_SCHEDULER);
359: universe.removeViewPlatform(this );
360: }
361:
362: /**
363: * Re-evaluate all View active status reference to this view
364: * platform. This procedure is called from RenderBin when switch
365: * above a view platform changed.
366: */
367: void reEvaluateView() {
368: View views[] = getViewList();
369:
370: for (int i = views.length - 1; i >= 0; i--) {
371: views[i].evaluateActive();
372: }
373: }
374:
375: /**
376: * Get a copy of cached view list
377: */
378: View[] getViewList() {
379: synchronized (viewList) {
380: if (viewListDirty) {
381: views = (View[]) viewList.toArray(new View[viewList
382: .size()]);
383: viewListDirty = false;
384: }
385: return views;
386: }
387: }
388:
389: /**
390: * Use by BehaviorStructure to determine whether current
391: * ViewPlatform is active or not.
392: */
393: boolean isActiveViewPlatform() {
394: View v[] = getViewList();
395: if (v != null) {
396: for (int i = 0; i < v.length; i++) {
397: if (v[i].active) {
398: return true;
399: }
400: }
401: }
402: return false;
403: }
404:
405: void processSwitchChanged() {
406: reEvaluateView();
407: }
408:
409: void compile(CompileState compState) {
410:
411: super .compile(compState);
412:
413: // keep the parent transform group. It's not worth
414: // to push the static transform here.
415: compState.keepTG = true;
416: }
417: }
|