|
/*
*
* Copyright (c) 1998 David R. Nadeau
*
*/
import java.applet.Applet;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.CheckboxMenuItem;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Frame;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.util.BitSet;
import java.util.Enumeration;
import java.util.EventListener;
import javax.media.j3d.Appearance;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.Group;
import javax.media.j3d.IndexedQuadArray;
import javax.media.j3d.IndexedTriangleStripArray;
import javax.media.j3d.Light;
import javax.media.j3d.Link;
import javax.media.j3d.Material;
import javax.media.j3d.Shape3D;
import javax.media.j3d.SharedGroup;
import javax.media.j3d.Switch;
import javax.media.j3d.Texture;
import javax.media.j3d.TextureAttributes;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOnElapsedFrames;
import javax.media.j3d.WakeupOr;
import javax.vecmath.Color3f;
import javax.vecmath.Matrix4d;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;
import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.image.TextureLoader;
import com.sun.j3d.utils.universe.PlatformGeometry;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.universe.Viewer;
import com.sun.j3d.utils.universe.ViewingPlatform;
public class ExSwitch extends Java3DFrame {
//--------------------------------------------------------------
// SCENE CONTENT
//--------------------------------------------------------------
//
// Nodes (updated via menu)
//
private Switch swtch = null;
private int currentSwitch = 0;
//
// Build scene
//
public Group buildScene() {
// Turn on the example headlight
setHeadlightEnable(true);
// Default to walk navigation
setNavigationType(Walk);
// Build the scene group
Group scene = new Group();
if (debug)
System.err.println(" switch shapes...");
// BEGIN EXAMPLE TOPIC
// Build the switch group and allow its switch
// value to be changed via menu items
swtch = new Switch();
swtch.setCapability(Switch.ALLOW_SWITCH_WRITE);
// Create several shapes to place in a switch group
// Child 0: a red sphere
Appearance app0 = new Appearance();
Material mat0 = new Material();
mat0.setAmbientColor(0.2f, 0.2f, 0.2f);
mat0.setDiffuseColor(1.0f, 0.0f, 0.2f);
mat0.setSpecularColor(0.7f, 0.7f, 0.7f);
app0.setMaterial(mat0);
Transform3D t3d = new Transform3D();
t3d.setTranslation(new Vector3f(-2.0f, 1.5f, 0.0f));
TransformGroup tg0 = new TransformGroup(t3d);
Sphere sph0 = new Sphere(0.5f, // radius
Primitive.GENERATE_NORMALS, // components
16, // facets
app0); // appearance
tg0.addChild(sph0);
swtch.addChild(tg0); // Child 0
// Child 1: a green sphere
Appearance app1 = new Appearance();
Material mat1 = new Material();
mat1.setAmbientColor(0.2f, 0.2f, 0.2f);
mat1.setDiffuseColor(0.0f, 1.0f, 0.0f);
mat1.setSpecularColor(0.7f, 0.7f, 0.7f);
app1.setMaterial(mat1);
t3d.setTranslation(new Vector3f(0.0f, 1.5f, 0.0f));
TransformGroup tg1 = new TransformGroup(t3d);
Sphere sph1 = new Sphere(0.5f, // radius
Primitive.GENERATE_NORMALS, // components
16, // facets
app1); // appearance
tg1.addChild(sph1);
swtch.addChild(tg1); // Child 1
// Child 2: a blue sphere
Appearance app2 = new Appearance();
Material mat2 = new Material();
mat2.setAmbientColor(0.2f, 0.2f, 0.2f);
mat2.setDiffuseColor(0.0f, 0.6f, 1.0f);
mat2.setSpecularColor(0.7f, 0.7f, 0.7f);
app2.setMaterial(mat2);
t3d.setTranslation(new Vector3f(2.0f, 1.5f, 0.0f));
TransformGroup tg2 = new TransformGroup(t3d);
Sphere sph2 = new Sphere(0.5f, // radius
Primitive.GENERATE_NORMALS, // components
16, // facets
app2); // appearance
tg2.addChild(sph2);
swtch.addChild(tg2);
// Set the initial child choice
swtch.setWhichChild(options[currentSwitch].child);
scene.addChild(swtch);
// END EXAMPLE TOPIC
// Build foreground geometry including a floor and
// columns on which the switchable shapes stand
// Load textures
TextureLoader texLoader = new TextureLoader("granite07rev.jpg", this);
Texture columnTex = texLoader.getTexture();
if (columnTex == null)
System.err.println("Cannot load granite07rev.jpg texture");
else {
columnTex.setBoundaryModeS(Texture.WRAP);
columnTex.setBoundaryModeT(Texture.WRAP);
columnTex.setMinFilter(Texture.NICEST);
columnTex.setMagFilter(Texture.NICEST);
columnTex.setMipMapMode(Texture.BASE_LEVEL);
columnTex.setEnable(true);
}
texLoader = new TextureLoader("flooring.jpg", this);
Texture groundTex = texLoader.getTexture();
if (groundTex == null)
System.err.println("Cannot load flooring.jpg texture");
else {
groundTex.setBoundaryModeS(Texture.WRAP);
groundTex.setBoundaryModeT(Texture.WRAP);
groundTex.setMinFilter(Texture.NICEST);
groundTex.setMagFilter(Texture.NICEST);
groundTex.setMipMapMode(Texture.BASE_LEVEL);
groundTex.setEnable(true);
}
//
// Build several columns on the floor
//
if (debug)
System.err.println(" columns...");
SharedGroup column = new SharedGroup();
Appearance columnApp = new Appearance();
Material columnMat = new Material();
columnMat.setAmbientColor(0.6f, 0.6f, 0.6f);
columnMat.setDiffuseColor(1.0f, 1.0f, 1.0f);
columnMat.setSpecularColor(0.0f, 0.0f, 0.0f);
columnApp.setMaterial(columnMat);
TextureAttributes columnTexAtt = new TextureAttributes();
columnTexAtt.setTextureMode(TextureAttributes.MODULATE);
columnTexAtt.setPerspectiveCorrectionMode(TextureAttributes.NICEST);
columnApp.setTextureAttributes(columnTexAtt);
if (columnTex != null)
columnApp.setTexture(columnTex);
GothicColumn columnShape = new GothicColumn(1.8f, // height
0.25f, // radius
GothicColumn.BUILD_TOP, // flags
columnApp); // appearance
column.addChild(columnShape);
Vector3f trans = new Vector3f();
Transform3D tr = new Transform3D();
TransformGroup tg;
// Left
trans.set(-2.0f, -1.0f, 0.0f);
tr.set(trans);
tg = new TransformGroup(tr);
tg.addChild(new Link(column));
scene.addChild(tg);
// Middle
trans.set(0.0f, -1.0f, 0.0f);
tr.set(trans);
tg = new TransformGroup(tr);
tg.addChild(new Link(column));
scene.addChild(tg);
// Right
trans.set(2.0f, -1.0f, 0.0f);
tr.set(trans);
tg = new TransformGroup(tr);
tg.addChild(new Link(column));
scene.addChild(tg);
//
// Add the ground
//
if (debug)
System.err.println(" ground...");
Appearance groundApp = new Appearance();
Material groundMat = new Material();
groundMat.setAmbientColor(0.6f, 0.6f, 0.6f);
groundMat.setDiffuseColor(1.0f, 1.0f, 1.0f);
groundMat.setSpecularColor(0.0f, 0.0f, 0.0f);
groundApp.setMaterial(groundMat);
tr = new Transform3D();
tr.setScale(new Vector3d(4.0, 4.0, 1.0));
TextureAttributes groundTexAtt = new TextureAttributes();
groundTexAtt.setTextureMode(TextureAttributes.MODULATE);
groundTexAtt.setPerspectiveCorrectionMode(TextureAttributes.NICEST);
groundTexAtt.setTextureTransform(tr);
groundApp.setTextureAttributes(groundTexAtt);
if (groundTex != null)
groundApp.setTexture(groundTex);
ElevationGrid ground = new ElevationGrid(11, // X dimension
11, // Z dimension
2.0f, // X spacing
2.0f, // Z spacing
// Automatically use zero heights
groundApp); // Appearance
trans.set(0.0f, -1.0f, 0.0f);
tr.set(trans);
tg = new TransformGroup(tr);
tg.addChild(ground);
scene.addChild(tg);
// Add a light
BoundingSphere worldBounds = new BoundingSphere(new Point3d(0.0, 0.0,
0.0), // Center
1000.0); // Extent
DirectionalLight light = new DirectionalLight();
light.setEnable(true);
light.setColor(new Color3f(1.0f, 1.0f, 1.0f));
light.setDirection(new Vector3f(0.5f, -1.0f, -0.5f));
light.setInfluencingBounds(worldBounds);
scene.addChild(light);
return scene;
}
//--------------------------------------------------------------
// USER INTERFACE
//--------------------------------------------------------------
//
// Main
//
public static void main(String[] args) {
ExSwitch ex = new ExSwitch();
ex.initialize(args);
ex.buildUniverse();
ex.showFrame();
}
//
// Private class for holding switch options
//
private class NameChildMask {
public String name;
public int child;
public BitSet mask;
public NameChildMask(String n, int c, int m) {
name = n;
child = c;
mask = new BitSet(3);
if ((m & 1) != 0)
mask.set(0);
if ((m & 2) != 0)
mask.set(1);
if ((m & 4) != 0)
mask.set(2);
}
}
// Switch menu choices
private NameChildMask[] options = {
new NameChildMask("CHILD_ALL", Switch.CHILD_ALL, 0),
new NameChildMask("CHILD_NONE", Switch.CHILD_NONE, 0),
new NameChildMask("Child 0", 0, 0),
new NameChildMask("Child 1", 1, 0),
new NameChildMask("Child 2", 2, 0),
new NameChildMask("Children 0 & 1", Switch.CHILD_MASK, 3),
new NameChildMask("Children 0 & 2", Switch.CHILD_MASK, 5),
new NameChildMask("Children 1 & 2", Switch.CHILD_MASK, 6), };
private CheckboxMenuItem[] switchMenu;
//
// Initialize the GUI (application and applet)
//
public void initialize(String[] args) {
// Initialize the window, menubar, etc.
super.initialize(args);
exampleFrame.setTitle("Java 3D Switch Example");
// Add a menu to select among switch options
Menu mt = new Menu("Switch");
switchMenu = new CheckboxMenuItem[options.length];
for (int i = 0; i < options.length; i++) {
switchMenu[i] = new CheckboxMenuItem(options[i].name);
switchMenu[i].addItemListener(this);
switchMenu[i].setState(false);
mt.add(switchMenu[i]);
}
exampleMenuBar.add(mt);
currentSwitch = 0;
switchMenu[currentSwitch].setState(true);
}
//
// Handle checkboxes
//
public void itemStateChanged(ItemEvent event) {
Object src = event.getSource();
// Check if it is switch choice
for (int i = 0; i < switchMenu.length; i++) {
if (src == switchMenu[i]) {
// Update the checkboxes
switchMenu[currentSwitch].setState(false);
currentSwitch = i;
switchMenu[currentSwitch].setState(true);
// Set the switch
swtch.setWhichChild(options[currentSwitch].child);
swtch.setChildMask(options[currentSwitch].mask);
return;
}
}
// Handle all other checkboxes
super.itemStateChanged(event);
}
}
//
//CLASS
//ElevationGrid - a 3D terrain grid built from a list of heights
//
//DESCRIPTION
//This class creates a 3D terrain on a grid whose X and Z dimensions,
//and row/column spacing are parameters, along with a list of heights
//(elevations), one per grid row/column pair.
//
class ElevationGrid extends Primitive {
// Parameters
protected int xDimension = 0, zDimension = 0;
protected double xSpacing = 0.0, zSpacing = 0.0;
protected double[] heights = null;
// 3D nodes
private Appearance mainAppearance = null;
private Shape3D shape = null;
private IndexedTriangleStripArray tristrip = null;
//
// Construct an elevation grid
//
public ElevationGrid() {
xDimension = 2;
zDimension = 2;
xSpacing = 1.0;
zSpacing = 1.0;
mainAppearance = null;
zeroHeights();
rebuild();
}
public ElevationGrid(int xDim, int zDim) {
xDimension = xDim;
zDimension = zDim;
xSpacing = 1.0;
zSpacing = 1.0;
mainAppearance = null;
zeroHeights();
rebuild();
}
public ElevationGrid(int xDim, int zDim, Appearance app) {
xDimension = xDim;
zDimension = zDim;
xSpacing = 1.0;
zSpacing = 1.0;
mainAppearance = app;
zeroHeights();
rebuild();
}
public ElevationGrid(int xDim, int zDim, double xSpace, double zSpace) {
xDimension = xDim;
zDimension = zDim;
xSpacing = xSpace;
zSpacing = zSpace;
mainAppearance = null;
zeroHeights();
rebuild();
}
public ElevationGrid(int xDim, int zDim, double xSpace, double zSpace,
Appearance app) {
xDimension = xDim;
zDimension = zDim;
xSpacing = xSpace;
zSpacing = zSpace;
mainAppearance = app;
zeroHeights();
rebuild();
}
public ElevationGrid(int xDim, int zDim, double[] h) {
this(xDim, zDim, 1.0, 1.0, h, null);
}
public ElevationGrid(int xDim, int zDim, double[] h, Appearance app) {
this(xDim, zDim, 1.0, 1.0, h, app);
}
public ElevationGrid(int xDim, int zDim, double xSpace, double zSpace,
double[] h) {
this(xDim, zDim, xSpace, zSpace, h, null);
}
public ElevationGrid(int xDim, int zDim, double xSpace, double zSpace,
double[] h, Appearance app) {
xDimension = xDim;
zDimension = zDim;
xSpacing = xSpace;
zSpacing = zSpace;
mainAppearance = app;
if (h == null)
zeroHeights();
else {
heights = new double[h.length];
for (int i = 0; i < h.length; i++)
heights[i] = h[i];
}
rebuild();
}
private void zeroHeights() {
int n = xDimension * zDimension;
heights = new double[n];
for (int i = 0; i < n; i++)
heights[i] = 0.0;
}
private void rebuild() {
// Build a shape
if (shape == null) {
shape = new Shape3D();
shape.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
shape.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
shape.setAppearance(mainAppearance);
addChild(shape);
} else {
shape.setAppearance(mainAppearance);
}
if (xDimension < 2 || zDimension < 2 || heights == null
|| heights.length < 4) {
tristrip = null;
shape.setGeometry(null);
return;
}
// Create a list of coordinates, one per grid row/column
double[] coordinates = new double[xDimension * zDimension * 3];
double x, z;
int n = 0, k = 0;
z = ((double) (zDimension - 1)) * zSpacing / 2.0; // start at front edge
for (int i = 0; i < zDimension; i++) {
x = -((double) (xDimension - 1)) * xSpacing / 2.0;// start at left
// edge
for (int j = 0; j < xDimension; j++) {
coordinates[n++] = x;
coordinates[n++] = heights[k++];
coordinates[n++] = z;
x += xSpacing;
}
z -= zSpacing;
}
// Create a list of normals, one per grid row/column
float[] normals = new float[xDimension * zDimension * 3];
Vector3f one = new Vector3f(0.0f, 0.0f, 0.0f);
Vector3f two = new Vector3f(0.0f, 0.0f, 0.0f);
Vector3f norm = new Vector3f(0.0f, 0.0f, 0.0f);
n = 0;
k = 0;
for (int i = 0; i < zDimension - 1; i++) {
for (int j = 0; j < xDimension - 1; j++) {
// Vector to right in X
one.set((float) xSpacing,
(float) (heights[k + 1] - heights[k]), 0.0f);
// Vector back in Z
two.set(0.0f, (float) (heights[k + xDimension] - heights[k]),
(float) -zSpacing);
// Cross them to get the normal
norm.cross(one, two);
normals[n++] = norm.x;
normals[n++] = norm.y;
normals[n++] = norm.z;
k++;
}
// Last normal in row is a copy of the previous one
normals[n] = normals[n - 3]; // X
normals[n + 1] = normals[n - 2]; // Y
normals[n + 2] = normals[n - 1]; // Z
n += 3;
k++;
}
// Last row of normals is a copy of the previous row
for (int j = 0; j < xDimension; j++) {
normals[n] = normals[n - xDimension * 3]; // X
normals[n + 1] = normals[n - xDimension * 3 + 1]; // Y
normals[n + 2] = normals[n - xDimension * 3 + 2]; // Z
n += 3;
}
// Create a list of texture coordinates, one per grid row/column
float[] texcoordinates = new float[xDimension * zDimension * 2];
float deltaS = 1.0f / (float) (xDimension - 1);
float deltaT = 1.0f / (float) (zDimension - 1);
float s = 0.0f;
float t = 0.0f;
n = 0;
for (int i = 0
|