> 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;
}
}