/*
Viewer.java
Copyright (C) 2009 Collin Monahan
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package acm2;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.vp.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import com.sun.j3d.utils.behaviors.keyboard.*;
import acm2.atomics.*;
import acm2.composites.*;
import acm2.models.*;
public class Viewer extends JFrame implements KeyListener {
SimpleUniverse univ;
BranchGroup scene;
Appearance look;
BranchGroup currentshape;
Group addpoint;
JLabel label0;
JLabel label1;
JLabel label2;
JPanel labelpanel;
String shapeclasses[] = {
"acm2.atomics.RightCuboid",
"acm2.atomics.EllipticCylinder",
"acm2.atomics.Tetrahedron",
"acm2.atomics.Octahedron",
"acm2.atomics.PentagonalTrapezohedron",
"acm2.atomics.Dodecahedron",
"acm2.atomics.Icosahedron",
"acm2.atomics.SmallStellatedDodecahedron",
"acm2.atomics.GreatDodecahedron",
"acm2.atomics.GreatStellatedDodecahedron",
"acm2.atomics.GreatIcosahedron",
"acm2.atomics.Icosidodecahedron",
"acm2.atomics.PentagonalBipyramid",
"acm2.atomics.PentagrammicDipyramid",
"acm2.atomics.Star",
"acm2.atomics.Ex01",
"acm2.atomics.Ex02",
"acm2.atomics.Ex03",
"acm2.atomics.Ex04",
"acm2.atomics.Ex05",
"acm2.atomics.Ex06",
// "acm2.atomics.Ex07",
// "acm2.atomics.Ex08",
"acm2.atomics.Ex09",
"acm2.atomics.Ex10",
"acm2.atomics.Ex11",
"acm2.atomics.Ex12",
"acm2.atomics.Ex13",
"acm2.atomics.Ex14",
"acm2.atomics.Ex15",
"acm2.atomics.Ex16",
"acm2.atomics.Ex17",
"acm2.atomics.Ex18",
"acm2.atomics.Ex19",
"acm2.atomics.Ex20",
"acm2.atomics.Ex21",
"acm2.atomics.Ex22",
"acm2.models.Cylinder",
"acm2.models.Ring",
"acm2.models.BalanceWheel",
};
int shapedex = 0;
Viewer(String args[]) throws Throwable {
initcomponents();
Canvas3D c = createUniverse();
drawingpanel.add(c, java.awt.BorderLayout.CENTER);
// Create the content branch and add it to the universe
scene = createSceneGraph();
univ.addBranchGraph(scene);
}
void initcomponents() {
drawingpanel = new javax.swing.JPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("acm2 Shape Viewer");
drawingpanel.setLayout(new java.awt.BorderLayout());
drawingpanel.setPreferredSize(new java.awt.Dimension(700, 700));
getContentPane().add(drawingpanel, java.awt.BorderLayout.CENTER);
label0 = new JLabel("acm2 Shape viewer by Collin Monahan");
label0.setBackground(Color.WHITE);
label1 = new JLabel(
"1 / " + shapeclasses.length + " " + shapeclasses[0],
SwingConstants.CENTER);
label1.setBackground(Color.WHITE);
label2 = new JLabel("page up / down to navigate", SwingConstants.RIGHT);
label2.setBackground(Color.WHITE);
labelpanel = new JPanel();
labelpanel.setPreferredSize(
new Dimension(700, label0.getPreferredSize().height));
labelpanel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = gbc.gridy = 0;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
labelpanel.add(label0, gbc);
gbc.gridx++;
labelpanel.add(label1, gbc);
gbc.gridx++;
labelpanel.add(label2, gbc);
getContentPane().add(labelpanel, java.awt.BorderLayout.NORTH);
pack();
}
Canvas3D createUniverse() throws Throwable {
// Get the preferred graphics configuration for the default screen
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
// Create a Canvas3D using the preferred configuration
Canvas3D c = new Canvas3D(config);
c.addKeyListener(this);
// Create simple universe with view branch
univ = new SimpleUniverse(c);
// This will move the ViewPlatform back a bit so the
// objects in the scene can be viewed.
Transform3D viewmove = new Transform3D();
viewmove.set(new Vector3f(0.2f,-2f,1f));
Transform3D viewrot = new Transform3D();
viewrot.rotX(Math.PI / 3);
viewmove.mul(viewrot);
viewrot.rotY(Math.PI / 32);
viewmove.mul(viewrot);
univ.getViewingPlatform().
getViewPlatformTransform().setTransform(viewmove);
// Ensure at least 5 msec per frame (i.e., < 200Hz)
univ.getViewer().getView().setMinimumFrameCycleTime(5);
return c;
}
BranchGroup createSceneGraph() throws Throwable {
BranchGroup ret = new BranchGroup();
// Create a Transformgroup to scale all objects so they
// appear in the scene.
TransformGroup objScale = new TransformGroup();
Transform3D t3d = new Transform3D();
t3d.setScale(0.4);
objScale.setTransform(t3d);
ret.addChild(objScale);
// Create a bounds for the background and lights
BoundingSphere bounds =
new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
// Set up the background
Color3f bgColor = new Color3f(0.05f, 0.05f, 0.2f);
Background bgNode = new Background(bgColor);
bgNode.setApplicationBounds(bounds);
objScale.addChild(bgNode);
// Set up the global lights
Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f);
Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f);
Color3f light2Color = new Color3f(0.3f, 0.3f, 0.4f);
Vector3f light2Direction = new Vector3f(-6.0f, -2.0f, -1.0f);
Color3f ambientColor = new Color3f(0.1f, 0.1f, 0.1f);
AmbientLight ambientLightNode = new AmbientLight(ambientColor);
ambientLightNode.setInfluencingBounds(bounds);
objScale.addChild(ambientLightNode);
DirectionalLight light1
= new DirectionalLight(light1Color, light1Direction);
light1.setInfluencingBounds(bounds);
objScale.addChild(light1);
DirectionalLight light2
= new DirectionalLight(light2Color, light2Direction);
light2.setInfluencingBounds(bounds);
objScale.addChild(light2);
// Create the transform group node and initialize it to the
// identity. Enable the TRANSFORM_WRITE capability so that
// our behavior code can modify it at runtime. Add it to the
// root of the subgraph.
TransformGroup objTrans = new TransformGroup();
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objScale.addChild(objTrans);
MouseRotate behavior = new MouseRotate();
behavior.setTransformGroup(objTrans);
objTrans.addChild(behavior);
behavior.setSchedulingBounds(bounds);
BranchGroup bg = new BranchGroup();
objTrans.addChild(bg);
TransformGroup objTrans2 = new TransformGroup();
objTrans2.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
bg.addChild(objTrans2);
// Create an Appearance.
look = new Appearance();
Color3f objColor = new Color3f(0.7f, 0.7f, 0.7f);
Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
look.setMaterial(new Material(
objColor, black, objColor, white, 100.0f));
// Create a gear, add it to the scene graph.
addpoint = objTrans2;
addpoint.setCapability(Group.ALLOW_CHILDREN_WRITE);
addpoint.setCapability(Group.ALLOW_CHILDREN_EXTEND);
currentshape = generategeometry(look);
addpoint.addChild(currentshape);
// Create a new Behavior object that will rotate the object and
// add it into the scene graph.
Transform3D zAxis = new Transform3D(); // default is y-axis
zAxis.rotX(Math.PI/2); // 90 deg on the x-axis brings it to z
Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE,
0, 0,
8000, 0, 0,
0, 0, 0);
RotationInterpolator rotator =
new RotationInterpolator(rotationAlpha, objTrans2, zAxis,
0.0f, (float) Math.PI*2.0f);
rotator.setSchedulingBounds(bounds);
// objTrans2.addChild(rotator);
// Have Java 3D perform optimizations on this scene graph.
ret.compile();
return ret;
}
BranchGroup generategeometry(Appearance look) throws Throwable {
BranchGroup ret = new BranchGroup();
ret.setCapability(BranchGroup.ALLOW_DETACH);
Shape3D s3d = (Shape3D)
Class.forName(shapeclasses[shapedex]).newInstance();
s3d.setAppearance(look);
ret.addChild(s3d);
return ret;
}
public static void main(final String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
Viewer viewer = null;
try {
viewer = new Viewer(args);
} catch (Throwable t) {
System.err.println(t);
t.printStackTrace();
System.exit(1);
}
viewer.setVisible(true);
}
});
}
JPanel drawingpanel;
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_PAGE_UP) {
next();
}
else if (e.getKeyCode() == KeyEvent.VK_PAGE_DOWN) {
previous();
}
else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
System.exit(0);
}
}
public void keyTyped(KeyEvent e) {
}
void next() {
shapedex++;
if (shapedex >= shapeclasses.length) shapedex = 0;
label1.setText(
Integer.toString(shapedex+1) + " / " + shapeclasses.length +
" " + unpackage(shapeclasses[shapedex]));
polymorph();
}
void previous() {
shapedex--;
if (shapedex < 0) shapedex = shapeclasses.length - 1;
label1.setText(
Integer.toString(shapedex+1) + " / " + shapeclasses.length +
" " + unpackage(shapeclasses[shapedex]));
polymorph();
}
String unpackage(String x) {
return x.substring(5);
}
void polymorph() {
BranchGroup newshape = null;
try {
newshape = generategeometry(look);
} catch (Throwable t) {
System.err.println(t);
return;
}
addpoint.removeChild(currentshape);
currentshape = newshape;
addpoint.addChild(currentshape);
}
}