001: /*
002: * $Header: /cvs/j3dfly/J3dFly/src/org/jdesktop/j3dfly/J3dFlyController.java,v 1.5 2007/05/02 22:06:32 paulby Exp $
003: *
004: * Sun Public License Notice
005: *
006: * The contents of this file are subject to the Sun Public License Version
007: * 1.0 (the "License"). You may not use this file except in compliance with
008: * the License. A copy of the License is available at http://www.sun.com/
009: *
010: * The Original Code is Java 3D(tm) Fly Through.
011: * The Initial Developer of the Original Code is Paul Byrne.
012: * Portions created by Paul Byrne are Copyright (C) 2002.
013: * All Rights Reserved.
014: *
015: * Contributor(s): Paul Byrne.
016: *
017: **/
018: package org.jdesktop.j3dfly;
019:
020: import com.sun.j3d.utils.scenegraph.io.NamedObjectException;
021: import com.sun.j3d.utils.scenegraph.io.SceneGraphStreamWriter;
022: import java.awt.Cursor;
023: import java.io.BufferedOutputStream;
024: import java.io.FileOutputStream;
025: import java.io.IOException;
026: import java.util.ArrayList;
027: import java.util.HashMap;
028:
029: import javax.swing.JFileChooser;
030: import javax.swing.JLabel;
031: import javax.swing.JComboBox;
032: import javax.swing.JOptionPane;
033: import javax.swing.SwingUtilities;
034: import javax.swing.ProgressMonitor;
035:
036: import java.net.URL;
037: import java.util.jar.Manifest;
038: import java.util.jar.JarFile;
039: import java.util.jar.Attributes;
040:
041: import javax.media.j3d.BranchGroup;
042: import javax.media.j3d.BoundingSphere;
043: import javax.media.j3d.Bounds;
044: import javax.media.j3d.TransformGroup;
045: import javax.media.j3d.View;
046: import javax.media.j3d.Transform3D;
047: import javax.media.j3d.BoundingSphere;
048: import javax.media.j3d.PolygonAttributes;
049: import javax.media.j3d.DirectionalLight;
050: import javax.media.j3d.Node;
051: import javax.media.j3d.ViewPlatform;
052:
053: import javax.vecmath.Point3d;
054: import javax.vecmath.Vector3d;
055: import javax.vecmath.Color3f;
056: import javax.vecmath.Vector3f;
057:
058: import com.sun.j3d.utils.behaviors.vp.ViewPlatformBehavior;
059: import com.sun.j3d.utils.behaviors.vp.OrbitBehavior;
060:
061: import org.jdesktop.j3dfly.utils.developmenttools.DevelopmentLocale;
062: import org.jdesktop.j3dfly.utils.loadercontrol.LoaderControl;
063: import org.jdesktop.j3dfly.utils.loadercontrol.LoaderControlListener;
064: import org.jdesktop.j3dfly.utils.loadercontrol.ManifestParser;
065: import org.jdesktop.j3dfly.utils.vpbehaviors.VPCollisionBehavior;
066: import org.jdesktop.j3dfly.utils.vpbehaviors.VPDefaultCollision;
067: import org.jdesktop.j3dfly.utils.vpbehaviors.SimpleSweptVolume;
068: import org.jdesktop.j3dfly.utils.vpbehaviors.ViewUtils;
069:
070: import org.jdesktop.j3d.utils.scenegraph.traverser.ChangePolygonAttributes;
071: import org.jdesktop.j3d.utils.scenegraph.traverser.ChangeTextureAttributes;
072: import org.jdesktop.j3d.utils.scenegraph.traverser.TreeScan;
073: import org.jdesktop.j3d.utils.scenegraph.traverser.ChangeMaterial;
074: import org.jdesktop.j3d.utils.scenegraph.traverser.NodeChangeProcessor;
075: import org.jdesktop.j3d.utils.scenegraph.traverser.BehaviorSetEnable;
076: import org.jdesktop.j3dfly.utils.loadercontrol.ExampleFileFilter;
077: import org.jdesktop.j3dfly.utils.loaderwrappers.J3fLoaderListener;
078: import org.jdesktop.j3dfly.utils.loaderwrappers.J3fLoader;
079: import org.jdesktop.j3dfly.utils.gui.StatsDialog;
080: import org.jdesktop.j3dfly.utils.gui.FloatDocument;
081: import org.jdesktop.j3dfly.utils.gui.WorkingDialog;
082: import org.jdesktop.j3dfly.utils.environment.J3dSky;
083:
084: import org.jdesktop.j3dfly.plugins.J3dFlyPlugin;
085: import org.jdesktop.j3dfly.namecontrol.NameControl;
086: import org.jdesktop.j3dfly.event.EventProcessor;
087: import org.jdesktop.j3dfly.event.FileLoadEvent;
088: import org.jdesktop.j3dfly.event.CollisionEnableEvent;
089: import org.jdesktop.j3dfly.event.ViewClipDistanceChangedEvent;
090: import org.jdesktop.j3dfly.event.DefaultLightingRequiredEvent;
091:
092: import com.sun.j3d.utils.scenegraph.io.SceneGraphFileWriter;
093:
094: import org.jdesktop.j3dfly.plugins.VPBehaviorPlugin;
095: import org.jdesktop.j3dfly.plugins.PluginJ3fData;
096:
097: import org.jdesktop.j3dfly.utils.gui.ErrorHandler;
098: import org.jdesktop.j3dfly.utils.gui.ErrorManager;
099:
100: /**
101: * The controller for J3dFly.
102: *
103: * TODO Move the collision elements of this package into a plugin.
104: *
105: * @author Paul Byrne
106: * @version $Id: J3dFlyController.java,v 1.5 2007/05/02 22:06:32 paulby Exp $
107: */
108: public class J3dFlyController extends javax.swing.JFrame implements
109: LoaderControlListener, J3fLoaderListener,
110: ManifestParser.ManifestListener {
111:
112: private static LoaderControl loaderControl = null;
113: private JFileChooser fileChooser = null;
114: private boolean collisionEnabled = false;
115: private boolean collisionCapabilitySet = false;
116: private VPDefaultCollision collisionControl = null;
117: private BoundingSphere bigBounds;
118:
119: private ArrayList graphs;
120:
121: private StatsDialog statsDialog = null;
122: private Cursor normalCursor;
123: private int showAllAxis;
124:
125: private boolean gotValidBounds = false;
126: private BoundingSphere worldBounds = null;
127: private J3dFlyContext context;
128:
129: private String fileExtension = "j3f";
130:
131: private String currentSceneName = null;
132:
133: /**
134: * The currently active view platform Behavior plugin
135: */
136: private VPBehaviorPlugin vpBehavior = null;
137:
138: /** Creates new form controlPanel */
139: public J3dFlyController(J3dFlyContext context) {
140: this .context = context;
141:
142: graphs = new ArrayList();
143:
144: bigBounds = new BoundingSphere(new Point3d(),
145: Double.POSITIVE_INFINITY);
146:
147: BranchGroup toolBG = context.getLocale().getHiddenBranchGraph();
148: if (toolBG == null) {
149: toolBG = new BranchGroup();
150: toolBG.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
151: toolBG.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
152: toolBG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
153: toolBG.setPickable(false);
154: context.getLocale().setHiddenBranchGraph(toolBG);
155: }
156:
157: if (loaderControl == null)
158: loaderControl = new LoaderControl();
159:
160: // This sets up the class loader which will be used by XMLDecoder to
161: // load plugins etc.
162: Thread.currentThread().setContextClassLoader(
163: loaderControl.getClassLoader());
164:
165: processLoaderManifests();
166:
167: J3fLoader.setJ3fLoaderListener(this );
168: J3fLoader.setClassLoader(loaderControl.getClassLoader());
169:
170: // Tell the IO system to use the Java3D super class objects for any
171: // user subclasses of Java3D objects whose class is not in the
172: // classpath when loading j3f files.
173: System.setProperty("j3d.io.UseSuperClassIfNoChildClass", "");
174:
175: // Use JPEG compression (which is the default) when saving
176: // images.
177: System.setProperty("j3d.io.ImageCompression", "None");
178:
179: }
180:
181: private void processLoaderManifests() {
182: // Cycle through all the classpath entries in the ClassLoader from
183: // loaderControl looking for jars.
184:
185: // For each jar process it's manifest looking for J3dFly plugins
186: URL[] urls = loaderControl.getClassLoader().getURLs();
187:
188: for (int i = 0; i < urls.length; i++)
189: if (urls[i].getFile().toLowerCase().endsWith(".jar")) {
190: try {
191: ManifestParser
192: .processMainAttributes(
193: new java.util.jar.JarFile(urls[i]
194: .getFile()),
195: new String[] { "J3dFly-Plugins" },
196: this );
197: } catch (java.io.IOException e) {
198: ErrorManager.getDefault().notify(e,
199: ErrorHandler.INFORMATIONAL,
200: "Error with jar " + urls[i]);
201: }
202: }
203:
204: }
205:
206: /**
207: * Listener for ManifestParser
208: */
209: public void foundManifestAttribute(String name, String value) {
210:
211: ClassLoader classLoader = loaderControl.getClassLoader();
212: java.io.InputStream in = classLoader.getResourceAsStream(value);
213:
214: if (in == null)
215: ErrorManager.getDefault().notify(null,
216: ErrorHandler.INFORMATIONAL,
217: "Error loading Loader Plugin " + value);
218: else {
219: System.out.println("Loader adding plugins " + name + " "
220: + value);
221: context.getPluginPreferenceControl().addLoaderPlugins(in,
222: context, classLoader);
223: }
224: }
225:
226: /**
227: * Display a Dialog (parented on parent) that allows the user
228: * to edit the properties of the current View Behavior
229: *
230: * If there is no behavior, or the behavior does not have an editor
231: * no action is taken
232: */
233: /*
234: public void editViewBehaviorProperties( java.awt.Frame parent ) {
235: if ( getVPBehavior() instanceof VPCollisionBehavior )
236: ((VPCollisionBehavior)getVPBehavior()).editParameters( parent );
237: }
238: */
239:
240: /**
241: * Return the current View Platform Behavior
242: */
243: private ViewPlatformBehavior getVPBehavior() {
244: return context.getJ3dFly().getUniverse().getViewingPlatform()
245: .getViewPlatformBehavior();
246: }
247:
248: /**
249: * Load a scene
250: *
251: * Presents a FileChooser to the user and allows a scene to be selected
252: *
253: * Returns the file loaded
254: */
255: public java.io.File loadScene() {
256: if (fileChooser == null) {
257: String currentDir = new String();
258: try {
259: currentDir = System.getProperty("user.dir");
260: } catch (SecurityException e) {
261: }
262: fileChooser = new JFileChooser(currentDir);
263: }
264: loaderControl.setFileFilter(fileChooser);
265:
266: int ret = fileChooser.showDialog(this , "Load Geometry");
267:
268: if (ret == JFileChooser.APPROVE_OPTION) {
269: loadGeometry(fileChooser.getSelectedFile());
270: currentSceneName = fileChooser.getSelectedFile().getName();
271: context.getJ3dFly().setFrameTitle(currentSceneName);
272: return fileChooser.getSelectedFile();
273: }
274:
275: return null;
276: }
277:
278: /**
279: * Load the scene from the specified file
280: */
281: public void loadScene(java.io.File file) {
282: loadGeometry(file);
283: currentSceneName = file.getName();
284: context.getJ3dFly().setFrameTitle(file.getName());
285: }
286:
287: public String getCurrentSceneName() {
288: return currentSceneName;
289: }
290:
291: /**
292: * Returns the file chooser
293: */
294: public JFileChooser getFileChooser() {
295: if (fileChooser == null) {
296: String currentDir = new String();
297: try {
298: currentDir = System.getProperty("user.dir");
299: } catch (SecurityException e) {
300: }
301: fileChooser = new JFileChooser(currentDir);
302: }
303:
304: return fileChooser;
305: }
306:
307: /**
308: * Allow the user to select a filename and save the scene.
309: *
310: * Universe must not be live when this method is called
311: *
312: * Returns the file saved
313: */
314: public java.io.File saveAsScene() {
315: return saveAsScene(false, false);
316: }
317:
318: public java.io.File saveAsScene(boolean asStream,
319: boolean coreClassesOnly) {
320: // Add your handling code here:
321: fileChooser = getFileChooser();
322:
323: ExampleFileFilter j3dFilter = new ExampleFileFilter();
324: j3dFilter.setDescription("J3dFly Files");
325: j3dFilter.addExtension(fileExtension);
326:
327: fileChooser.setFileFilter(j3dFilter);
328:
329: int ret = fileChooser.showDialog(this , "Save SceneGraph");
330:
331: java.io.File file = null;
332: if (ret == JFileChooser.APPROVE_OPTION) {
333: String filename = fileChooser.getSelectedFile()
334: .getAbsolutePath();
335:
336: String ext = filename.substring(filename.length() - 4,
337: filename.length());
338: if (!ext.equalsIgnoreCase("." + fileExtension))
339: filename = filename.concat("." + fileExtension);
340:
341: long start = System.currentTimeMillis();
342: file = new java.io.File(filename);
343:
344: if (asStream)
345: saveSceneGraphAsStream(file);
346: else
347: saveSceneGraph(file);
348: //System.out.println("Save Time "+(System.currentTimeMillis()-start));
349: }
350:
351: return file;
352: }
353:
354: /**
355: * Saves the scene is the specified file
356: *
357: * Universe must not be live when this method is called
358: */
359: public void saveScene(java.io.File file) {
360: saveSceneGraph(file);
361: }
362:
363: /**
364: * Write the branchgraphs to <code>file</code>
365: */
366: public void saveSceneGraph(java.io.File file) {
367: PluginJ3fData flyData = new PluginJ3fData();
368:
369: boolean wasLive = context.getLocale().getLive();
370: context.getLocale().setLive(false);
371:
372: context.getPluginPreferenceControl().savePluginFilePreferences(
373: flyData);
374:
375: try {
376: SceneGraphFileWriter writer = new SceneGraphFileWriter(
377: file, null, false, "Generated by J3dFly", flyData);
378: BranchGroup[] bgs = (BranchGroup[]) graphs
379: .toArray(new BranchGroup[1]);
380: for (int i = 0; i < bgs.length; i++) {
381: writer.writeBranchGraph(bgs[i]);
382: }
383:
384: // Preserve named objects
385: String[] scenes = context.getNameControl().getSceneNames();
386: for (int sc = 0; sc < scenes.length; sc++) {
387: String[] names = context.getNameControl()
388: .getObjectNames(scenes[sc]);
389: for (int nm = 0; nm < names.length; nm++)
390: try {
391: Object obj = context.getNameControl()
392: .getNamedObject(scenes[sc], names[nm]);
393: if (obj != null
394: && obj instanceof javax.media.j3d.SceneGraphObject)
395: writer
396: .addObjectName(
397: names[nm],
398: (javax.media.j3d.SceneGraphObject) obj);
399: else
400: System.out.println("ERROR " + names[nm]
401: + " object is null");
402: } catch (com.sun.j3d.utils.scenegraph.io.NamedObjectException e) {
403: e.printStackTrace();
404: System.out.println("Continuing.....");
405: }
406: }
407:
408: writer.close();
409: } catch (java.io.IOException e) {
410: JOptionPane.showMessageDialog(this , "Failed to save file",
411: "Error", JOptionPane.ERROR_MESSAGE);
412: } catch (com.sun.j3d.utils.scenegraph.io.UnsupportedUniverseException e2) {
413: e2.printStackTrace();
414: }
415:
416: context.getLocale().setLive(wasLive);
417: }
418:
419: public void saveSceneGraphAsStream(java.io.File file) {
420: boolean wasLive = context.getLocale().getLive();
421: context.getLocale().setLive(false);
422:
423: try {
424: BufferedOutputStream out = new BufferedOutputStream(
425: new FileOutputStream(file));
426: SceneGraphStreamWriter writer = new SceneGraphStreamWriter(
427: out);
428: BranchGroup[] bgs = (BranchGroup[]) graphs
429: .toArray(new BranchGroup[1]);
430: HashMap map = new HashMap();
431: for (int i = 0; i < bgs.length; i++) {
432: writer.writeBranchGraph(bgs[i], map);
433: }
434: writer.close();
435: out.close();
436: } catch (IOException ioe) {
437: JOptionPane.showMessageDialog(this , "Failed to save file",
438: "Error", JOptionPane.ERROR_MESSAGE);
439: ioe.printStackTrace();
440: ;
441: } catch (NamedObjectException noe) {
442: noe.printStackTrace();
443: }
444:
445: context.getLocale().setLive(wasLive);
446: }
447:
448: /**
449: * Write the branchgraphs to <code>file</code>
450: *
451: * Uses the old io system that ships with J3dFly, which will be removed
452: * from the distribution very soon.
453: */
454: // private void OldSaveSceneGraph( java.io.File file ) {
455: // J3dFlyData flyData = new J3dFlyData();
456: // //flyData.addProperty( "WarpSet", warpSet);
457: //
458: // try {
459: // com.sun.j3d.demos.utils.scenegraph.io.SceneGraphFileWriter writer = new com.sun.j3d.demos.utils.scenegraph.io.SceneGraphFileWriter( file , null, false, "Generated by J3dFly", flyData );
460: // BranchGroup[] bgs = (BranchGroup[])graphs.toArray( new BranchGroup[1] );
461: // for(int i=0; i<bgs.length; i++) {
462: // writer.writeBranchGraph( bgs[i] );
463: // }
464: //
465: // // Preserve named objects
466: // String[] scenes = context.getNameControl().getSceneNames();
467: // for( int sc=0; sc<scenes.length; sc++) {
468: // String[] names = context.getNameControl().getObjectNames( scenes[sc] );
469: // for( int nm=0; nm<names.length; nm++)
470: // try {
471: // Object obj = context.getNameControl().getNamedObject( scenes[sc], names[nm] );
472: // if (obj!=null)
473: // writer.addObjectName( names[nm], (javax.media.j3d.SceneGraphObject)obj );
474: // else
475: // System.out.println("ERROR "+names[nm]+" object is null");
476: // } catch( com.sun.j3d.demos.utils.scenegraph.io.NamedObjectException e ) {
477: // e.printStackTrace();
478: // System.out.println("Continuing.....");
479: // }
480: // }
481: //
482: // writer.close();
483: // } catch( java.io.IOException e ) {
484: // JOptionPane.showMessageDialog( this, "Failed to save file", "Error", JOptionPane.ERROR_MESSAGE );
485: // } catch( com.sun.j3d.demos.utils.scenegraph.io.UnsupportedUniverseException e2 ) {
486: // e2.printStackTrace();
487: // }
488: // }
489: /**
490: * Display a dialog to allow users to select loaders
491: */
492: public void configureLoaders(java.awt.Frame parent) {
493: loaderControl.showSelectionDialog(parent);
494: }
495:
496: /**
497: * Remove all geometry from the scenegraph and reset the universe
498: */
499: public void clearUniverse() {
500: // Add your handling code here:
501: BranchGroup bg;
502: context.getLocale().setLive(false);
503: context.getEventProcessor().postEvent(
504: new org.jdesktop.j3dfly.event.UniverseClearEvent());
505: for (int i = 0; i < graphs.size(); i++) {
506: bg = (BranchGroup) graphs.get(i);
507: context.getLocale().removeBranchGraph(bg);
508: }
509: graphs.clear();
510:
511: // TODO - statsDialog should listen for UniverseClearEvent
512: if (statsDialog != null)
513: statsDialog.calcGeometryStats((BranchGroup) null); // Clear the stats
514: context.getLocale().setLive(true);
515: }
516:
517: /**
518: * Return an array of all the BranchGraphs in the universe, if graphArray
519: * is not null and is the correct size it will be populated with the
520: * graphs and returned, otherwise a new array will be created and returned
521: */
522: public BranchGroup[] getBranchGraphs(BranchGroup[] graphArray) {
523: if (graphArray == null)
524: graphArray = new BranchGroup[] {};
525: return (BranchGroup[]) graphs.toArray(graphArray);
526: }
527:
528: /**
529: * Add a new Branch Graph to the universe
530: *
531: * This method also sets the ALLOW_DETACH capability bit on graph
532: * so it can be removed later if needed
533: */
534: public void addBranchGraph(BranchGroup graph) {
535: graph.setCapability(BranchGroup.ALLOW_DETACH);
536:
537: if (worldBounds == null)
538: worldBounds = (BoundingSphere) graph.getBounds();
539: else
540: worldBounds.combine(graph.getBounds());
541: gotValidBounds = true;
542:
543: context.getUniverse().getLocale().addBranchGraph(graph);
544: graphs.add(graph);
545: // TODO it should also send a bounds change event
546: }
547:
548: /**
549: * Remove a Branch Graph from the universe
550: */
551: public void removeBranchGraph(BranchGroup graph) {
552: context.getUniverse().getLocale().removeBranchGraph(graph);
553: int index = graphs.indexOf(graph);
554: if (index != -1)
555: graphs.remove(index);
556: else {
557: ErrorManager.getDefault()
558: .notify(
559: new RuntimeException(
560: "BranchGraph not in Universe"),
561: ErrorHandler.EXCEPTION);
562: }
563: gotValidBounds = false;
564:
565: }
566:
567: /**
568: * Enable/Disable collision detection for viewplatform behavior.
569: * If necessary set the capability bits in the scenegraph to
570: * enable picking of geometry which is how the collision detection is
571: * implemented
572: *
573: * @deprecated Use setCollisionEnabled
574: */
575: public void enableCollision(boolean enabled) {
576: setCollisionEnabled(enabled);
577: }
578:
579: /**
580: * Enable/Disable collision detection for viewplatform behavior.
581: * If necessary set the capability bits in the scenegraph to
582: * enable picking of geometry which is how the collision detection is
583: * implemented
584: */
585: public void setCollisionEnabled(boolean enabled) {
586: // Add your handling code here:
587: if (collisionEnabled == enabled)
588: return;
589:
590: collisionEnabled = enabled;
591:
592: if (!(getVPBehavior() instanceof VPCollisionBehavior))
593: return;
594:
595: if (collisionEnabled && !collisionCapabilitySet) {
596: //collisionControl = new VPDriveCollision();
597: collisionControl = new VPDefaultCollision();
598:
599: BranchGroup bg;
600: for (int i = 0; i < graphs.size(); i++) {
601: bg = (BranchGroup) graphs.get(i);
602: setCollisionCapabilityBits(bg);
603: }
604: collisionCapabilitySet = true;
605: collisionControl.setCollisionLocale(context.getUniverse()
606: .getLocale());
607: collisionControl.setVPSweptVolume(new SimpleSweptVolume());
608: ((VPCollisionBehavior) getVPBehavior())
609: .setCollisionControl(collisionControl);
610: }
611:
612: if (getVPBehavior() != null) {
613: ((VPCollisionBehavior) getVPBehavior())
614: .setCollisionEnabled(collisionEnabled);
615: }
616:
617: context.getEventProcessor().postEvent(
618: new CollisionEnableEvent(enabled));
619:
620: }
621:
622: /**
623: * Return true if Collision detection is enabled, false otherwise
624: */
625: public boolean isCollisionEnabled() {
626: return collisionEnabled;
627: }
628:
629: /**
630: * Change the collisionController to the new object.
631: * Copy the state from the old controller to the new
632: */
633: public void changeCollisionController(
634: VPDefaultCollision newController) {
635: VPDefaultCollision oldController = collisionControl;
636: collisionControl = newController;
637: collisionControl.setCollisionLocale(context.getUniverse()
638: .getLocale());
639:
640: if (oldController == null) {
641: collisionControl.setVPSweptVolume(new SimpleSweptVolume());
642: } else {
643: collisionControl.setVPSweptVolume(oldController
644: .getVPSweptVolume());
645: }
646: }
647:
648: public VPDefaultCollision getCollisionController() {
649: return collisionControl;
650: }
651:
652: private void setCollisionCapabilityBits(BranchGroup bg) {
653: context.getLocale().setLive(false);
654: NodeChangeProcessor proc = new NodeChangeProcessor() {
655: public boolean changeNode(Node node) {
656: com.sun.j3d.utils.picking.PickTool
657: .setCapabilities(
658: node,
659: com.sun.j3d.utils.picking.PickTool.INTERSECT_COORD);
660: return true;
661: }
662: };
663:
664: TreeScan.findNode(bg, javax.media.j3d.Shape3D.class, proc,
665: false, true);
666: context.getLocale().setLive(true);
667: }
668:
669: /**
670: * Set the ViewPlatform behavior
671: */
672: public void setVPBehavior(VPBehaviorPlugin plugin) {
673: if (vpBehavior == plugin)
674: return;
675:
676: if (vpBehavior != null)
677: vpBehavior.setActive(false);
678:
679: plugin.setActive(true);
680: vpBehavior = plugin;
681: }
682:
683: /**
684: * Move the view platform so that all geometry fit inside view frustum
685: *
686: * Axis must be one of the constant axis specified in ViewUtils.
687: *
688: * Return the eye Distance from the center of the Scene bounds
689: */
690: public double showAll(int axis) {
691: computeWorldBounds();
692: if (worldBounds == null)
693: return 0;
694:
695: return ViewUtils.setViewpoint(context.getUniverse()
696: .getViewingPlatform().getViewPlatformTransform(),
697: worldBounds, context.getUniverse().getViewer()
698: .getView().getFieldOfView(), axis);
699: }
700:
701: /**
702: * Show the stats Dialog
703: */
704: public void showStatsDialog(java.awt.Container parent) {
705: if (statsDialog == null) {
706: statsDialog = new StatsDialog(null,
707: ((DevelopmentLocale) context.getUniverse()
708: .getLocale()).getHiddenBranchGraph());
709: statsDialog.setLocationRelativeTo(parent);
710: statsDialog.setEnable(false);
711: statsDialog.show();
712: } else {
713: statsDialog.setEnable(false);
714: statsDialog.show();
715: }
716: context.getLocale().setLive(false);
717:
718: statsDialog.calcGeometryStats(getBranchGraphs(null));
719: context.getLocale().setLive(true);
720: statsDialog.setEnable(true);
721: }
722:
723: /**
724: * Ensures the global variable worldBounds is upto date
725: */
726: private void computeWorldBounds() {
727: if (graphs.size() == 0 || gotValidBounds)
728: return;
729:
730: boolean wasLive = context.getLocale().getLive();
731:
732: context.getLocale().setLive(false);
733: worldBounds = (BoundingSphere) ((BranchGroup) graphs.get(0))
734: .getBounds();
735: for (int i = 1; i < graphs.size(); i++) {
736: worldBounds.combine(((BranchGroup) graphs.get(i))
737: .getBounds());
738: }
739:
740: context.getLocale().setLive(wasLive);
741: gotValidBounds = true;
742: }
743:
744: public BoundingSphere getWorldBounds() {
745: computeWorldBounds();
746:
747: return worldBounds;
748: }
749:
750: /**
751: * Load some geometry from the specified file and add it to the
752: * existing scene graph
753: */
754: public void loadGeometry(java.io.File file) {
755: normalCursor = this .getCursor();
756: this .setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
757: WorkingDialog progressMonitor = new WorkingDialog(null);
758: progressMonitor.setLocationRelativeTo(null); // Put in center of screen
759: progressMonitor.setVisible(true);
760: try {
761: loaderControl.loadFile(file, this , progressMonitor);
762: } catch (org.jdesktop.j3dfly.utils.loadercontrol.UnsupportedFormatException ef) {
763: JOptionPane.showMessageDialog(SwingUtilities
764: .getAncestorOfClass(java.awt.Frame.class, this ),
765: "No Loader for File format", "Error",
766: JOptionPane.ERROR_MESSAGE);
767: this .setCursor(normalCursor);
768: progressMonitor.setVisible(false);
769: }
770: }
771:
772: /**
773: * Check if the graph contains any lights and if it needs lights
774: * If it does not have lights but requires them then ask the user if they
775: * would like to add some
776: *
777: * If autoAdd is true the lights are added without asking the user.
778: *
779: * Returns true if no changes made, returns false is scene graph updated
780: *
781: * If lightBG is not null, the lights will be added to it,
782: * otherwise they will be added in a new BranchGraph
783: *
784: * Scene graph must not be live
785: */
786: void checkForLights(boolean autoAdd) {
787: SceneGraphChecker checker = new SceneGraphChecker();
788: boolean needsLights = false;
789:
790: BranchGroup bg;
791: for (int i = 0; i < graphs.size(); i++) {
792: bg = (BranchGroup) graphs.get(i);
793:
794: needsLights |= checker.needsLights(bg);
795:
796: if (checker.getHasLights()) {
797: needsLights = false;
798: i = graphs.size(); // Abort loop
799: }
800: }
801:
802: if (needsLights)
803: context.getEventProcessor().postEvent(
804: new DefaultLightingRequiredEvent());
805: }
806:
807: /**
808: * Remove the file extension from str and return the new string
809: */
810: private String removeFileExtension(String str) {
811: int dot = str.lastIndexOf('.');
812:
813: if (dot == -1 || dot == 0)
814: return str;
815: else
816: return str.substring(0, dot);
817: }
818:
819: /**
820: * Callback from scene loader when load is complete
821: */
822: public void sceneLoaded(int status,
823: com.sun.j3d.loaders.Scene scene, int loaderID,
824: java.io.File file, Exception ex) {
825: if (status == LoaderControlListener.LOAD_FAILED) {
826: JOptionPane.showMessageDialog(this , "Error Loading file "
827: + file.getName(), "Error",
828: JOptionPane.ERROR_MESSAGE);
829: if (ex != null)
830: ex.printStackTrace();
831: this .setCursor(normalCursor);
832: return;
833: }
834:
835: if (collisionCapabilitySet) {
836: setCollisionCapabilityBits(scene.getSceneGroup());
837: }
838:
839: context.getNameControl().addObjectsFromFile(
840: removeFileExtension(file.getName()),
841: scene.getNamedObjects());
842:
843: context.getLocale().setLive(false);
844:
845: addBranchGraph(scene.getSceneGroup());
846:
847: gotValidBounds = false;
848:
849: context.getEventProcessor().postEvent(
850: new FileLoadEvent(file, scene.getSceneGroup()));
851: checkForLights(false);
852: if (statsDialog != null) {
853: statsDialog.calcGeometryStats((BranchGroup[]) graphs
854: .toArray(new BranchGroup[graphs.size()]));
855: }
856:
857: /*
858: // Show the bounds of the object just loaded
859: BranchGroup t = new BranchGroup();
860: org.jdesktop.j3d.utils.scenegraph.visualtools.ShowBoundsBehavior b = new org.jdesktop.j3d.utils.scenegraph.visualtools.ShowBoundsBehavior( t );
861: b.showBounds( (BranchGroup)graphs.get(0) );
862: universe.addBranchGraph( t );
863: */
864:
865: // If current Behavior is an OrbitBehavior reset the center of rotation
866: // This is a hack, OrbitBehavior should listen for bounds change events
867: // and update it's own center
868: // TODO remove hack
869: if (getVPBehavior() instanceof OrbitBehavior) {
870: computeWorldBounds();
871: if (worldBounds != null) {
872: Point3d center = new Point3d();
873: worldBounds.getCenter(center);
874: ((OrbitBehavior) getVPBehavior())
875: .setRotationCenter(center);
876: }
877: }
878:
879: context.getLocale().setLive(true);
880: this .setCursor(normalCursor);
881: }
882:
883: /**
884: * Callback for J3fLoaderListener
885: */
886: public void loadingJ3f(J3fLoader loader) {
887: Object data = null;
888: try {
889: data = loader.getFileUserData();
890: } catch (java.io.IOException e) {
891: }
892:
893: if (data instanceof J3dFlyData) {
894: // Legacy data from J3dFly 1.0, this data is no longer produced
895: // by J3dFly 2.0 and above. Instead PluginJ3fData is used
896: Object prop = ((J3dFlyData) data).getProperty("WarpSet");
897: if (prop != null) {
898: org.jdesktop.j3dfly.plugins.ViewingPlatformWarpPlugin plugin = (org.jdesktop.j3dfly.plugins.ViewingPlatformWarpPlugin) context
899: .getPluginPreferenceControl()
900: .getPlugin(
901: org.jdesktop.j3dfly.plugins.ViewingPlatformWarpPlugin.class);
902: if (plugin != null) {
903: // Merge this warp set with that from the previous file
904: plugin
905: .addWarpSet((org.jdesktop.j3dfly.warp.WarpSet) prop);
906: } else {
907: org.jdesktop.j3dfly.plugins.ViewingPlatformWarpPlugin.ViewingPlatformWarpPluginPreference pluginPref = new org.jdesktop.j3dfly.plugins.ViewingPlatformWarpPlugin.ViewingPlatformWarpPluginPreference();
908: try {
909: context.getPluginPreferenceControl()
910: .installFilePlugin(pluginPref, context);
911: plugin = (org.jdesktop.j3dfly.plugins.ViewingPlatformWarpPlugin) pluginPref
912: .getPlugin();
913: plugin
914: .addWarpSet((org.jdesktop.j3dfly.warp.WarpSet) prop);
915: } catch (Exception e) {
916: ErrorManager
917: .getDefault()
918: .notify(e, ErrorHandler.EXCEPTION,
919: "Ignoring error, Warps will not be added");
920: return;
921: }
922: }
923: }
924: } else if (data instanceof PluginJ3fData) {
925: context.getPluginPreferenceControl()
926: .loadPluginFilePreferences((PluginJ3fData) data);
927: }
928: }
929:
930: /**
931: * Returns the LoaderControl object used by J3dFly
932: */
933: public LoaderControl getLoaderControl() {
934: return loaderControl;
935: }
936:
937: /**
938: * Set the default file extension.
939: *
940: * @param extension string without the . ie j3f or j3s
941: */
942: public void setDefaultFileExtension(String extension) {
943: fileExtension = extension;
944: }
945:
946: }
|