> From: Juergen Neubauer <[EMAIL PROTECTED]> > using the Vrml97Viewer from the examples that came with the > vj3d0.90.2.src [...] > > My question is about the navigation in the examine-mode. > Is it somehow possible to separate the navigation from the object view ? > > The problem: > The zoom is always along the z-axis of the object, not along the actual > view-axis. > (So, if the object is rotated or looked at from the x-axis, the zoom is > still along the z-axis...) The problem here is that MouseZoom is really MouseTranslateZ. That is, MouseTranslate does XY translation and MouseZoom does Z translation, which makes the object larger or smaller in a perspective view aligned with the Z axis. The fix is to replace the MouseZoom behavior with a MouseScale behavior. Attached below is a start. It still isn't perfect, since the object is not scaled/rotated around the origin, but its better than the MouseZoom behavior. I'll see if I can improve on this sometime soon, Doug Gehringer Sun Microsystems
/* * %Z%%M% %I% %E% %U% * * Copyright (c) 1996-1999 Sun Microsystems, Inc. All Rights Reserved. * * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use, * modify and redistribute this software in source and binary code form, * provided that i) this copyright notice and license appear on all copies of * the software; and ii) Licensee does not utilize the software in a manner * which is disparaging to Sun. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * This software is not designed or intended for use in on-line control of * aircraft, air traffic, aircraft navigation or aircraft communications; or in * the design, construction, operation or maintenance of any nuclear * facility. Licensee represents and warrants that it will not use or * redistribute the Software for such purposes. * * @Author: Doug Gehringer * @Author: Rick Goldberg */ // A Frame which creates a Canvas3D and a VrmlLoader and passes a URL to // the loader // TODO: make into an applet import java.io.File; import java.io.IOException; import java.awt.*; import java.awt.event.*; import java.util.Enumeration; import java.util.Hashtable; import java.net.URL; import javax.media.j3d.*; import javax.vecmath.*; import com.sun.j3d.utils.behaviors.mouse.*; import com.sun.j3d.utils.geometry.Sphere; import com.sun.j3d.loaders.vrml97.VrmlLoader; import com.sun.j3d.loaders.vrml97.VrmlScene; import vrml.BaseNode; import com.sun.j3d.loaders.vrml97.node.Viewpoint; //import TreePrinter; public class Vrml97Viewer extends Frame implements ActionListener, ItemListener, MotionNotifierInterface { Canvas3D canvas; VirtualUniverse universe; Locale locale; View view; String urlString; VrmlLoader loader; Viewpoint[] fileViewpoints = null; TransformGroup[] fileVpWorldTrans; TransformGroup[] fileVpOrientTrans; TransformGroup[] fileVpTrans; ViewPlatform[] fileVp; BranchGroup objRoot; BoundingSphere objBounds = null; BranchGroup vpRoot; BranchGroup browserGroup; DirectionalLight headLight; AmbientLight ambLight; ViewPlatform vp ; TransformGroup vpTrans, prevVpTrans; TransformGroup vpWorldTrans, vpOrientTrans; TransformGroup objVpObjectTrans; TransformGroup objVpWorldTrans[] = new TransformGroup[NUM_OBJ_VIEWS]; TransformGroup objVpOrientTrans[] = new TransformGroup[NUM_OBJ_VIEWS]; TransformGroup objVpTrans[] = new TransformGroup[NUM_OBJ_VIEWS]; ViewPlatform objVp[] = new ViewPlatform[NUM_OBJ_VIEWS]; BoundingSphere browserBounds; float vpFieldOfView, vpFrontClip, vpBackClip; float objVpFieldOfView, objVpFrontClip; float objVpBackClip; int viewMode = EXAMINE; TextField gotoUrl; Panel panel; Label label; FileDialog fd; String filename; String pathname; MenuBar mb; Menu m; Menu fileVpMenu; Menu objVpMenu; MenuItem mi; CheckboxMenuItem hlCheck; File file; WindowListener wl; int initVp = OBJ_VIEW_PLUS_Z; String fileVpAction = "setFileVp "; String objVpAction = "setObjVp "; String modeAction = "setMode "; String resetViewpoint = "Reset Viewpoint"; Transform3D identity = new Transform3D(); NumFormat numFormat = new NumFormat(); boolean fileLoaded = false; boolean debug; boolean timing; boolean loadOnly; int numTris; boolean startupTiming; int startupCount; int startupFrames = 5; int numFrames = 0; long postTime; long baseTime = System.currentTimeMillis(); //TreePrinter tp = new TreePrinter(); static final int AMB_LIGHT = 0; static final int DIR_LIGHT = 1; static final int BEHAVIOR = 2; static final int NUM_SLOTS = 3; static final int EXAMINE = 1; static final int FLY = 2; static final int FILE_VIEW = -1; static final int OBJ_VIEW_PLUS_X = 0; static final int OBJ_VIEW_PLUS_Y = 1; static final int OBJ_VIEW_PLUS_Z = 2; static final int NUM_OBJ_VIEWS = 3; Vrml97Viewer(String initURL) { debug = Boolean.getBoolean("debug"); timing = Boolean.getBoolean("timing"); loadOnly = Boolean.getBoolean("loadOnly"); urlString = initURL; if (!urlString.endsWith(".wrl") ) { pathname = urlString; urlString +="interp.wrl"; } else { int lastSlash = urlString.lastIndexOf('/'); if (lastSlash > 0) { pathname = urlString.substring(0, lastSlash+1); } } //System.out.println("pathname = " + pathname); // menus mb = new MenuBar(); m = new Menu("File"); mi = new MenuItem("Open"); mi.addActionListener(this); m.add(mi); mi = new MenuItem("Exit"); mi.addActionListener(this); m.add(mi); mb.add(m); m = new Menu("View"); fileVpMenu = new Menu("File Viewpoint"); m.add(fileVpMenu); objVpMenu = new Menu("Object Viewpoint"); mi = new MenuItem("Object from +X"); mi.addActionListener(this); mi.setActionCommand(objVpAction + OBJ_VIEW_PLUS_X); //objVpMenu.add(mi); mi = new MenuItem("Object from +Y"); mi.addActionListener(this); mi.setActionCommand(objVpAction + OBJ_VIEW_PLUS_Y); //objVpMenu.add(mi); mi = new MenuItem("Object from +Z"); mi.addActionListener(this); mi.setActionCommand(objVpAction + OBJ_VIEW_PLUS_Z); objVpMenu.add(mi); m.add(objVpMenu); mi = new MenuItem(resetViewpoint); mi.addActionListener(this); m.add(mi); mi = new MenuItem("WorldInfo"); mi.addActionListener(this); m.add(mi); mb.add(m); m = new Menu("Mode"); mi = new MenuItem("Examine"); mi.addActionListener(this); mi.setActionCommand(modeAction + EXAMINE); m.add(mi); mi = new MenuItem("Fly"); mi.setActionCommand(modeAction + FLY); mi.addActionListener(this); m.add(mi); mb.add(m); m = new Menu("Options"); hlCheck = new CheckboxMenuItem("Headlight", true); hlCheck.addItemListener(this); m.add(hlCheck); mb.add(m); m = new Menu("Info"); mi = new MenuItem("About"); mi.addActionListener(this); m.add(mi); mb.add(m); fd = new FileDialog(this,"Visit WRL",FileDialog.LOAD); fd.setDirectory("."+File.separator+"parts"); setMenuBar(mb); loader = new VrmlLoader(); } public void actionPerformed(ActionEvent evt) { if(evt.getSource().equals(gotoUrl)){ urlString = gotoUrl.getText(); gotoUrl(urlString); } else if (evt.getSource() instanceof MenuItem) { String arg = evt.getActionCommand(); if (arg.equals("Open")) { fd.show(); gotoUrl.setText(pathname+fd.getFile()); gotoUrl(pathname+fd.getFile()); } else if (arg.equals("Exit")) { if (timing) { outputTiming(); } System.exit(0); } else if (arg.startsWith(fileVpAction)) { String indexString = arg.substring(fileVpAction.length()); int index = Integer.valueOf(indexString).intValue(); setFileViewpoint(index); } else if (arg.startsWith(objVpAction)) { String indexString = arg.substring(objVpAction.length()); int index = Integer.valueOf(indexString).intValue(); setObjViewpoint(index); } else if (arg.equals(resetViewpoint)) { resetViewpoint(); } else if (arg.startsWith(modeAction)) { String indexString = arg.substring(modeAction.length()); int index = Integer.valueOf(indexString).intValue(); setMode(index); } else { System.out.println("Unknown action: " + arg); } } } public void itemStateChanged(ItemEvent evt) { if (evt.getItem().equals("Headlight")) { setHeadlight(hlCheck.getState()); } else { System.out.println("Unknown item changed: " + evt); } } // This is the normal UniverseBuilder code, except that the ViewPlatform // will only be used if VRML doesn't define one void setupJ3D(Canvas3D canvas) { // Establish an unnamed virtual universe, with a single hi-res Locale universe = new VirtualUniverse(); locale = new Locale(universe); // Create a PhysicalBody and Physical Environment object PhysicalBody body = new PhysicalBody(); PhysicalEnvironment environment = new PhysicalEnvironment(); // Create a View and attach the Canvas3D and the physical // body and environment to the view. view = new View(); view.addCanvas3D(canvas); view.setPhysicalBody(body); view.setPhysicalEnvironment(environment); // Create a branch group node for the default view platform vpRoot = new BranchGroup(); vpRoot.setCapability(BranchGroup.ALLOW_CHILDREN_READ); // This is the stuff that the browser needs to have in the same // place as the view platform. It will get added to the view platform // group when a view is selected browserGroup = new BranchGroup(); browserGroup.setCapability(BranchGroup.ALLOW_DETACH); browserGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ); browserGroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE); setSize(browserGroup, NUM_SLOTS); BoundingSphere lightBounds = new BoundingSphere(new Point3d(), Double.MAX_VALUE); ambLight = new AmbientLight(true, new Color3f(0.2f, 0.2f, 0.2f)); ambLight.setInfluencingBounds(lightBounds); ambLight.setCapability(Light.ALLOW_STATE_WRITE); browserGroup.setChild(ambLight, AMB_LIGHT); headLight = new DirectionalLight(); headLight.setColor(new Color3f(0.8f, 0.8f, 0.8f)); headLight.setCapability(Light.ALLOW_STATE_WRITE); headLight.setInfluencingBounds(lightBounds); browserGroup.setChild(headLight, DIR_LIGHT); // initialize the default view tree. These are predefined views // which display the whole object along each of the axes. // The Object transform is used to scale and translate the object so // it's BoundingSphere is at the origin with radius=1 in the View // space. The World transform is used to tranform the "world" // relative to the view (examine mode). The Orient tranform is used // to set the initial placement of the view (set by the VRML fields // for VRML Viewpoints and initialzed here for obj views) and the // VpTrans is the transform from the initial view platform orientation // made by the browser objVpFieldOfView = .785398f; objVpFrontClip = 0.01f; objVpBackClip = 30.0f; double eyeDist = 1.1 / Math.tan(objVpFieldOfView/ 2.0); Point3d origin = new Point3d(); Point3d offset = new Point3d(); Vector3d up = new Vector3d(); Transform3D eyeTrans = new Transform3D(); objVpObjectTrans = new TransformGroup(); objVpObjectTrans.setCapability(vpTrans.ALLOW_TRANSFORM_READ); objVpObjectTrans.setCapability(vpTrans.ALLOW_TRANSFORM_WRITE); objVpObjectTrans.setCapability(Group.ALLOW_CHILDREN_READ); objVpObjectTrans.setCapability(Group.ALLOW_CHILDREN_WRITE); objVpObjectTrans.setCapability(Group.ALLOW_CHILDREN_EXTEND); for (int i = 0; i < NUM_OBJ_VIEWS; i++) { objVpWorldTrans[i] = new TransformGroup(); objVpWorldTrans[i].setCapability(vpTrans.ALLOW_TRANSFORM_READ); objVpWorldTrans[i].setCapability(vpTrans.ALLOW_TRANSFORM_WRITE); objVpWorldTrans[i].setCapability(Group.ALLOW_CHILDREN_READ); objVpWorldTrans[i].setCapability(Group.ALLOW_CHILDREN_WRITE); objVpWorldTrans[i].setCapability(Group.ALLOW_CHILDREN_EXTEND); objVpObjectTrans.addChild(objVpWorldTrans[i]); objVpOrientTrans[i] = new TransformGroup(); objVpOrientTrans[i].setCapability(vpTrans.ALLOW_TRANSFORM_READ); objVpOrientTrans[i].setCapability(vpTrans.ALLOW_TRANSFORM_WRITE); objVpOrientTrans[i].setCapability(Group.ALLOW_CHILDREN_READ); objVpOrientTrans[i].setCapability(Group.ALLOW_CHILDREN_WRITE); objVpOrientTrans[i].setCapability(Group.ALLOW_CHILDREN_EXTEND); // set orient trans to view sphere of radius 1 at origin switch (i) { case OBJ_VIEW_PLUS_X: offset.x = eyeDist; offset.y = 0.0; offset.z = 0.0; up.x = 0.0; up.y = 0.0; up.z = 1.0; eyeTrans.lookAt(offset, origin, up); //System.out.println("+X eye xform = \n" + eyeTrans); break; case OBJ_VIEW_PLUS_Y: offset.x = 0.0; offset.y = eyeDist; offset.z = 0.0; up.x = 0.0; up.y = 0.0; up.z = 1.0; eyeTrans.lookAt(offset, origin, up); // System.out.println("+Y eye xform = \n" + eyeTrans); break; case OBJ_VIEW_PLUS_Z: offset.x = 0.0; offset.y = 0.0; offset.z = eyeDist; up.x = 0.0; up.y = 1.0; up.z = 0.0; eyeTrans.lookAt(offset, origin, up); // System.out.println("+Z eye xform = \n" + eyeTrans); break; } eyeTrans.invert(); // need to invert because on view side of tree objVpOrientTrans[i].setTransform(eyeTrans); objVpWorldTrans[i].addChild(objVpOrientTrans[i]); objVpTrans[i] = new TransformGroup(); objVpTrans[i].setCapability(vpTrans.ALLOW_TRANSFORM_READ); objVpTrans[i].setCapability(vpTrans.ALLOW_TRANSFORM_WRITE); objVpTrans[i].setCapability(Group.ALLOW_CHILDREN_READ); objVpTrans[i].setCapability(Group.ALLOW_CHILDREN_WRITE); objVpTrans[i].setCapability(Group.ALLOW_CHILDREN_EXTEND); objVpOrientTrans[i].addChild(objVpTrans[i]); objVp[i] = new ViewPlatform(); objVpTrans[i].addChild(objVp[i]); } browserBounds = new BoundingSphere(new Point3d(), Double.MAX_VALUE); // currently don't have a file version for these, so they will always // be the obj versions vpFieldOfView = objVpFieldOfView; vpFrontClip = objVpFrontClip; vpBackClip = objVpBackClip; updateBehavior(); vpRoot.addChild(objVpObjectTrans); objVpTrans[0].addChild(browserGroup); prevVpTrans = objVpTrans[0]; // setup the initial obj viewpoints and use one setupObjViewpoints(); setObjViewpoint(0); // Attach the vpRoot to the universe, via the Locale. locale.addBranchGraph(vpRoot); objRoot = new BranchGroup(); objRoot.setCapability(BranchGroup.ALLOW_BOUNDS_READ); objRoot.setCapability(BranchGroup.ALLOW_CHILDREN_READ); objRoot.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE); objRoot.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND); objRoot.setCapability(BranchGroup.ALLOW_DETACH); } private void setSize(javax.media.j3d.Group g, int size) { for (int i = 0; i < size; i++) { g.addChild(new NullNode()); } } void setupCanvas() { if (timing) { canvas = new TimingCanvas3D(null, this); } else { canvas = new Canvas3D(null); } add("Center",canvas); panel = new Panel(); panel.setLayout(new FlowLayout(FlowLayout.LEFT)); gotoUrl = new GotoWRLTextField(this,urlString,60); label = new Label("WRL:"); panel.add(label); panel.add(gotoUrl); add("North",panel); canvas.setCursor(new Cursor(Cursor.WAIT_CURSOR)); setupJ3D(canvas); show(); } void removeOldURL() { objRoot.detach(); int numToRemove = objRoot.numChildren(); for (int i = 0; i < numToRemove; i++) { objRoot.removeChild(0); } fileVpMenu.removeAll(); fileViewpoints = null; objBounds = null; } void resetViewpoint() { vpWorldTrans.setTransform(identity); vpTrans.setTransform(identity); } private void removeBgFromPrev() { if (debug) System.out.println("removeBgFromPrev()"); int numChildren = prevVpTrans.numChildren(); boolean found = false; for (int i = numChildren-1; i >= 0; i--) { Node child = prevVpTrans.getChild(i); if (child.equals(browserGroup)) { if (debug) System.out.println("removeBgFromPrev():" + " removing child " + i + " from group " + prevVpTrans); prevVpTrans.removeChild(i); found = true; } } if (!found) { System.out.println("Can'f find browserGroup on previous vpTrans"); } } private void updateView() { if (debug) System.out.println("updateView()"); resetViewpoint(); removeBgFromPrev(); vpTrans.addChild(browserGroup); if (debug) System.out.println("updateView(): updating view"); view.setFieldOfView(vpFieldOfView); view.setFrontClipDistance(vpFrontClip); view.setBackClipDistance(vpBackClip); view.attachViewPlatform(vp); updateBehavior(); prevVpTrans = vpTrans; } void setFileViewpoint(int index) { if (debug) System.out.println("setFileViewpoint(" + index + ")"); Viewpoint viewpoint = fileViewpoints[index]; vpWorldTrans = fileVpWorldTrans[index]; vpOrientTrans = fileVpOrientTrans[index]; vpTrans = fileVpTrans[index]; vp = fileVp[index]; updateView(); } void setObjViewpoint(int index) { if (debug) System.out.println("setObjViewpoint(" + index + ")"); vp = objVp[index]; vpTrans = objVpTrans[index]; vpWorldTrans = objVpWorldTrans[index]; vpOrientTrans = objVpOrientTrans[index]; updateView(); } void setupObjViewpoints() { if (debug) System.out.println("setupObjViewpoints()"); Vector3d offset = new Vector3d(); Transform3D objTrans = new Transform3D(); if (objBounds == null) { objVpObjectTrans.setTransform(identity); } else { // Scale the obj trans so that the bounding sphere has radius 1 // in view space double radius = objBounds.getRadius(); // Set the Obj trans so the bounding sphere is at the origin Point3d center = new Point3d(); objBounds.getCenter(center); offset.x = center.x; offset.y = center.y; offset.z = center.z; if (debug) { System.out.println("Default view center:" + center + " distance " + radius); } objTrans.set(radius, offset); objVpObjectTrans.setTransform(objTrans); } } void setupFileViewpoints() { if (fileViewpoints != null) { MenuItem mi; String desc; fileVpWorldTrans = new TransformGroup[fileViewpoints.length]; fileVpOrientTrans = new TransformGroup[fileViewpoints.length]; fileVpTrans = new TransformGroup[fileViewpoints.length]; fileVp = new ViewPlatform[fileViewpoints.length]; for (int i = 0; i < fileViewpoints.length; i++) { // insert a transform above and below the Viewpoint's // TransformGroup TransformGroup viewOri = fileViewpoints[i].getTransformGroup(); viewOri.setCapability(BranchGroup.ALLOW_CHILDREN_READ); Group parent = (Group)viewOri.getParent(); TransformGroup viewWorld = new TransformGroup(); viewWorld.setCapability(viewWorld.ALLOW_TRANSFORM_READ); viewWorld.setCapability(viewWorld.ALLOW_TRANSFORM_WRITE); // Replace the TG by a new TG which will hold the ViewTG int numChildren = parent.numChildren(); boolean found = false; for (int j = 0; (j < numChildren) && (!found); j++) { if (parent.getChild(j) == viewOri) { found = true; parent.setChild(viewWorld, j); } } if (!found) { System.err.println("Internal error, can't find viewOri"); } viewWorld.addChild(viewOri); TransformGroup viewBrowser = new TransformGroup(); viewBrowser.setCapability(viewBrowser.ALLOW_TRANSFORM_READ); viewBrowser.setCapability(viewBrowser.ALLOW_TRANSFORM_WRITE); viewBrowser.setCapability(viewBrowser.ALLOW_CHILDREN_READ); viewBrowser.setCapability(viewBrowser.ALLOW_CHILDREN_WRITE); viewBrowser.setCapability(viewBrowser.ALLOW_CHILDREN_EXTEND); viewOri.setChild(viewBrowser, 0); viewBrowser.addChild(fileViewpoints[i].getViewPlatform()); fileVpWorldTrans[i] = viewWorld; fileVpOrientTrans[i] = viewOri; fileVpTrans[i] = viewBrowser; fileVp[i] = fileViewpoints[i].getViewPlatform(); if (((desc = fileViewpoints[i].getDescription()) == null) || desc.equals("")) { desc = "Viewpoint " + i; } mi = new MenuItem(desc); mi.addActionListener(this); mi.setActionCommand(fileVpAction + i); fileVpMenu.add(mi); } } } void setHeadlight(boolean state) { if (debug) System.out.println("setHeadlight(" + state + ")"); ambLight.setEnable(state); headLight.setEnable(state); } private void updateBehavior() { BranchGroup bg = new BranchGroup(); bg.setCapability(BranchGroup.ALLOW_DETACH); bg.setCapability(BranchGroup.ALLOW_CHILDREN_READ); KeyBehavior kb = new KeyBehavior(this); kb.setSchedulingBounds(browserBounds); bg.addChild(kb); switch (viewMode) { case EXAMINE: MouseRotate mr = new MouseRotate(MouseRotate.INVERT_INPUT); mr.setTransformGroup(vpWorldTrans); mr.setSchedulingBounds(browserBounds); bg.addChild(mr); MouseTranslate mt = new MouseTranslate(MouseTranslate.INVERT_INPUT); mt.setTransformGroup(vpWorldTrans); mt.setSchedulingBounds(browserBounds); bg.addChild(mt); MouseScale ms = new MouseScale(MouseScale.INVERT_INPUT); ms.setTransformGroup(vpWorldTrans); ms.setSchedulingBounds(browserBounds); bg.addChild(ms); break; case FLY: FlightBehavior fb = new FlightBehavior(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, vpTrans, canvas); bg.addChild(fb); break; } browserGroup.setChild(bg, BEHAVIOR); } void setMode(int mode) { viewMode = mode; updateBehavior(); } synchronized void gotoUrl(String u) { try { Node j3dNode; VrmlScene scene; // local var so VRML stuff will get gc'd canvas.setCursor(new Cursor(Cursor.WAIT_CURSOR)); removeOldURL(); fileLoaded = false; long startFree = 0; scene = (VrmlScene)loader.load(new URL(u)); Hashtable named = scene.getNamedObjects(); if (debug || timing || loadOnly) { System.gc(); System.out.println("After parse, freeMemory = " + numFormat.format( Runtime.getRuntime().freeMemory()/(1024*1024.0),2) + " totalMemory = " + numFormat.format( Runtime.getRuntime().totalMemory()/(1024*1024.0),2)); } if (loadOnly) { System.exit(0); } BranchGroup sceneGroup = scene.getSceneGroup(); // Clean the scene to prepare to compile it. This will keep the // scene from being pickable or collidable, but we don't need // either of those for this app. scene.cleanForCompile(sceneGroup); if (debug) { System.out.println("Adding subtree:"); System.out.println(sceneGroup); //tp.print(sceneGroup); //System.out.println(""); } // setting up file viewpoints modifies nodes in the Scene graph, // so we need to do this before we compile/add fileViewpoints = scene.getViewpoints(); if (fileViewpoints.length > 0) { setupFileViewpoints(); } // compile the branchgraph to optimize it sceneGroup.compile(); // add the brachgraph to our object tree objRoot.addChild(sceneGroup); locale.addBranchGraph(objRoot); objBounds = (BoundingSphere)objRoot.getBounds(); if (debug) { System.out.println("Object Bounds = " + objBounds); TransparencyAttributes sphereTransp = new TransparencyAttributes( TransparencyAttributes.FASTEST, 0.95f); Appearance sphereApp = new Appearance(); sphereApp.setTransparencyAttributes(sphereTransp); Sphere sphere = new Sphere((float)objBounds.getRadius(), sphereApp); TransformGroup sphereTG = new TransformGroup(); Point3d center = new Point3d(); objBounds.getCenter(center); Vector3d sphereOffset = new Vector3d(center); Transform3D sphereXform = new Transform3D(); sphereXform.setTranslation(sphereOffset); sphereTG.setTransform(sphereXform); sphereTG.addChild(sphere); BranchGroup sphereBG = new BranchGroup(); sphereBG.addChild(sphereTG); objRoot.addChild(sphereBG); } if (timing) { startupTiming = true; startupCount = 0; postTime = System.currentTimeMillis(); } fileLoaded = true; setupObjViewpoints(); if ((fileViewpoints.length > 0) && (initVp == FILE_VIEW)) { setFileViewpoint(0); } else { setObjViewpoint(OBJ_VIEW_PLUS_Z); } numTris = scene.getNumTris(); if (debug || timing) { System.out.println("Scene contains " + numTris + " triangles"); } String desc = scene.getDescription(); if ((desc == null) || desc.equals("")) { desc = u.substring(u.lastIndexOf('/')+1); } setTitle("Vrml97 Viewer : " + desc); } catch (java.io.IOException e) { System.err.println("IO exception reading URL"); } catch (vrml.InvalidVRMLSyntaxException e) { System.err.println("VRML parse error"); e.printStackTrace(System.err); } canvas.setCursor(new Cursor(Cursor.HAND_CURSOR)); } void outputTiming() { // TODO: remove TimingCanvas3D and switch these to use view instead of // tc when these methods are implemented TimingCanvas3D tc = (TimingCanvas3D) canvas; long now = System.currentTimeMillis(); long[] startTimes = new long[10]; tc.getFrameStartTimes(startTimes); long lastFrameDuration = tc.getLastFrameDuration(); int numFrames = (int)tc.getFrameNumber(); if (numFrames > 10) numFrames = 10; double elapsed = (now - startTimes[numFrames-1]) / 1000.0; System.out.println("Last " + numFrames + " frames rendered in " + numFormat.format(elapsed, 1) + " seconds, " + numFormat.format(numFrames / elapsed, 2) + " frames/sec"); System.out.println(numTris + " triangles/frame "); System.out.println("Overall rate: " + numFormat.format((numTris * numFrames) / (1000.0 * elapsed),0) + "K triangles/sec"); System.out.println("Last frame rendered in " + numFormat.format(lastFrameDuration / 1000.0, 3) + " seconds " + numFormat.format(1.0 * numTris / lastFrameDuration, 0) + "K triangles/sec "); } public void postRender() { if (startupTiming) { if ((startupCount++) == startupFrames) { TimingCanvas3D tc = (TimingCanvas3D) canvas; long[] startTimes = new long[startupFrames+1]; long[] durations = new long[startupFrames+1]; tc.getFrameStartTimes(startTimes); tc.getFrameDurations(durations); int first = startupFrames; System.out.println("Post to first start: " + numFormat.format((startTimes[first] - postTime)/1000.0,2)); for (int i = 0; i < startupFrames; i++) { double overall = (startTimes[first-i-1] - startTimes[first-i]) / 1000.0; double render = durations[first - i] / 1000.0; double other = overall - render; System.out.println("Frame " + i + " overall time " + numFormat.format(overall, 3) + " render time " + numFormat.format(render, 3) + " other time " + numFormat.format(other, 3)); } startupTiming = false; } } if (fileLoaded && ((numFrames++ % 10) == 0)) { outputTiming(); } } // MotionNotifierInteface public void viewMoved( Matrix4d position ) {} public void velocityChanged(double velocity) {} public void buttonPressed(int buttonId) {}; public void processEvent(AWTEvent e) { if(e.getID() == WindowEvent.WINDOW_CLOSING){ dispose(); System.exit(0); } } public void setGotoString(String s) { gotoUrl.setText(s); validate(); } public static void main(String[] args) { String urlString = null; if (args.length == 0) { urlString = "file:" + System.getProperties().getProperty("user.dir") + "/parts/simple.wrl"; } else { if (args.length != 1) { System.out.println("Usage: Vrml97Viewer [<URL>]"); System.exit(0); } else { urlString = args[0]; } } Vrml97Viewer v97v = new Vrml97Viewer(urlString); v97v.setSize(780, 780); v97v.setupCanvas(); v97v.gotoUrl(urlString); } }
/* * @(#)MouseScale.java 1.22 99/09/15 13:46:25 * * Copyright (c) 1996-1999 Sun Microsystems, Inc. All Rights Reserved. * * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use, * modify and redistribute this software in source and binary code form, * provided that i) this copyright notice and license appear on all copies of * the software; and ii) Licensee does not utilize the software in a manner * which is disparaging to Sun. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * This software is not designed or intended for use in on-line control of * aircraft, air traffic, aircraft navigation or aircraft communications; or in * the design, construction, operation or maintenance of any nuclear * facility. Licensee represents and warrants that it will not use or * redistribute the Software for such purposes. */ // package com.sun.j3d.utils.behaviors.mouse; import com.sun.j3d.utils.behaviors.mouse.*; import java.awt.*; import java.awt.event.*; import java.util.*; import javax.media.j3d.*; import javax.vecmath.*; /** * MouseScale is a Java3D behavior object that lets users control the * scaling of an object via a mouse drag motion with the second * mouse button for movement along the y axis. See MouseRotate for similar usage info. */ public class MouseScale extends MouseBehavior { double scale_factor = 1.01; private MouseBehaviorCallback callback = null; /** * Creates a scale behavior given the transform group. * @param transformGroup The transformGroup to operate on. */ public MouseScale(TransformGroup transformGroup) { super(transformGroup); } /** * Creates a default mouse scale behavior. **/ public MouseScale(){ super(0); } /** * Creates a scale behavior. * Note that this behavior still needs a transform * group to work on (use setTransformGroup(tg)) and * the transform group must add this behavior. * @param flags */ public MouseScale(int flags) { super(flags); } public void initialize() { super.initialize(); if ((flags & INVERT_INPUT) == INVERT_INPUT) { invert = true; } } /** * Return the scale movement multipler. **/ public double getFactor() { return scale_factor; } /** * Set the scale movement multipler with factor. **/ public void setFactor( double factor) { scale_factor = factor; } public void processStimulus (Enumeration criteria) { WakeupCriterion wakeup; AWTEvent[] event; int id; int dx, dy; double scale = 1.0; while (criteria.hasMoreElements()) { wakeup = (WakeupCriterion) criteria.nextElement(); if (wakeup instanceof WakeupOnAWTEvent) { event = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); for (int i=0; i<event.length; i++) { processMouseEvent((MouseEvent) event[i]); if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))){ id = event[i].getID(); if ((id == MouseEvent.MOUSE_DRAGGED) && ((MouseEvent)event[i]).isAltDown() && !((MouseEvent)event[i]).isMetaDown()){ x = ((MouseEvent)event[i]).getX(); y = ((MouseEvent)event[i]).getY(); dx = x - x_last; dy = y - y_last; if (!reset){ transformGroup.getTransform(currXform); //System.out.println("dy = " + dy); scale = 1.0; if (dy > 0) { for (int iy = 0; iy < dy; iy++) { scale *= scale_factor; } } else { for (int iy = 0; iy < -dy; iy++) { scale /= scale_factor; } } //System.out.println("scale = " + scale); transformX.set(scale); if (invert) { currXform.mul(currXform, transformX); } else { currXform.mul(transformX, currXform); } transformGroup.setTransform(currXform); transformChanged( currXform ); if (callback!=null) callback.transformChanged( MouseBehaviorCallback.ZOOM, currXform ); } else { reset = false; } x_last = x; y_last = y; } else if (id == MouseEvent.MOUSE_PRESSED) { x_last = ((MouseEvent)event[i]).getX(); y_last = ((MouseEvent)event[i]).getY(); } } } } } wakeupOn (mouseCriterion); } /** * Users can overload this method which is called every time * the Behavior updates the transform * * Default implementation does nothing */ public void transformChanged( Transform3D transform ) { } /** * The transformChanged method in the callback class will * be called every time the transform is updated */ public void setupCallback( MouseBehaviorCallback callback ) { this.callback = callback; } }