/* Author Claude G. Schwab
* Copyright (c) 2005 University of applied sciences
* Biel School of Engineering and Architecture, Switzerland.
* http://www.hta-bi.bfh.ch
* All Rights Reserved.
* Compiled with SDK 1.4.1 and Java3D API Version 1.3
*
* This Demo class is a demonstration software (code)
* for my introduction to Java3D.
*/
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.text.NumberFormat;
import java.util.Enumeration;
import javax.media.j3d.Alpha;
import javax.media.j3d.AmbientLight;
import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.Group;
import javax.media.j3d.LineArray;
import javax.media.j3d.Locale;
import javax.media.j3d.Material;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.PointLight;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.QuadArray;
import javax.media.j3d.RotationInterpolator;
import javax.media.j3d.Shape3D;
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.TransparencyAttributes;
import javax.media.j3d.View;
import javax.media.j3d.ViewPlatform;
import javax.media.j3d.VirtualUniverse;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOnElapsedFrames;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.vecmath.AxisAngle4f;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.TexCoord2f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;
import com.sun.j3d.utils.behaviors.picking.PickRotateBehavior;
import com.sun.j3d.utils.behaviors.picking.PickTranslateBehavior;
import com.sun.j3d.utils.behaviors.picking.PickZoomBehavior;
import com.sun.j3d.utils.geometry.GeometryInfo;
import com.sun.j3d.utils.geometry.NormalGenerator;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.geometry.Stripifier;
import com.sun.j3d.utils.image.TextureLoader;
/**
* This class is the main class of the program Demo. It creates a Virtual
* Universe and a Locale and attaches to the Locale: a right-handed 3D
* coordinate system, a color cube, a tetrahedron, the earth and the ViewBranch.
* It also overrides the addBranchGraph methode.
*/
public class Demo3D extends JFrame implements Runnable {
static int screenwidth;
static int screenheight;
static Thread fpsThread;
long sleepDuration = 200; // in msec
int decimalForAllFps = 1;
JLabel jLabel;
// Create a virtual universe.
VirtualUniverse universe = new VirtualUniverse();
// A single hi-res. Locale node is created and attached to the
// virtual universe.
Locale locale = new Locale(universe);
Canvas3D canvas3D;
ViewBranch viewBr;
/**
* Constructor that allows to specify the desired initial instances.
*/
public Demo3D() {
// Set the best GraphicsConfiguration
GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D();
GraphicsConfiguration graphConf = GraphicsEnvironment
.getLocalGraphicsEnvironment().getDefaultScreenDevice()
.getBestConfiguration(template);
canvas3D = new Canvas3D(graphConf); // The used Canvas3D
// Construction of the main frame.
setTitle("Demo");
JPanel jMainPanel = new JPanel(true);
jMainPanel.setLayout(new BorderLayout(0, 5)); // hor_gap and ver_gap
JPanel jFpsPanel = new JPanel(true);
jFpsPanel.setBackground(Color.white);
jLabel = new JLabel("");
jLabel.setText("Wait for informations");
jFpsPanel.add(jLabel);
jMainPanel.add(canvas3D, BorderLayout.CENTER);
/*
* // For the stereo-mode with an "Head Monted Display" (HMD). JPanel
* jScene_Stereo_Panel = new JPanel(true);
* jScene_Stereo_Panel.setLayout(new GridLayout(1, 2, 0, 0)); // rows,
* col, hor_gap and ver_gap jScene_Stereo_Panel.add(canvas3D);
* jScene_Stereo_Panel.add(canvas3D);
* jMainPanel.add(jScene_Stereo_Panel, BorderLayout.CENTER);
*/
jMainPanel.add(jFpsPanel, BorderLayout.SOUTH);
setContentPane(jMainPanel);
// The ViewBranch class creates the instances of ViewPlatform, View,
// etc.
viewBr = new ViewBranch(canvas3D);
fpsThread = new Thread(this);
myScene();
}
/**
* Assembling of all components of the scene.
*/
public void myScene() {
// Necessary to use NewTextureLoader in other classes.
NewTextureLoader.setImageObserver(this); // AWT Component
// Attach the subgraphs SceneBuilder1, SceneBuilder2, SceneBuilder3
// and the ViewBranch to the Locale node.
addBranchGraph(new SceneBuilder1().mySubGraph1());
addBranchGraph(new SceneBuilder2().mySubGraph2());
addBranchGraph(new SceneBuilder3(canvas3D).mySubGraph3());
addBranchGraph(viewBr.myViewBranch());
}
/**
* Allows to attach all subgraphs of the scene and the ViewBranch to the
* Locale node.
*
* @param javax.media.j3d.BranchGroup
* brGr - the root of the subgraph
*/
public void addBranchGraph(BranchGroup brGr) {
locale.addBranchGraph(brGr);
}
///////////////////////////// Framemeter /////////////////////////////
/**
* This start method allows to start the thread of the framemeter.
*/
public void start() {
SwingUtilities.invokeLater(fpsThread);
}
/**
* This run method allows to launch the computation of all frames per second
* for the framemeter.
*/
public void run() {
long lastFrameTime;
double fps;
double min = Double.MAX_VALUE;
double max = Double.MIN_VALUE;
long count = 0;
double sum = 0;
double mean = 0;
while (true) {
lastFrameTime = viewBr.view.getLastFrameDuration();
if (lastFrameTime > 0) {
fps = 1000 / (double) lastFrameTime;
count += 1;
sum += fps;
mean = sum / count;
// To format all fps-informations.
NumberFormat numbForm;
numbForm = NumberFormat.getInstance();
numbForm.setMaximumFractionDigits(decimalForAllFps);
if (min > fps && fps != 0 && count > 4)
min = fps;
if (max < fps)
max = fps;
jLabel.setText("Frames/sec = " + numbForm.format(fps)
+ " ; minFrames/sec = " + numbForm.format(min)
+ " ; maxFrames/sec = " + numbForm.format(max)
+ " ; meanFrames/sec = " + numbForm.format(mean));
// System.out.println("Frames per second = " + fps);
}
try {
Thread.sleep(sleepDuration);
} catch (InterruptedException e) {
}
}
}
///////////////////////// End of the framemeter /////////////////////////
/**
* Main of the Demo program. Take the graphic environment of the
* workstation.
*/
public static void main(String args[]) {
JFrame jFrameDemo = new Demo3D();
// To be sure to stop the application when the frame is closed.
WindowListener winListener = new WindowAdapter() {
public void windowClosing(WindowEvent event) {
System.exit(0);
}
};
jFrameDemo.addWindowListener(winListener);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
screenwidth = (int) screenSize.getWidth();
screenheight = (int) screenSize.getHeight();
jFrameDemo.setSize(screenwidth, screenheight);
// Turn on the visibility of the frame.
jFrameDemo.setVisible(true);
fpsThread.start();
}
}
/*
* Author Claude G. Schwab Copyright (c) 2002 University of applied sciences
* Biel School of Engineering and Architecture, Switzerland.
* http://www.hta-bi.bfh.ch All Rights Reserved. Compiled with SDK 1.4.1 and
* Java3D API Version 1.3
*
* This ViewBranch class is a demonstration software (code) for my introduction
* to Java3D.
*/
/**
* This class creates all necessary objects on the "View Branch" side of the
* scene graph.
*/
class ViewBranch {
public BranchGroup vbBrGr;
private Canvas3D canvas3D;
private PhysicalBody body;
private PhysicalEnvironment environment;
public static View view; // static for the Framemeter
private ViewPlatform viewPlat;
private TransformGroup vpTrGrStart, vpTrGrKeys_Transl_Turn,
vpTrGrKeys_Rot_Up_Down;
private Transform3D trStart;
private BoundingSphere cameraBounds;
private Camera_Transl_Turn camera_Transl_Turn;
private Camera_Rot_Up_Down camera_Rot_Up_Down;
private Aimer aimer;
/**
* Constructor that allows to specify the desired Canvas3D.
*
* @param javax.media.j3d.Canvas3D
* canv - the Canvas3D being used
*/
public ViewBranch(Canvas3D canv) // The instance canv of Canvas3D class is
{ // created in the constructor of the Demo class.
canvas3D = canv;
}
/**
* Create the ViewBranch
*
* @return javax.media.j3d.BranchGroup vbBrGr - the root of the ViewBranch
*/
public BranchGroup myViewBranch() {
// Create the minimal PhysicalBody and PhysicalEnvironnement
// instances with default parameters.
body = new PhysicalBody();
environment = new PhysicalEnvironment();
// Create a View instance and attach the Canvas3D, the PhysicalBody
// and the PhysicalEnvironment to it.
view = new View();
view.setFrontClipDistance(0.02); // Default value is 0.1 m
view.setBackClipDistance(40.0); // Default value is 10 m
// Rem.: BackClipDistance / FrontClipDistance = 2000 > 1000 but < 3000
view.addCanvas3D(canvas3D);
view.setPhysicalBody(body);
view.setPhysicalEnvironment(environment);
/*
* // Choices of the projection type. They are 2 possibilities, namely: //
* PERSPECTIVE_PROJECTION and PARALLEL_PROJECTION. // Note: the default
* value is PERSPECTIVE_PROJECTION
* view.setProjectionPolicy(View.PARALLEL_PROJECTION);
*/
// Create a ViewPlatform instance and bind it with the View instance.
viewPlat = new ViewPlatform();
viewPlat.setActivationRadius(40.0f); // Default value is 62 m
view.attachViewPlatform(viewPlat);
// Create the action volume for the camera's navigation.
cameraBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
// Create the two necessary TransformGroups for the ViewPlatform's
// motion (6 translations and 4 rotations).
vpTrGrKeys_Rot_Up_Down = new TransformGroup();
vpTrGrKeys_Transl_Turn = new TransformGroup();
// With the ALLOW_TRANSFORM_READ and ALLOW_TRANSFORM_WRITE
// capabilities, we allow the modification of the TransformGroup's
// code by the Behavior's code at run time.
vpTrGrKeys_Transl_Turn
.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
vpTrGrKeys_Transl_Turn
.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
vpTrGrKeys_Rot_Up_Down
.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
vpTrGrKeys_Rot_Up_Down
.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
// Attach the ViewPlatform to the vpTrGrKeys_Rot_Up_Down node.
vpTrGrKeys_Rot_Up_Down.addChild(viewPlat);
// Create and attach an aimer to the TransformGroup node
// vpTrGrKeys_Rot_Up_Down.
aimer = new Aimer(1.5f);
vpTrGrKeys_Rot_Up_Down.addChild(aimer.myAimer());
// View-platform's motion ==> camera's navigation: 6 translations and 4
// rotations.
// Create and attach the camera's rotation on the vpTrGrKeys_Rot_Up_Down
// node.
camera_Rot_Up_Down = new Camera_Rot_Up_Down(vpTrGrKeys_Rot_Up_Down);
camera_Rot_Up_Down.setSchedulingBounds(cameraBounds);
vpTrGrKeys_Rot_Up_Down.addChild(camera_Rot_Up_Down);
// Create and attach the camera's translation and rotation instances
// on the vpTrGrKeys_Transl_Turn node.
camera_Transl_Turn = new Camera_Transl_Turn(vpTrGrKeys_Transl_Turn);
camera_Transl_Turn.setSchedulingBounds(cameraBounds);
vpTrGrKeys_Transl_Turn.addChild(camera_Transl_Turn);
// Attach the vpTrGrKeys_Rot_Up_Down node to the vpTrGrKeys_Transl_Turn
// node.
vpTrGrKeys_Transl_Turn.addChild(vpTrGrKeys_Rot_Up_Down);
// Give the starting position of the ViewPlatform.
trStart = new Transform3D(); // Identity matrix
trStart.set(new Vector3f(0.0f, 0.0f, 10.0f)); // Translation of the
// camera (0,0,10)
// Create the TransformGroup node for the ViewPlatform's
// starting position.
vpTrGrStart = new TransformGroup(trStart);
// Attach the vpTrGrKeys_Transl_Turn node to the TransformGroup
// node vpTrGrStart.
vpTrGrStart.addChild(vpTrGrKeys_Transl_Turn);
// Add the TransformGroup node vpTrGrStart to the view
// BranchGroup node vbBrGr.
vbBrGr = new BranchGroup();
vbBrGr.addChild(vpTrGrStart);
// Compile the ViewBranch to optimize the performances.
vbBrGr.compile();
// Return the final version of the view branch BranchGroup node vbBrGr.
return vbBrGr;
}
}
/**
* This class serves to put a locale right-handed 3D coordinate system as
* reference system into the scene. It also creates a background, the
* illumination of the scene and the borders of the virtual universe.
*/
class SceneBuilder1 {
public BranchGroup brGr1;
private CoordSyst coordSyst;
private BoundingSphere boundsBackGr, boundsGen;
private Background backGr;
private NewTextureLoader newTextureLoader;
private AmbientLight ambientLight;
private PointLight pointLight;
private DirectionalLight directionalLight;
private BordersIn bordersIn;
private BordersOut bordersOut;
private static final float dimUniverse = 5.0f; // dimensions of the virtual
// universe are:
// dimUniverse x dimUniverse x dimUniverse
/**
* Create the subgraph #1
*
* @return javax.media.j3d.BranchGroup brGr1 - the root of the subgraph #1
*/
public BranchGroup mySubGraph1() {
// Create the BranchGroup brGr1 of the subgraph #1.
brGr1 = new BranchGroup();
// Create and attach the coordinate system to the brGr1.
coordSyst = new CoordSyst(1.0f, 1.0f, 0.0f, // Color of the x-axis
0.0f, 0.0f, 1.0f, // Color of the y-axis
1.0f, 0.0f, 0.0f, // Color of the z-axis
0.75f); // Lenght of the 3 axes
brGr1.addChild(coordSyst);
// Background setting for the scene.
newTextureLoader = new NewTextureLoader("Images/Ciel_Out.jpg");
newTextureLoader.setImageObserver(newTextureLoader.getImageObserver());
backGr = new Background(newTextureLoader.getImage());
backGr.setImageScaleMode(Background.SCALE_FIT_ALL);
boundsBackGr = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 1000.0);
backGr.setApplicationBounds(boundsBackGr);
brGr1.addChild(backGr);
// A BoundingSphere instance as general bounding region.
boundsGen = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
// Lighting of the scene.
// Create and attach an ambient light.
ambientLight = new AmbientLight(true, new Color3f(0.2f, 0.2f, 0.2f));
ambientLight.setInfluencingBounds(boundsGen);
brGr1.addChild(ambientLight);
// Create and attach a point light.
pointLight = new PointLight(true, new Color3f(1.0f, 1.0f, 0.3f),
new Point3f(-100.0f, 0.0f, 100.0f), new Point3f(0.0f, 0.05f,
0.1f));
pointLight.setInfluencingBounds(boundsGen);
brGr1.addChild(pointLight);
// Create and attach a directional light.
directionalLight = new DirectionalLight(true, new Color3f(0.8f, 1.0f,
1.0f), new Vector3f(-0.5f, -0.5f, -0.5f));
directionalLight.setInfluencingBounds(boundsGen);
brGr1.addChild(directionalLight);
// Create the borders of the virtual universe for the inside view of the
// scene.
bordersIn = new BordersIn(dimUniverse);
brGr1.addChild(bordersIn.myInternalUniverse());
// Create the borders of the virtual universe for the outside view of
// the scene.
bordersOut = new BordersOut(dimUniverse);
brGr1.addChild(bordersOut.myExternalUniverse());
// Compile the subgraph to optimize the performances.
brGr1.compile();
// Return the final version of the BranchGroup node brGr1
return brGr1;
}
}
/**
* This class serves to put a colored cube into the scene graph. It also
* produces a "static rotation" and a "dynamic rotation" of the colored cube.
*/
class SceneBuilder2 {
public BranchGroup brGr2;
private BoundingSphere boundsGen;
private TransformGroup trGr2_1, trGr2_2;
private CoordSyst coordSyst;
private ColorCube colorCube;
private Transform3D trans1, rot1;
private Alpha rotationAlpha;
private AxisAngle4f axe_rot;
private RotationInterpolator rotator;
/**
* Create the subgraph #2
*
* @return javax.media.j3d.BranchGroup brGr2 - the root of the subgraph #2
*/
public BranchGroup mySubGraph2() {
// Create the BranchGroup node brGr2 of the second subgraph.
brGr2 = new BranchGroup();
// A BoundingSphere instance as general bounding region.
boundsGen = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
// Create a Transform3D instance rot1 to perform the necessary
// "static rotation" for the desired cube's position.
rot1 = new Transform3D();
// Rotation of Pi/2 - arctan(1/sqrt(2)) = 0.955 rad about the
// (1,0,-1)-axis passing through the origin.
axe_rot = new AxisAngle4f(1.0f, 0.0f, -1.0f, 0.955f);
rot1.setRotation(axe_rot);
// Create the first TransformGroup node trGr2_1 and attach the
// "static rotation" rot1 instance to it.
trGr2_1 = new TransformGroup(rot1);
// Create and attach a coordinate system to the TransformGroup node
// trGr2_1 of the subgraph #2, that is to the cube.
coordSyst = new CoordSyst(1.0f, 1.0f, 0.0f, // Color of the x-axis
0.0f, 0.0f, 1.0f, // Color of the y-axis
1.0f, 0.0f, 0.0f, // Color of the z-axis
0.4f); // Lenght of the 3 axes
trGr2_1.addChild(coordSyst);
// Create the ColorCube (Shape3D) and attach it to the
// TransformGroup node trGr2_1 of the subgraph #2.
colorCube = new ColorCube(0.5f);
trGr2_1.addChild(colorCube);
// Create the second TransformGroup node trGr2_2.
trGr2_2 = new TransformGroup();
// With the ALLOW_TRANSFORM_WRITE capability, we allow the
// modification of the TransformGroup's code by the behavior's
// code at run time.
trGr2_2.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
// Attach the first node trGr2_1 to the second node trGr2_2.
trGr2_2.addChild(trGr2_1);
// Prepare the RotationInterpolator (Behavior) for the
// cube's rotation about the y-axis.
trans1 = new Transform3D();
// Create the alpha(t) function.
rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 10000, 0,
0, 0, 0, 0);
// Create the cube's rotation about the y-axis.
rotator = new RotationInterpolator(rotationAlpha, trGr2_2, trans1,
0.0f, (float) Math.PI * 2.0f);
rotator.setSchedulingBounds(boundsGen);
trGr2_2.addChild(rotator);
brGr2.addChild(trGr2_2);
// Compile the subgraph to optimize the performances.
brGr2.compile();
// Return the final version of the BranchGroup node brGr2
return brGr2;
}
}
/**
* This class serves to attache both the BranchGraph31 and BranchGraph32 to the
* Locale and to pick the tetrahedron.
*/
/*
* Note: It is not always necessary to use "detach" and "add" to add/remove a
* subgraph from a scene graph. In many cases the using of the setEnable()
* method, to turn a subgraph on and off, is adequate.
*/
class SceneBuilder3 {
public BranchGroup brGr3;
private AddDetachEarthBehavior addDetachEarthBehavior;
private BoundingSphere boundsGen, pickBounds;
private Canvas3D canvas3D; // needed 3 times for the Picking of the
// tetrahedron
private PickRotateBehavior pickRotBehavior;
private PickZoomBehavior pickZoomBehavior;
private PickTranslateBehavior pickTransBehavior;
private SceneBuilder31 sceneBuilder31;
private SceneBuilder32 sceneBuilder32;
private Tetrahedron tetrahedron;
/**
* Constructor that allows to specify the desired Canvas3D.
*
* @param javax.media.j3d.Canvas3D
* canv - the active Canvas3D
*/
public SceneBuilder3(Canvas3D canv) {
canvas3D = canv;
}
/**
* Create the subgraph #3
*
* @return javax.media.j3d.BranchGroup brGr3 - the root of the subgraph #3
*/
public BranchGroup mySubGraph3() {
// Create the BranchGroup node brGr3, in other words the root of
// the subgraph31 and subgraph32.
brGr3 = new BranchGroup();
// To allow the detach/add process of the subgraph 32 from the
// BranchGroup node brGr3.
brGr3.setCapability(Group.ALLOW_CHILDREN_READ);
brGr3.setCapability(Group.ALLOW_CHILDREN_WRITE);
brGr3.setCapability(Group.ALLOW_CHILDREN_EXTEND);
// A BoundingSphere instance as picking bound region.
pickBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 5.0);
// A BoundingSphere instance as general bounding region.
boundsGen = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
// Create and attach the subgraph31 with the tetrahedron
// to the BranchGroup node brGr3.
tetrahedron = new Tetrahedron(1.0f);
sceneBuilder31 = new SceneBuilder31(tetrahedron.myTetrahedron());
brGr3.addChild(sceneBuilder31.mySubGraph31());
// Picking of the tetrahedron
// Note:It's the instruction:
// trGr31.setCapability(TransformGroup.ENABLE_PICK_REPORTING)
// in the class SceneBuilder31 that determines if the
// tetrahedron is pickable or not.
// Pick and translate the tetrahedron parallel to the z-axis if the
// mouse pointer is over it.
pickZoomBehavior = new PickZoomBehavior(brGr3, canvas3D, pickBounds);
// pickZoomBehavior.setEnable(ctrlDown);
brGr3.addChild(pickZoomBehavior);
// Pick and translate the tetrahedron in the (x-y)-plane if the
// mouse pointer is over it.
pickTransBehavior = new PickTranslateBehavior(brGr3, canvas3D,
pickBounds);
// pickTransBehavior.setEnable(ctrlDown);
brGr3.addChild(pickTransBehavior);
// Pick and rotate the tetrahedron if the mouse pointer is over it.
pickRotBehavior = new PickRotateBehavior(brGr3, canvas3D, pickBounds);
// pickRotBehavior.setEnable(ctrlDown);
brGr3.addChild(pickRotBehavior);
// Create the subgraph32 ===> the earth in double rotation.
sceneBuilder32 = new SceneBuilder32();
brGr3.addChild(sceneBuilder32.mySubGraph32());
// Create an instance of the AddDetachEarthBehavior class to
// allow the detach/add process of the subgraph32.
addDetachEarthBehavior = new AddDetachEarthBehavior(this,
sceneBuilder32);
addDetachEarthBehavior.setSchedulingBounds(boundsGen);
brGr3.addChild(addDetachEarthBehavior);
// Compile the subgraph to optimize the performances.
brGr3.compile();
// Return the final version of the BranchGroup node brGr3
return brGr3;
}
/**
* This method is called up in the DetachEathBehavior class to add a new
* representation of the earth.
*/
public void addEarth() {
brGr3.addChild(sceneBuilder32.mySubGraph32());
}
}
/**
* This class serves to put the objet (a tetrahedron) into the scene. It also
* produces a "static translation" of the tetrahedron and allows its picking.
*/
class SceneBuilder31 {
public TransformGroup trGr31;
private Shape3D myObject;
private Transform3D transl;
private Vector3d vectransl; // translation
/**
* Constructor that allows to specify the desired object.
*
* @param javax.media.j3d.Shape3D
* objet - the Shape3D instance which will be attached to the
* subgraph #31
*/
public SceneBuilder31(Shape3D object) {
myObject = object;
}
/**
* Create the subgraph #31 and prepare the TransformGroup node trGr31 for
* the tetrahedron's picking.
*
* @return javax.media.j3d.TransformGroup trGr31_2 - the root of the
* subgraph #31
*/
public TransformGroup mySubGraph31() {
// Create a Transform3D node to execute the desired "static translation"
// of the tetrahedron ===> start position.
transl = new Transform3D();
vectransl = new Vector3d(0.0, -2.0, 0.0); // translation
transl.set(vectransl);
// Create the TransformGroup node trGr31, attach into it the "static
// translation" instance and prepare it for the picking.
trGr31 = new TransformGroup(transl);
trGr31.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
trGr31.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
trGr31.setCapability(TransformGroup.ENABLE_PICK_REPORTING);
// Attach myObject (Shape3D leaf) to the TransformGroup node trGr31.
trGr31.addChild(myObject);
// Return the final version of the TransformGroup node trGr31.
return trGr31;
}
}
/**
* This class serves to put the rendering of five different earth's
* representations (each with a right-handed 3D coordinate system) into the
* scene graph. It also produces a "static translation" and a double "dynamic
* rotation" of each earth's representations and allows to detach and then add
* again this subgraph32 from to the entire scene graph.
*/
/*
* Note: It is not always necessary to use "detach" and "add" to detach/add a
* subgraph from a scene graph. In many cases the using of the setEnable()
* method, to turn a subgraph on and off, is adequate.
*/
class SceneBuilder32 {
public BranchGroup brGr32;
private TransformGroup trGr32_1, trGr32_2, trGr32_3;
private int thisEarth;
private BoundingSphere boundsGen;
private CoordSyst coordSyst;
private SwitchBehavior switchBehavior;
private Switch switchEarths; // the Switch for the 5 different earth's
// representations
private Transform3D transl;
private Vector3d vectTransl; // translation
private Alpha rotationAlpha_1, rotationAlpha_2;
private RotationInterpolator rotator_1, rotator_2;
// The five different earth's representations
private Earth earth_Points, earth_Lines, earth_Polygons, earth_Gouraud,
earth_Texture;
/**
* Create the subgraph #32
*
* @return javax.media.j3d.TransformGroup trGr32_3 - the root of the
* subgraph #32
*/
public BranchGroup mySubGraph32() {
// A BoundingSphere instance as general bounding region.
boundsGen = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
// Create the first TransformGroup node trGr32_1 to:
// 1) attach the Switch node with the five different earth's
// representations to the subgraph32
// 2) attach a coordinate system to each earth's representation
// 3) rotate each earth about its own y-axis.
trGr32_1 = new TransformGroup();
// With the ALLOW_TRANSFORM_WRITE capability, we allow the
// modification of the TransformGroup's code by the behavior's
// code at run time.
trGr32_1.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
// SwitchBehavior is the class which controls the fonctioning of
// the switchEarths node.
switchBehavior = new SwitchBehavior(this);
switchBehavior.setSchedulingBounds(boundsGen);
trGr32_1.addChild(switchBehavior);
// The Switch which allows the rendering of the five different
// earth's representations.
switchEarths = new Switch();
// With the ALLOW_TRANSFORM_WRITE, ALLOW_SWITCH_WRITE and
// ALLOW_CHILDREN_READ
// capabilities we allow to get or set new capabilities.
switchEarths.setCapability(Switch.ALLOW_SWITCH_READ);
switchEarths.setCapability(Switch.ALLOW_SWITCH_WRITE);
switchEarths.setCapability(Switch.ALLOW_CHILDREN_READ);
// Attach the different earth's representations to the Switch node.
// Increasing
earth_Points = new Earth("points", 0.4f);
switchEarths.addChild(earth_Points.myEarth()); // # 0
earth_Lines = new Earth("lines", 0.4f);
switchEarths.addChild(earth_Lines.myEarth()); // # 1
earth_Polygons = new Earth("polygons", 0.4f);
switchEarths.addChild(earth_Polygons.myEarth()); // # 2
earth_Gouraud = new Earth("gouraud", 0.4f);
switchEarths.addChild(earth_Gouraud.myEarth()); // # 3
earth_Texture = new Earth("texture", 0.4f);
switchEarths.addChild(earth_Texture.myEarth()); // # 4
// Decreasing
switchEarths.addChild(earth_Texture.myEarth()); // # 4
switchEarths.addChild(earth_Gouraud.myEarth()); // # 3
switchEarths.addChild(earth_Polygons.myEarth()); // # 2
switchEarths.addChild(earth_Lines.myEarth()); // # 1
switchEarths.addChild(earth_Points.myEarth()); // # 0
// Attach the Switch node with the five different earth's
// representations to the TransformGroup node trGr32_1.
trGr32_1.addChild(switchEarths);
// Create and attach a coordinate system to the TransformGroup node
// trGr32_1, that is to each earth's representation.
coordSyst = new CoordSyst(1.0f, 1.0f, 0.0f, // Color of the x-axis
0.0f, 0.0f, 1.0f, // Color of the y-axis
1.0f, 0.0f, 0.0f, // Color of the z-axis
0.6f); // Lenght of the 3 axes
trGr32_1.addChild(coordSyst);
// Create the alpha(t) function for the earth's rotation about
// its own y-axis.
rotationAlpha_1 = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 10000,
0, 0, 0, 0, 0);
// Create the earth's rotation about its own y-axis.
rotator_1 = new RotationInterpolator(rotationAlpha_1, trGr32_1,
new Transform3D(), 0.0f, (float) Math.PI * 2.0f);
rotator_1.setSchedulingBounds(boundsGen);
trGr32_1.addChild(rotator_1);
// Create a Transform3D instance to execute the desired "static
// translation" of the earth, that is the rotation radius around
// the sun.
transl = new Transform3D();
vectTransl = new Vector3d(2.5, 0.0, 0.0);
transl.set(vectTransl);
// Create the second TransformGroup node trGr32_2 and attach the
// "static translation" transl to it.
trGr32_2 = new TransformGroup(transl);
// Attach the trGr32_1 node to the trGr32_2 node.
trGr32_2.addChild(trGr32_1);
// Create the third TransformGroup node trGr32_3 for the earth's
// rotation around the sun.
trGr32_3 = new TransformGroup();
// With the ALLOW_TRANSFORM_WRITE capability, we allow the
// modification of the TransformGroup's code by the behavior's
// code at run time.
trGr32_3.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
// Attach the trGr32_2 node to the trGr32_3 node.
trGr32_3.addChild(trGr32_2);
// Create the alpha(t) function for the earth's rotation around the sun.
rotationAlpha_2 = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 20000,
0, 0, 0, 0, 0);
// To restart correctly the rotation of the earth around the
// sun after a detach/add process of the subgraph32 from the
// BranchGroup node brGr3.
rotationAlpha_2.setStartTime(System.currentTimeMillis());
// Create the earth's rotation around the sun.
rotator_2 = new RotationInterpolator(rotationAlpha_2, trGr32_3,
new Transform3D(), 0.0f, (float) Math.PI * 2.0f);
rotator_2.setSchedulingBounds(boundsGen);
trGr32_3.addChild(rotator_2);
// To allow the detaching of this subgraph32 from the
// BranchGroup node brGr3.
brGr32 = new BranchGroup();
brGr32.setCapability(BranchGroup.ALLOW_DETACH);
brGr32.addChild(trGr32_3);
// Return the final version of the BranchGroup node brGr32.
return brGr32;
}
/**
* This method is called up in the SwitchBehavior class and gets the new
* earth's representation which has to be drawn.
*
* @param thisEarth -
* the new earth's representation to draw.
*/
public void setNewEarth(int thisEarth) {
switchEarths.setWhichChild(thisEarth);
}
// This method is called up in the DetachEathBehavior class to
// detach the momentary representation of the earth.
public void detachEarth() {
brGr32.detach();
}
}
/*
* @(#)NewTextureLoades.java 1.0 99/10/21
*
* 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.
*/
/**
* A texture loading utility that doesn't require an image observer for
* constructing objects. This class extends the TextureLoader class of the
* com.sun.j3d.utils.image package.
*
*/
class NewTextureLoader extends TextureLoader {
static java.awt.Component observer;
/**
* Specify an object to server as the image observer. Use this method once
* before constructing any texture loaders.
*
* @param imageObserver
* the object to be used in subsequent NewTextureLoader
* constuctions
*/
public static void setImageObserver(java.awt.Component imageObserver) {
observer = imageObserver;
}
/**
* Retreve the object used as the image observer for NewTextureLoader
* objects. Use this method when the image observer is needed.
*
* @return the object used in as the image observer in subsequent
* NewTextureLoader constuctions
*/
public static java.awt.Component getImageObserver() {
return observer;
}
// constructors without an image observer argument
/**
* Constructs a NewTextureLoader object loading the specified iamge in
* default (RGBA) format. The an image observer must be set using the
* setImageObserver() method before using this constructor.
*
* @param image
* the image object to load
*/
public NewTextureLoader(java.awt.Image image) {
super(image, observer);
}
/**
* Constructs a NewTextureLoader object loading the specified image and
* option flags in the default (RGBA) format. The an image observer must be
* set using the setImageObserver() method before using this constructor.
*
* @param image
* the image object to load
* @param flags
* the flags to use in construction (e.g. generate mipmap)
*/
public NewTextureLoader(java.awt.Image image, int flags) {
super(image, flags, observer);
}
/**
* Constructs a NewTextureLoader object loading the specified file using the
* specified format. The an image observer must be set using the
* setImageObserver() method before using this constructor.
*
* @param image
* the image object to load
* @param format
* specificaiton of which channels to use (e.g. RGB)
*/
public NewTextureLoader(java.awt.Image image, java.lang.String format) {
super(image, format, observer);
}
/**
* Constructs a NewTextureLoader object loading the specified file with
* specified format and flags. The an image observer must be set using the
* setImageObserver() method before using this constructor.
*
* @param image
* the image object to load
* @param format
* specificaiton of which channels to use (e.g. RGB)
* @param flags
* the flags to use in construction (e.g. generate mipmap)
*/
public NewTextureLoader(java.awt.Image image, java.lang.String format,
int flags) {
super(image, format, flags, observer);
}
/**
* Constructs a NewTextureLoader object loading the specified file using the
* default format (RGBA). The an image observer must be set using the
* setImageObserver() method before using this constructor.
*
* @param fname
* the name of the file to load
*/
public NewTextureLoader(java.lang.String fname) {
super(fname, observer);
}
/**
* Constructs a NewTextureLoader object loading the specified file with the
* specified flags. The an image observer must be set using the
* setImageObserver() method before using this constructor.
*
* @param fname
* the name of the file to load
* @param flags
* the flags to use in construction (e.g. generate mipmap)
*/
public NewTextureLoader(java.lang.String fname, int flags) {
super(fname, flags, observer);
}
/**
* Constructs a NewTextureLoader object loading the specified file using the
* specified format. The an image observer must be set using the
* setImageObserver() method before using this constructor.
*
* @param fname
* the name of the file to load
* @param format
* specificaiton of which channels to use (e.g. RGB)
*/
public NewTextureLoader(java.lang.String fname, java.lang.String format) {
super(fname, format, observer);
}
/**
* Constructs a NewTextureLoader object loading the specified file using the
* specified format and flags. The an image observer must be set using the
* setImageObserver() method before using this constructor.
*
* @param fname
* the name of the file to load
* @param format
* specificaiton of which channels to use (e.g. RGB)
* @param flags
* the flags to use in construction (e.g. generate mipmap)
*/
public NewTextureLoader(java.lang.String fname, java.lang.String format,
int flags) {
super(fname, format, flags, observer);
}
/**
* Constructs a NewTextureLoader object loading the specified URL using the
* default format. The an image observer must be set using the
* setImageObserver() method before using this constructor.
*
* @param url
* specifies the URL of the image to load
*/
public NewTextureLoader(java.net.URL url) {
super(url, observer);
}
/**
* Constructs a NewTextureLoader object loading the specified URL using the
* specified flags. The an image observer must be set using the
* setImageObserver() method before using this constructor.
*
* @param url
* specifies the URL of the image to load
* @param flags
* the flags to use in construction (e.g. generate mipmap)
*/
public NewTextureLoader(java.net.URL url, int flags) {
super(url, flags, observer);
}
/**
* Constructs a NewTextureLoader object loading the specified URL using the
* specified format. The an image observer must be set using the
* setImageObserver() method before using this constructor.
*
* @param url
* specifies the URL of the image to load
* @param format
* specificaiton of which channels to use (e.g. RGB)
*/
public NewTextureLoader(java.net.URL url, java.lang.String format) {
super(url, format, observer);
}
/**
* Constructs a NewTextureLoader object loading the specified URL using the
* specified format and flags. The an image observer must be set using the
* setImageObserver() method before using this constructor.
*
* @param url
* specifies the URL of the image to load
* @param format
* specificaiton of which channels to use (e.g. RGB)
* @param flags
* the flags to use in construction (e.g. generate mipmap)
*/
public NewTextureLoader(java.net.URL url, java.lang.String format, int flags) {
super(url, format, flags, observer);
}
} // end of TexturedPlane class
/**
* This class is a keyboard behavior to control the partly rotation (rotate up
* and rotate down) of the camera.
*/
class Camera_Rot_Up_Down extends Behavior {
// The TransformGroup node to modify by the keyboard interaction.
private TransformGroup target_trGr;
// Wake up event when a key is pressed.
private WakeupOnAWTEvent wakeUp = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
// The key event
private KeyEvent keyEvent;
// The angle to turn when the Home key or End key is pressed.
private float angle = (float) Math.PI / 36;
private Transform3D myKeyNavTransf3D = new Transform3D();
private Transform3D rotation = new Transform3D();
/**
* Constructor that allows to specify the desired target transform group.
*
* @param javax.media.j3d.TransformGroup
* target - the target transform group
*/
public Camera_Rot_Up_Down(TransformGroup target) {
target_trGr = target;
}
/**
* Override Behavior's initialize method to setup wakeup criteria.
*/
public void initialize() {
wakeupOn(wakeUp);
}
/**
* Override Behavior's stimulus method to handle the event. This method is
* called when a key on the keyboard has been pressed and operates on the
* specified transform group to move the camera.
*
* @param Enumeration
* criteria - all pressed keys in a list. This will be passed by
* the system.
*/
public void processStimulus(Enumeration criteria) {
WakeupOnAWTEvent eventToWakeUp;
AWTEvent[] events;
if (criteria.hasMoreElements()) {
// Decode the wakeup criteria
eventToWakeUp = (WakeupOnAWTEvent) criteria.nextElement();
events = eventToWakeUp.getAWTEvent();
keyEvent = (KeyEvent) events[0];
int keyCode = keyEvent.getKeyCode();
// Perform our processing
// Get the initial transformation from target and put it
// into myKeyNavTransf3D
target_trGr.getTransform(myKeyNavTransf3D);
// Not any of the 2 rotations don't act simultaneously.
switch (keyCode) {
case KeyEvent.VK_HOME: // Home - rotate up
rotation.rotX(angle);
break;
case KeyEvent.VK_END: // End - rotate down
rotation.rotX(-angle);
break;
default:
rotation.rotX(0.0f);
}
myKeyNavTransf3D.mul(rotation);
// Return the final transformation myKeyNavTransf3D to target
target_trGr.setTransform(myKeyNavTransf3D);
}
// Set wakeup criteria for next time.
wakeupOn(wakeUp);
}
}
/**
* This class creates an aimer in the ViewBranch.
*/
class Aimer extends Shape3D {
private float scale_XYZ;
private LineArray aimer;
private float scaledExtremites[];
/**
* Constructor that allows to specify the desired initial aimer's
* dimensions.
*
* @param type
* float s_XYZ - the scale factor to adjust the aimer's
* dimensions
*/
public Aimer(float s_XYZ) {
scale_XYZ = s_XYZ;
}
/**
* Construct an aimer.
*
* @return javax.media.j3d.Shape3D myAimer - the constructed aimer.
*/
public Shape3D myAimer() {
// Construction of the aimer (LineArray).
aimer = new LineArray(20, LineArray.COORDINATES | LineArray.COLOR_3);
// Scalling of the vertices of the aimer using scale_XYZ.
scaledExtremites = new float[extremites.length];
for (int i = 0; i < extremites.length; i++)
scaledExtremites[i] = extremites[i] * scale_XYZ;
aimer.setCoordinates(0, scaledExtremites);
aimer.setColors(0, color);
this.setGeometry(aimer);
return this;
}
// Aimer's geometry
private static final float extremites[] = {
// top-front
0.075f, 0.05f, -1.0f, -0.075f, 0.05f, -1.0f,
// left-front
-0.075f, 0.05f, -1.0f, -0.075f, -0.05f, -1.0f,
// bottom-front
-0.075f, -0.05f, -1.0f, 0.075f, -0.05f, -1.0f,
// right-front
0.075f, -0.05f, -1.0f, 0.075f, 0.05f, -1.0f,
// top-back
0.04f, 0.025f, -1.0f, -0.04f, 0.025f, -1.0f,
// left-back
-0.04f, 0.025f, -1.0f, -0.04f, -0.025f, -1.0f,
// bottom-back
-0.04f, -0.025f, -1.0f, 0.04f, -0.025f, -1.0f,
// right-back
0.04f, -0.025f, -1.0f, 0.04f, 0.025f, -1.0f,
// cross
-0.04f, 0.025f, -1.0f, 0.04f, -0.025f, -1.0f, -0.04f, -0.025f,
-1.0f, 0.04f, 0.025f, -1.0f };
// Colors of the aimer (each vertex in aimer is red).
float color[] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // front-frame
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // back-frame
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // cross
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f };
}
/**
* This class creates a simple cube with a given texture to simulate the inside
* of the virtual universe.
*/
class BordersIn extends Shape3D {
private QuadArray cube;
private float scale_XYZ;
private NewTextureLoader newTextureLoader;
private Texture texture;
private TextureAttributes textAttr;
/**
* Constructor that allows to specify the desired scale factor of the
* virtual universe.
*
* @param type
* float s_XYZ - the scale factor to adjust the borders of the
* virtual universe
*/
public BordersIn(float s_XYZ) {
scale_XYZ = s_XYZ;
}
/**
* Construction of the desired borders of the virtual universe (cube).
*
* @return javax.media.j3d.Shape3D myUniverse - the constructed borders of
* the virtual universe
*/
public Shape3D myInternalUniverse() {
cube = new QuadArray(cubeFaces.length, QuadArray.COORDINATES
| QuadArray.TEXTURE_COORDINATE_2);
////////////////////// Geometric part ///////////////////////////
// Scaling of the faces.
for (int i = 0; i < cubeFaces.length; i++)
cubeFaces[i].scale(scale_XYZ);
cube.setCoordinates(0, cubeFaces);
for (int i = 0; i < cubeFaces.length; i++) {
// With i mod 4 ==> 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 for
// the 4 vertices of the 6 faces, thus each vertex has
// a point in the texture space. In this case, each cube's
// face has the same texture coordinates.
cube.setTextureCoordinate(0, i, textCoord[i % 4]);
}
// The geometry is passed to the instance this of the cube.
this.setGeometry(cube);
////////////////////// Appearance part ///////////////////////////
Appearance appearance = new Appearance();
// This code block is only necessary to insure, in all cases, the
// correct
// rendering of the 6 faces of the cube (bug in Java3D version 1.2.0 !).
// Set up the polygon's rendering-mode
PolygonAttributes polygonAttributes = new PolygonAttributes();
polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL);
appearance.setPolygonAttributes(polygonAttributes);
// Loading the texture for the 6 cube's faces.
newTextureLoader = new NewTextureLoader("Images/Galaxies.gif");
newTextureLoader.setImageObserver(newTextureLoader.getImageObserver());
texture = newTextureLoader.getTexture();
appearance.setTexture(texture);
// Application modes of the texture
textAttr = new TextureAttributes();
textAttr.setTextureMode(TextureAttributes.MODULATE); // there still are:
// BLEND, COMBINE,
// DECAL, and REPLACE
appearance.setTextureAttributes(textAttr);
// The appearance is passed to the instance this of the cube.
this.setAppearance(appearance);
return this;
}
// The 8 vertices p1, p2, ..., p8 of the cube.
private static final Point3f p1 = new Point3f(1.0f, 1.0f, 1.0f);
private static final Point3f p2 = new Point3f(1.0f, -1.0f, 1.0f);
private static final Point3f p3 = new Point3f(-1.0f, -1.0f, 1.0f);
private static final Point3f p4 = new Point3f(-1.0f, 1.0f, 1.0f);
private static final Point3f p5 = new Point3f(-1.0f, 1.0f, -1.0f);
private static final Point3f p6 = new Point3f(-1.0f, -1.0f, -1.0f);
private static final Point3f p7 = new Point3f(1.0f, -1.0f, -1.0f);
private static final Point3f p8 = new Point3f(1.0f, 1.0f, -1.0f);
// The 6 faces of the cube.
private static final Point3f cubeFaces[] = { // internal front face
p5, p6, p7, p8,
// internal right face
p1, p8, p7, p2,
// internal back face
p1, p2, p3, p4,
// internal left face
p4, p3, p6, p5,
// internal top face
p1, p4, p5, p8,
// internal bottom face
p3, p2, p7, p6 };
// Coordinates in the texture space. Each cube's face has the
// same texture coordinates.
private TexCoord2f textCoord[] = { new TexCoord2f(0.0f, 0.0f),
new TexCoord2f(0.0f, 1.0f), new TexCoord2f(1.0f, 1.0f),
new TexCoord2f(1.0f, 0.0f) };
}
/**
* This class creates a simple cube with a given texture to simulate the outside
* of the virtual universe.
*/
class BordersOut extends Shape3D {
private QuadArray cube;
private float scale_XYZ;
private NewTextureLoader newTextureLoader;
private Texture texture;
private TextureAttributes textAttr;
/**
* Constructor that allows to specify the desired scale factor of the
* virtual universe.
*
* @param type
* float s_XYZ - the scale factor to adjust the borders of the
* virtual universe
*/
public BordersOut(float s_XYZ) {
scale_XYZ = s_XYZ;
}
/**
* Construction of the desired borders of the virtual universe (cube).
*
* @return javax.media.j3d.Shape3D myUniverse - the constructed borders of
* the virtual universe
*/
public Shape3D myExternalUniverse() {
cube = new QuadArray(cubeFaces.length, QuadArray.COORDINATES
| QuadArray.TEXTURE_COORDINATE_2);
////////////////////// Geometric part ///////////////////////////
// Scaling of the faces.
for (int i = 0; i < cubeFaces.length; i++)
cubeFaces[i].scale(scale_XYZ);
cube.setCoordinates(0, cubeFaces);
for (int i = 0; i < cubeFaces.length; i++) {
// With i mod 4 ==> 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 for
// the 4 vertices of the 6 faces, thus each vertex has
// a point in the texture space. In this case, each cube's
// face has the same texture coordinates.
cube.setTextureCoordinate(0, i, textCoord[i % 4]);
}
// The geometry is passed to the instance this of the cube.
this.setGeometry(cube);
////////////////////// Appearance part ///////////////////////////
Appearance appearance = new Appearance();
// This code block is only necessary to insure, in all cases, the
// correct
// rendering of the 6 faces of the cube (bug in Java3D version 1.2.0 !).
// Set up the polygon's rendering-mode
PolygonAttributes polygonAttributes = new PolygonAttributes();
polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL);
appearance.setPolygonAttributes(polygonAttributes);
// Loading the texture for the 6 cube's faces.
newTextureLoader = new NewTextureLoader("Images/Ciel_Outside.jpg");
newTextureLoader.setImageObserver(newTextureLoader.getImageObserver());
texture = newTextureLoader.getTexture();
appearance.setTexture(texture);
// Application modes of the texture
textAttr = new TextureAttributes();
textAttr.setTextureMode(TextureAttributes.MODULATE); // there still are:
// BLEND, COMBINE,
// DECAL, and REPLACE
appearance.setTextureAttributes(textAttr);
// The appearance is passed to the instance this of the cube.
this.setAppearance(appearance);
return this;
}
// The 8 vertices p1, p2, ..., p8 of the cube.
private static final Point3f p1 = new Point3f(1.0f, 1.0f, 1.0f);
private static final Point3f p2 = new Point3f(1.0f, -1.0f, 1.0f);
private static final Point3f p3 = new Point3f(-1.0f, -1.0f, 1.0f);
private static final Point3f p4 = new Point3f(-1.0f, 1.0f, 1.0f);
private static final Point3f p5 = new Point3f(-1.0f, 1.0f, -1.0f);
private static final Point3f p6 = new Point3f(-1.0f, -1.0f, -1.0f);
private static final Point3f p7 = new Point3f(1.0f, -1.0f, -1.0f);
private static final Point3f p8 = new Point3f(1.0f, 1.0f, -1.0f);
// The 6 faces of the cube.
private static final Point3f cubeFaces[] = { // external front face
p5, p8, p7, p6,
// external right face
p8, p1, p2, p7,
// external back face
p1, p4, p3, p2,
// external left face
p4, p5, p6, p3,
// external top face
p8, p5, p4, p1,
// external bottom face
p2, p3, p6, p7 };
// Coordinates in the texture space. Each cube's face has the
// same texture coordinates.
private TexCoord2f textCoord[] = { new TexCoord2f(1.0f, 1.0f),
new TexCoord2f(0.0f, 1.0f), new TexCoord2f(0.0f, 0.0f),
new TexCoord2f(1.0f, 0.0f) };
}
/**
* This class is a switch behavior to control the rendering of the five
* different earth's representations.
*/
class SwitchBehavior extends Behavior {
// The Alpha class which gives the alpha values to command the Switch node.
private Alpha switchAlpha;
private float switchAlphaValue;
// The class which contains the Switch node for the rendering of
// the 5 different earth's representations.
private SceneBuilder32 sceneBuilder32 = null;
// The earth which will be rendered.
private int thisEarth = 0;
// Wakeup event after each frame.
private WakeupOnElapsedFrames wakeUp = new WakeupOnElapsedFrames(0);
/**
* Constructor that allows to specify the reference of the SceneBuilder32's
* instance.
*
* @param sceneBuilder32 -
* the SceneBuilder32 instance
*/
public SwitchBehavior(SceneBuilder32 sceneBuilder32) {
super();
// Create the alpha(t) function to automaticaly switch between the
// five different earth's representations.
switchAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE
| Alpha.DECREASING_ENABLE, 0, 0, 10000, 0, 0, 10000, 0, 0);
// Get the SceneBuilder32 reference
this.sceneBuilder32 = sceneBuilder32;
}
/**
* Override Behavior's initialize method to setup wakeup criteria.
*/
public void initialize() {
wakeupOn(wakeUp);
}
/**
* Override Behavior's stimulus method to handle the event. This method is
* called up when the define number of frames is draw.
*
* @param criteria -
* the wake-up criteria
*/
public void processStimulus(Enumeration criteria) {
switchAlphaValue = switchAlpha.value();
if (switchAlphaValue <= 0.15f)
thisEarth = 0;
else if (0.15f < switchAlphaValue && switchAlphaValue <= 0.4f)
thisEarth = 1;
else if (0.4f < switchAlphaValue && switchAlphaValue <= 0.6f)
thisEarth = 2;
else if (0.6f < switchAlphaValue && switchAlphaValue <= 0.8f)
thisEarth = 3;
else if (0.8f < switchAlphaValue)
thisEarth = 4;
sceneBuilder32.setNewEarth(thisEarth);
// Set wakeup criteria for next time.
wakeupOn(wakeUp);
}
}
/**
* This class creates a simple colored cube.
*/
class ColorCube extends Shape3D {
private QuadArray cube;
// The constant colors of each cube's face
private static final Color3f red = new Color3f(1.0f, 0.0f, 0.0f);
private static final Color3f green = new Color3f(0.0f, 1.0f, 0.0f);
private static final Color3f blue = new Color3f(0.0f, 0.0f, 1.0f);
private static final Color3f yellow = new Color3f(1.0f, 1.0f, 0.0f);
private static final Color3f magenta = new Color3f(1.0f, 0.0f, 1.0f);
private static final Color3f cyan = new Color3f(0.0f, 1.0f, 1.0f);
/**
* Constructor that allows to specify the desired scale factor for the
* colored cube.
*
* @param type
* float s_XYZ - the scale factor to adjust the edges's length of
* the colored cube
*/
public ColorCube(float scale_XYZ) { // 24
cube = new QuadArray(cubeFaces.length, QuadArray.COORDINATES
| QuadArray.COLOR_3);
// Scaling of vertices
for (int i = 0; i < cubeFaces.length; i++)
cubeFaces[i].scale(scale_XYZ);
cube.setCoordinates(0, cubeFaces);
cube.setColors(0, colorsFaces);
this.setGeometry(cube);
}
// The 8 vertices p1, ..., p8 of the cube.
private static final Point3f p1 = new Point3f(1.0f, 1.0f, 1.0f);
private static final Point3f p2 = new Point3f(-1.0f, 1.0f, 1.0f);
private static final Point3f p3 = new Point3f(-1.0f, -1.0f, 1.0f);
private static final Point3f p4 = new Point3f(1.0f, -1.0f, 1.0f);
private static final Point3f p5 = new Point3f(1.0f, -1.0f, -1.0f);
private static final Point3f p6 = new Point3f(1.0f, 1.0f, -1.0f);
private static final Point3f p7 = new Point3f(-1.0f, 1.0f, -1.0f);
private static final Point3f p8 = new Point3f(-1.0f, -1.0f, -1.0f);
// The 6 faces of the cube.
private static final Point3f cubeFaces[] = { // front face
p1, p2, p3, p4,
// right face
p1, p4, p5, p6,
// back face
p8, p7, p6, p5,
// left face
p2, p7, p8, p3,
// top face
p1, p6, p7, p2,
// bottom face
p5, p4, p3, p8 };
// The constant colors for the 6 faces.
private static final Color3f[] colorsFaces = {// front face
red, red, red, red,
// back face
green, green, green, green,
// right face
blue, blue, blue, blue,
// left face
yellow, yellow, yellow, yellow,
// top face
magenta, magenta, magenta, magenta,
// bottom face
cyan, cyan, cyan, cyan };
}
/**
* This class is used to detach then add again the subgraph 32 from the scene
* graph.
*/
/*
* Note: It is not always necessary to use "detach" and "add" to add/remove a
* subgraph from a scene graph. In many cases the using of the setEnable()
* method, to turn a subgraph on and off, is adequate.
*/
class AddDetachEarthBehavior extends Behavior {
// The classe which contains the addEarth method.
private SceneBuilder3 sceneBuilder3;
// The classe which contains the detachEarth method.
private SceneBuilder32 sceneBuilder32;
// To control the detach / add sequence.
private boolean validation = false;
// Wake up event when a key is pressed.
private WakeupOnAWTEvent wakeUp = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
// The key event
private KeyEvent keyEvent;
/**
* Constructor that allows to specify the references of the SceneBuilder3's
* and SceneBuilder32's instances.
*
* @param sceneBuilder3 -
* the SceneBuilder3 instance
* @param sceneBuilder32 -
* the SceneBuilder32 instance
*/
public AddDetachEarthBehavior(SceneBuilder3 sceneBuilder3,
SceneBuilder32 sceneBuilder32) {
super();
// Get the SceneBuilder3's and SceneBuilder32's references
this.sceneBuilder3 = sceneBuilder3;
this.sceneBuilder32 = sceneBuilder32;
}
/**
* Override Behavior's initialize method to setup wakeup criteria.
*/
public void initialize() {
wakeupOn(wakeUp);
}
/**
* Override Behavior's stimulus method to handle the event. This method is
* called when a key on the keyboard has been pressed and operates on the
* specified transform group to move the camera.
*
* @param Enumeration
* criteria - all pressed keys in a list. This will be passed by
* the system.
*/
public void processStimulus(Enumeration criteria) {
WakeupOnAWTEvent eventToWakeUp;
AWTEvent[] events;
if (criteria.hasMoreElements()) {
// Decode the wakeup criteria
eventToWakeUp = (WakeupOnAWTEvent) criteria.nextElement();
events = eventToWakeUp.getAWTEvent();
keyEvent = (KeyEvent) events[0];
int keyCode = keyEvent.getKeyCode();
// Perform our processing
switch (keyCode) {
case KeyEvent.VK_A:
if (validation) {
sceneBuilder3.addEarth();
System.out.println("===> Add Earth");
validation = false;
}
break;
case KeyEvent.VK_D:
if (!validation) {
sceneBuilder32.detachEarth();
System.out.println("===> Detach Earth");
validation = true;
}
break;
default:
}
}
// Set wakeup criteria for next time.
wakeupOn(wakeUp);
}
}
/**
* This class is a keyboard behavior to control the translation and the partly
* rotation (turn left and turn right) of the camera.
*
* After a translation or rotation performed by using this class, the
* observation direction of the virtual camera will always stay parallel to the
* coordinate system's (x-y)-plane of the parent node.
*
* In the case of this Demo application, it will be the coordinate system
* associated with the Locale node.
*/
class Camera_Transl_Turn extends Behavior {
// The TransformGroup node to modify by the keyboard interaction.
private TransformGroup target_trGr;
// Wake up event when a key is pressed.
private WakeupOnAWTEvent wakeUp = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
// The key event
private KeyEvent keyEvent;
// The angle to turn when a Direction Key and the Shift key are pressed.
private float angle = (float) Math.PI / 36;
// The step size to move when a Direction Key or the PageDown or
// PageUp key is pressed.
private float step = 1f;
private Transform3D myKeyNavTransf3D = new Transform3D();
private Vector3f translation = new Vector3f();
private Vector3f dtrans = new Vector3f();
private Vector3f dtrans0 = new Vector3f();
private Transform3D trans_rot = new Transform3D();
/**
* Constructor that allows to specify the desired target transform group.
*
* @param javax.media.j3d.TransformGroup
* target - the target transform group
*/
public Camera_Transl_Turn(TransformGroup target) {
target_trGr = target;
}
/**
* Override Behavior's initialize method to setup wakeup criteria.
*/
public void initialize() {
wakeupOn(wakeUp);
}
/**
* Override Behavior's stimulus method to handle the event. This method is
* called when a key on the keyboard has been pressed and operates on the
* specified transform group to move the camera.
*
* @param Enumeration
* criteria - all pressed keys in a list. This will be passed by
* the system.
*/
public void processStimulus(Enumeration criteria) {
WakeupOnAWTEvent eventToWakeUp;
AWTEvent[] events;
if (criteria.hasMoreElements()) {
// Decode the wakeup criteria
eventToWakeUp = (WakeupOnAWTEvent) criteria.nextElement();
events = eventToWakeUp.getAWTEvent();
keyEvent = (KeyEvent) events[0];
int keyCode = keyEvent.getKeyCode();
// Perform our processing
// Get the initial transformation from target and put it into
// myKeyNavTransf3D
target_trGr.getTransform(myKeyNavTransf3D);
// Set the translational components of myKeyNavTransf3D in
// translation
myKeyNavTransf3D.get(translation);
// Not any of the 8 motions (6 translations and 2 rotations)
// don't act simultaneously.
switch (keyCode) {
case KeyEvent.VK_UP: // Up Arrow - to move forward
trans_rot.set(new Vector3f(0.0f, 0.0f, -step));
break;
case KeyEvent.VK_DOWN: // Down Arrow - to move backwards
trans_rot.set(new Vector3f(0.0f, 0.0f, step));
break;
case KeyEvent.VK_LEFT: // Left Arrow -to turn left or move left
if (keyEvent.isShiftDown())
trans_rot.set(new Vector3f(-step, 0.0f, 0.0f));
else
trans_rot.rotY(angle);
break;
case KeyEvent.VK_RIGHT: // Right Arrow - to turn right or move right
if (keyEvent.isShiftDown())
trans_rot.set(new Vector3f(step, 0.0f, 0.0f));
else
trans_rot.rotY(-angle);
break;
case KeyEvent.VK_PAGE_DOWN: // Page Down - to move down
trans_rot.set(new Vector3f(0.0f, -step, 0.0f));
break;
case KeyEvent.VK_PAGE_UP: // Page Up - to move up
trans_rot.set(new Vector3f(0.0f, step, 0.0f));
break;
default:
trans_rot.set(new Vector3f(0.0f, 0.0f, 0.0f));
}
myKeyNavTransf3D.mul(trans_rot);
// Return the final transformation myKeyNavTransf3D to target
target_trGr.setTransform(myKeyNavTransf3D);
}
// Set wakeup criteria for next time.
wakeupOn(wakeUp);
}
}
/**
* This class creates the Earth by using the Sphere class and a given texture
* (Earth.jpg).
*/
class Earth {
public Sphere earth;
private String renderingType;
private float scale_XYZ;
private Color3f diffAmb, reflDiff, reflSpec, emittedLight;
private float c; // shininess;
private Appearance appearance;
private Material material;
private ColoringAttributes coloringAttributes;
private PolygonAttributes polygonAttributes;
private NewTextureLoader newTextureLoader;
private Texture texture;
private TextureAttributes textAttr;
/**
* Constructor that allows to specify the desired rendering's mode and the
* desired scale factor.
*
* @param java.lang.String
* nom - the desired type of earth's rendering,
* @param type
* float s_XYZ - the scale factor to adjust the earth's radius
*/
public Earth(String name, float s_XYZ) {
renderingType = name;
scale_XYZ = s_XYZ;
}
/**
* This methode serves to construct the earth.
*
* @return com.sun.j3d.utils.geometry.Sphere earth - the constructed earth
*/
public Sphere myEarth() {
// Optical properties of the earth.
// Ambient-diffuse-reflection coefficient
diffAmb = new Color3f(1.0f, 1.0f, 1.0f);
// Diffuse-reflection coefficient
reflDiff = new Color3f(1.0f, 1.0f, 1.0f);
// Specular-reflection coefficient (reflectance function)
reflSpec = new Color3f(0.0f, 0.0f, 0.1f);
// c = shininess: cos^c in the specular reflection
c = 1;
// Emitted light
emittedLight = new Color3f(0.0f, 0.0f, 0.0f);
appearance = new Appearance();
// Create the material and set up the optical properties.
material = new Material(diffAmb, emittedLight, reflDiff, reflSpec, c);
appearance.setMaterial(material);
// Set up the polygon's rendering-mode (with the polygonAttributes) and
// the shading-mode (with the coloringAttributes).
polygonAttributes = new PolygonAttributes();
coloringAttributes = new ColoringAttributes();
// Points
if (renderingType.compareTo("points") == 0) {
polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_POINT);
}
/* Lines*/
else if (renderingType.compareTo("lines") == 0) {
polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_LINE);
}
/* Polygons */
else if (renderingType.compareTo("polygons") == 0) {
/* is the default value*/
polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL);
coloringAttributes.setShadeModel(ColoringAttributes.SHADE_FLAT);
}
/* Gouraud */
else if (renderingType.compareTo("gouraud") == 0) {
polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL); /* is the default value*/
coloringAttributes.setShadeModel(ColoringAttributes.SHADE_GOURAUD); /* is the default value*/
}
else if (renderingType.compareTo("texture") == 0) {
polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL); /* is the default value*/
coloringAttributes.setShadeModel(ColoringAttributes.SHADE_GOURAUD); /* is the default value*/
/* Loading of the texture*/
newTextureLoader = new NewTextureLoader("Images/Earth.jpg");
newTextureLoader.setImageObserver(newTextureLoader
.getImageObserver());
texture = newTextureLoader.getTexture();
appearance.setTexture(texture);
/* Application mode of the texture */
textAttr = new TextureAttributes();
textAttr.setTextureMode(TextureAttributes.REPLACE); /* there still are:
BLEND, COMBINE,
DECAL, and MODULATE*/
appearance.setTextureAttributes(textAttr);
}
appearance.setPolygonAttributes(polygonAttributes);
appearance.setColoringAttributes(coloringAttributes);
/* Construction of the earth with all its features.*/
earth = new Sphere(scale_XYZ, Sphere.GENERATE_NORMALS
| Sphere.GENERATE_TEXTURE_COORDS, 10, appearance);
return earth;
}
}
/**
* This class creates a tetrahedron with a given texture (Claude.jpg).
*/
class Tetrahedron extends Shape3D {
private float scale_XYZ;
private Point3f vertices[];
private int lengthVertices = 4, lengthTetraFaceIndices = 12; // 4 faces x 3
// vertices
private int tetraFaceIndices[], textCoordIndices[];
private GeometryInfo tetra_GeometryInfo;
private NormalGenerator normalGenerator;
private Stripifier stripifier;
private GeometryArray tetra_GeometryArray;
private TexCoord2f textCoord2f[]; // for triangles
private boolean crAngle;
private Appearance appearance;
private Color3f diffAmb, reflDiff, reflSpec, emittedLight;
private Material material;
private TransparencyAttributes trAttr;
private NewTextureLoader newTextureLoader;
private Texture texture;
private TextureAttributes textAttr;
/**
* Constructor that allows to specify the desired scale factor.
*
* @param type
* float s_XYZ - the scale factor to adjust the edges's length of
* the tetrahedron
*/
public Tetrahedron(float s_XYZ) {
scale_XYZ = s_XYZ;
}
/**
* Construction of the desired tetrahedron.
*
* @return javax.media.j3d.Shape3D myTetrahedron - the constructed
* tetrahedron
*/
public Shape3D myTetrahedron() {
////////////////////// Geometric part ///////////////////////////
// The 4 vertices p0, p1, p2 and p3 of the tetrahedron.
vertices = new Point3f[lengthVertices]; // 4
vertices[0] = new Point3f(0.0f, 0.0f, 0.0f);
vertices[1] = new Point3f(1.0f, 0.0f, 0.0f);
vertices[2] = new Point3f(0.0f, 1.0f, 0.0f);
vertices[3] = new Point3f(0.0f, 0.0f, 1.0f);
// Scaling of vertices
for (int i = 0; i < lengthVertices; i++)
// lengthVertices = 4
vertices[i].scale(scale_XYZ);
// Set the face's indices for the tetrahedron (referenced to the array
// of vertices
// by setCoordinates(vertices) and
// setCoordinateIndices(tetraFaceIndices)).
tetraFaceIndices = new int[lengthTetraFaceIndices]; // 12
// From the camera in the view coordinate system
// bottom
tetraFaceIndices[0] = 0;
tetraFaceIndices[1] = 1;
tetraFaceIndices[2] = 3;
// back-left face
tetraFaceIndices[3] = 0;
tetraFaceIndices[4] = 3;
tetraFaceIndices[5] = 2;
// back face
tetraFaceIndices[6] = 0;
tetraFaceIndices[7] = 2;
tetraFaceIndices[8] = 1;
// front face
tetraFaceIndices[9] = 1;
tetraFaceIndices[10] = 2;
tetraFaceIndices[11] = 3;
// Create the GeometryInfo instance and set the vertices
tetra_GeometryInfo = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);
tetra_GeometryInfo.setCoordinates(vertices);
tetra_GeometryInfo.setCoordinateIndices(tetraFaceIndices);
// triangulator = new Triangulator(); // only for polygons:
// POLYGON_ARRAY
// triangulator.triangulate(tetra_GeometryInfo); // and with: int
// stripCounts[]
// gi.setStripCounts(...)
// int contourCounts[]
// Set the parameters (1 texture with dimension 2) for the texture's
// coordinates
tetra_GeometryInfo.setTextureCoordinateParams(1, 2);
// case #1: each face of the tetrahedron has the same texture portion.
// The coordinates of the 3 points in the 2D texture space.
textCoord2f = new TexCoord2f[3];
textCoord2f[0] = new TexCoord2f(0.0f, 0.2f);
textCoord2f[1] = new TexCoord2f(0.5f, 1.0f);
textCoord2f[2] = new TexCoord2f(1.0f, 0.5f);
// Set the texture coordinate's indices (referenced to the array of 2D
// points
// in the texture space by setTextureCoordinates(0, textCoord2f) and
// setTextureCoordinateIndices(0, textCoordIndices)).
textCoordIndices = new int[lengthTetraFaceIndices]; // 12
// From the camera in the view coordinate system (inverse of
// tetraFaceIndices !!!)
// front face
textCoordIndices[0] = 0;
textCoordIndices[1] = 1;
textCoordIndices[2] = 2;
// back face
textCoordIndices[3] = 0;
textCoordIndices[4] = 1;
textCoordIndices[5] = 2;
// back-left face
textCoordIndices[6] = 2;
textCoordIndices[7] = 0;
textCoordIndices[8] = 1;
// bottom
textCoordIndices[9] = 0;
textCoordIndices[10] = 1;
textCoordIndices[11] = 2;
/*
* // case #2: each face of the tetrahedron has a different part of the
* texture.
* // The coordinates of the 4 points in the 2D texture space.
* textCoord2f = new TexCoord2f[4]; textCoord2f[0] = new
* TexCoord2f(0.0f, 0.5f); textCoord2f[1] = new TexCoord2f(1.0f, 0.5f);
* textCoord2f[2] = new TexCoord2f(0.6f, 0.7f); textCoord2f[3] = new
* TexCoord2f(0.6f, 0.3f);
*
* // Set the texture coordinate's indices (referenced to the array of
* 2D points // in the texture space by setTextureCoordinates(0,
* textCoord2f) and // setTextureCoordinateIndices(0,
* textCoordIndices)). textCoordIndices = new
* int[lengthTetraFaceIndices]; // 12
* // From the camera in the view coordinate system (inverse of
* tetraFaceIndices !!!) // front face textCoordIndices[0] = 3;
* textCoordIndices[1] = 2; textCoordIndices[2] = 0; // back face
* textCoordIndices[3] = 1; textCoordIndices[4] = 2; textCoordIndices[5] =
* 3; // back-left face textCoordIndices[6] = 1; textCoordIndices[7] =
* 0; textCoordIndices[8] = 2; // bottom textCoordIndices[9] = 1;
* textCoordIndices[10]= 3; textCoordIndices[11]= 0;
*/
// just one set
tetra_GeometryInfo.setTextureCoordinates(0, textCoord2f);
// just one set
tetra_GeometryInfo.setTextureCoordinateIndices(0, textCoordIndices);
normalGenerator = new NormalGenerator();
normalGenerator.generateNormals(tetra_GeometryInfo);
if (crAngle)
normalGenerator.setCreaseAngle(0.0f); // with 0 radian ===> creased
stripifier = new Stripifier();
stripifier.stripify(tetra_GeometryInfo);
tetra_GeometryArray = tetra_GeometryInfo.getGeometryArray();
// The geonometry is passed to the instance this of the tetrahedron.
this.setGeometry(tetra_GeometryArray);
////////////////////// Appearance part ///////////////////////////
appearance = new Appearance();
// Optical properties of the tetrahedron.
// Ambient-diffuse-reflection coefficient
diffAmb = new Color3f(1.0f, 0.5f, 1.0f);
// Diffuse-reflection coefficient
reflDiff = new Color3f(1.0f, 0.5f, 1.0f);
// Specular-reflection coefficient (reflectance function)
reflSpec = new Color3f(1.0f, 0.5f, 1.0f);
// c = shininess: cos^c in the specular reflection
float c = 15;
// Emitted light
emittedLight = new Color3f(0.0f, 0.0f, 0.0f);
material = new Material(diffAmb, emittedLight, reflDiff, reflSpec, c);
appearance.setMaterial(material);
// This instance acts only on the tetrahedron and not on its texture.
trAttr = new TransparencyAttributes(TransparencyAttributes.NICEST, 0.0f);
// 0.0 = fully opaque
// 1.0 = fully transparent
appearance.setTransparencyAttributes(trAttr);
// Loading the texture
newTextureLoader = new NewTextureLoader("Images/Claude.jpg");
newTextureLoader.setImageObserver(newTextureLoader.getImageObserver());
texture = newTextureLoader.getTexture();
appearance.setTexture(texture);
// Application mode of the texture
textAttr = new TextureAttributes();
textAttr.setTextureMode(TextureAttributes.MODULATE); // there still are:
// BLEND, COMBINE,
// DECAL, and REPLACE
appearance.setTextureAttributes(textAttr);
// The appearance is passed to the instance this of the tetrahedron.
this.setAppearance(appearance);
return this;
}
}
/**
* This class creates a right-handed 3D coordinate system.
*/
class CoordSyst extends Shape3D {
private float rX, gX, bX, rY, gY, bY, rZ, gZ, bZ, scale_XYZ;
private LineArray axes;
private float scaledExtremites[];
/**
* Constructor that allows to specify the desired initial colors and the
* length of the axes.
*
* @param type
* float rougeX, vertX, bleuX, rougeY, vertY, bleuY, rougeZ,
* vertZ, bleuZ - the colors of the axes
* @param type
* float s_XYZ - the scale factor to adjust the axes's length
*/
public CoordSyst(float rougeX, float vertX, float bleuX, float rougeY,
float vertY, float bleuY, float rougeZ, float vertZ, float bleuZ,
float s_XYZ) {
rX = rougeX;
rY = rougeY;
rZ = rougeZ;
gX = vertX;
gY = vertY;
gZ = vertZ;
bX = bleuX;
bY = bleuY;
bZ = bleuZ;
scale_XYZ = s_XYZ;
// Colors of the three axes.
float color[] = { rX, gX, bX, rX, gX, bX, // the x axis
rY, gY, bY, rY, gY, bY, // the y axis
rZ, gZ, bZ, rZ, gZ, bZ }; // the z axis
// Construction of the axes (LineArray).
axes = new LineArray(6, LineArray.COORDINATES | LineArray.COLOR_3);
// Scalling of the vertices of the 3 axes using scale_XYZ.
scaledExtremites = new float[extremites.length];
for (int i = 0; i < extremites.length; i++)
scaledExtremites[i] = extremites[i] * scale_XYZ;
axes.setCoordinates(0, scaledExtremites);
axes.setColors(0, color);
this.setGeometry(axes);
}
// Definition of the geometry of the three axes.
private static final float extremites[] = {
// x-axis
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
// y-axis
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
// z-axis
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
}
|