* The example creates a very simple navigation environment where each Viewer of * the environment can navigate using the keyboard and see the other viewer. */ public class PlatformTest extends Applet implements ActionListener { // size of each Canvas3D static final int m_kWidth = 256; static final int m_kHeight = 256; // table used to map the name of a Viewer to its KeyNavigatorBehavior Hashtable m_KeyHashtable = null; BoundingSphere m_Bounds = null; public PlatformTest() { m_KeyHashtable = new Hashtable(); m_Bounds = new BoundingSphere(new Point3d(0, 0, 0), 100); // get the graphics configuration for the graphics device GraphicsConfiguration config = SimpleUniverse .getPreferredConfiguration(); // create the first canvas, this is the top-down view Canvas3D c = new Canvas3D(config); c.setSize(m_kWidth, m_kHeight); add(c); // create the second canvas, this is used for "Jim's" Viewer Canvas3D c2 = new Canvas3D(config); c2.setSize(m_kWidth, m_kHeight); add(c2); // create the third canvas, this is used for "Dan's" Viewer Canvas3D c3 = new Canvas3D(config); c3.setSize(m_kWidth, m_kHeight); add(c3); // Create the simple environment BranchGroup scene = createSceneGraph(); // create the first Viewer, this is a static top-down view // create a ViewingPlatform with 2 TransformGroups above the // ViewPlatform ViewingPlatform vp = new ViewingPlatform(2); // create the Viewer and attach to the first canvas Viewer viewer = new Viewer(c); // rotate and position the first Viewer above the environment Transform3D t3d = new Transform3D(); t3d.rotX(Math.PI / 2.0); t3d.setTranslation(new Vector3d(0, 0, -40)); t3d.invert(); MultiTransformGroup mtg = vp.getMultiTransformGroup(); mtg.getTransformGroup(0).setTransform(t3d); // create a SimpleUniverse from the ViewingPlatform and Viewer SimpleUniverse u = new SimpleUniverse(vp, viewer); // add the geometry to the scenegraph u.addBranchGraph(scene); // add two more Viewers to the scenegraph u.getLocale().addBranchGraph( createViewer(c2, "Jim", new Color3f(0.1f, 1.0f, 1.0f), -5, 8)); u.getLocale().addBranchGraph( createViewer(c3, "Dan", new Color3f(1.0f, 0.1f, 0.1f), 2, -8)); } ViewingPlatform createViewer(Canvas3D c, String szName, Color3f objColor, double x, double z) { // create a Viewer and attach to its canvas // a Canvas3D can only be attached to a single Viewer Viewer viewer2 = new Viewer(c); // create a ViewingPlatform with 1 TransformGroups above the // ViewPlatform ViewingPlatform vp2 = new ViewingPlatform(1); // create and assign the PlatformGeometry to the Viewer vp2.setPlatformGeometry(createPlatformGeometry(szName)); // create and assign the ViewerAvatar to the Viewer viewer2.setAvatar(createViewerAvatar(szName, objColor)); // set the initial position for the Viewer Transform3D t3d = new Transform3D(); t3d.setTranslation(new Vector3d(x, 0, z)); vp2.getViewPlatformTransform().setTransform(t3d); // set capabilities on the TransformGroup so that the // KeyNavigatorBehavior // can modify the Viewer's position vp2.getViewPlatformTransform().setCapability( TransformGroup.ALLOW_TRANSFORM_WRITE); vp2.getViewPlatformTransform().setCapability( TransformGroup.ALLOW_TRANSFORM_READ); // attach a navigation behavior to the position of the viewer KeyNavigatorBehavior key = new KeyNavigatorBehavior(vp2 .getViewPlatformTransform()); key.setSchedulingBounds(m_Bounds); key.setEnable(false); // add the KeyNavigatorBehavior to the ViewingPlatform vp2.addChild(key); // set the ViewingPlatform for the Viewer viewer2.setViewingPlatform(vp2); // associate the name of the Viewer with its KeyNavigatorBehavior m_KeyHashtable.put(szName, key); // create a button to switch the Viewer ON. Button button = new Button(szName); button.addActionListener(this); add(button); return vp2; } // create a tiled environment from -12 to +12. The environment // is created from a QuadArray. The environment is surrounded by a ColorCube // "wall" that is 2 units high (from Z = -1 to Z = 1). public BranchGroup createSceneGraph() { final int LAND_WIDTH = 12; final float LAND_HEIGHT = -1.0f; final int LAND_LENGTH = 12; final int nTileSize = 2; // calculate how many vertices we need to store all the "tiles" // that compose the QuadArray. final int nNumTiles = ((LAND_LENGTH / nTileSize) * 2) * ((LAND_WIDTH / nTileSize) * 2); final int nVertexCount = 4 * nNumTiles; Point3f[] coordArray = new Point3f[nVertexCount]; Point2f[] texCoordArray = new Point2f[nVertexCount]; // create an Appearance and load a texture Appearance app = new Appearance(); Texture tex = new TextureLoader("land.jpg", this).getTexture(); app.setTexture(tex); // create the parent BranchGroup BranchGroup bg = new BranchGroup(); int nItem = 0; // loop over all the tiles in the environment for (int x = -LAND_WIDTH; x <= LAND_WIDTH; x += nTileSize) { for (int z = -LAND_LENGTH; z <= LAND_LENGTH; z += nTileSize) { // if we are on the border of the environment create a // TransformGroup to position a ColorCube to create a "wall" if (x == -LAND_WIDTH || x == LAND_WIDTH || z == -LAND_LENGTH || z == LAND_LENGTH) { TransformGroup tg = new TransformGroup(); Transform3D t3d = new Transform3D(); t3d.setTranslation(new Vector3d(x, 0, z)); tg.setTransform(t3d); tg.addChild(new ColorCube(nTileSize / 2)); bg.addChild(tg); } // if we are not on the last row or column create a "tile" // and add to the QuadArray. Use CCW winding and assign texture // coordinates. if (z < LAND_LENGTH && x < LAND_WIDTH) { coordArray[nItem] = new Point3f(x, LAND_HEIGHT, z); texCoordArray[nItem++] = new Point2f(0, 0); coordArray[nItem] = new Point3f(x, LAND_HEIGHT, z + nTileSize); texCoordArray[nItem++] = new Point2f(1, 0); coordArray[nItem] = new Point3f(x + nTileSize, LAND_HEIGHT, z + nTileSize); texCoordArray[nItem++] = new Point2f(1, 1); coordArray[nItem] = new Point3f(x + nTileSize, LAND_HEIGHT, z); texCoordArray[nItem++] = new Point2f(0, 1); } } } // create a GeometryInfo and generate Normal vectors // for the QuadArray that was populated. GeometryInfo gi = new GeometryInfo(GeometryInfo.QUAD_ARRAY); gi.setCoordinates(coordArray); gi.setTextureCoordinates(texCoordArray); NormalGenerator normalGenerator = new NormalGenerator(); normalGenerator.generateNormals(gi); // wrap the GeometryArray in a Shape3D Shape3D shape = new Shape3D(gi.getGeometryArray(), app); // add the Shape3D to the parent BranchGroup bg.addChild(shape); // create some lights for the scene Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f); Vector3f lDir1 = new Vector3f(-1.0f, -1.0f, -1.0f); Color3f alColor = new Color3f(0.2f, 0.2f, 0.2f); AmbientLight aLgt = new AmbientLight(alColor); aLgt.setInfluencingBounds(m_Bounds); DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1); lgt1.setInfluencingBounds(m_Bounds); // add the lights to the parent BranchGroup bg.addChild(aLgt); bg.addChild(lgt1); // create a light gray background Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f)); back.setApplicationBounds(m_Bounds); bg.addChild(back); // compile the whole scene //bg.compile(); return bg; } // creates and positions a simple Cone to represent the Viewer. // The Cone is aligned and scaled such that it is similar to a // 3D "turtle".... Aaah good old Logo. ViewerAvatar createViewerAvatar(String szText, Color3f objColor) { ViewerAvatar viewerAvatar = new ViewerAvatar(); // rotate the Cone so that it is lying down and // points sharp-end towards the Viewer's field of view. TransformGroup tg = new TransformGroup(); Transform3D t3d = new Transform3D(); t3d.setEuler(new Vector3d(Math.PI / 2.0, Math.PI, 0)); tg.setTransform(t3d); // create appearance and material for the Cone Appearance app = new Appearance(); Color3f black = new Color3f(0.4f, 0.2f, 0.1f); app.setMaterial(new Material(objColor, black, objColor, black, 90.0f)); // create the Primitive and add to the parent BranchGroup tg.addChild(new Cone(1, 3, Primitive.GENERATE_NORMALS, app)); viewerAvatar.addChild(tg); return viewerAvatar; } // create a simple Raster text label used to help // identify the viewer. PlatformGeometry createPlatformGeometry(String szText) { PlatformGeometry pg = new PlatformGeometry(); pg.addChild(createLabel(szText, 0f, 2f, 0f)); return pg; } // creates a simple Raster text label (similar to Text2D) private Shape3D createLabel(String szText, float x, float y, float z) { BufferedImage bufferedImage = new BufferedImage(25, 14, BufferedImage.TYPE_INT_RGB); Graphics g = bufferedImage.getGraphics(); g.setColor(Color.white); g.drawString(szText, 2, 12); ImageComponent2D imageComponent2D = new ImageComponent2D( ImageComponent2D.FORMAT_RGB, bufferedImage); // create the Raster for the image javax.media.j3d.Raster renderRaster = new javax.media.j3d.Raster( new Point3f(x, y, z), javax.media.j3d.Raster.RASTER_COLOR, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), imageComponent2D, null); return new Shape3D(renderRaster); } // Enables the KeyNavigatorBehavior associated with the // AWT button that was pressed for the Viewer. Disables all other // KeyNavigatorBehaviors for non-active Viewers. public void actionPerformed(ActionEvent event) { KeyNavigatorBehavior key = (KeyNavigatorBehavior) m_KeyHashtable .get(event.getActionCommand()); Object[] keysArray = m_KeyHashtable.values().toArray(); for (int n = 0; n < keysArray.length; n++) { KeyNavigatorBehavior keyAtIndex = (KeyNavigatorBehavior) keysArray[n]; keyAtIndex.setEnable(keyAtIndex == key); if (keyAtIndex == key) System.out.println("Enabled: " + event.getActionCommand()); } } public static void main(String[] args) { new MainFrame(new PlatformTest(), (int) (m_kWidth * 3.5), (int) (m_kHeight * 1.1)); } } /******************************************************************************* * Copyright (C) 2001 Daniel Selman * * First distributed with the book "Java 3D Programming" by Daniel Selman and * published by Manning Publications. http://manning.com/selman * * 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, version 2. * * 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. * * The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html * * Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite * 330, Boston, MA 02111-1307, USA. * * Authors can be contacted at: Daniel Selman: daniel@selman.org * * If you make changes you think others would like, please contact one of the * authors or someone at the www.j3d.org web site. ******************************************************************************/ //***************************************************************************** /** * Java3dApplet * * Base class for defining a Java 3D applet. Contains some useful methods for * defining views and scenegraphs etc. * * @author Daniel Selman * @version 1.0 */ //***************************************************************************** abstract class Java3dApplet extends Applet { public static int m_kWidth = 300; public static int m_kHeight = 300; protected String[] m_szCommandLineArray = null; protected VirtualUniverse m_Universe = null; protected BranchGroup m_SceneBranchGroup = null; protected Bounds m_ApplicationBounds = null; // protected com.tornadolabs.j3dtree.Java3dTree m_Java3dTree = null; public Java3dApplet() { } public boolean isApplet() { try { System.getProperty("user.dir"); System.out.println("Running as Application."); return false; } catch (Exception e) { } System.out.println("Running as Applet."); return true; } public URL getWorkingDirectory() throws java.net.MalformedURLException { URL url = null; try { File file = new File(System.getProperty("user.dir")); System.out.println("Running as Application:"); System.out.println(" " + file.toURL()); return file.toURL(); } catch (Exception e) { } System.out.println("Running as Applet:"); System.out.println(" " + getCodeBase()); return getCodeBase(); } public VirtualUniverse getVirtualUniverse() { return m_Universe; } //public com.tornadolabs.j3dtree.Java3dTree getJ3dTree() { //return m_Java3dTree; // } public Locale getFirstLocale() { java.util.Enumeration e = m_Universe.getAllLocales(); if (e.hasMoreElements() != false) return (Locale) e.nextElement(); return null; } protected Bounds getApplicationBounds() { if (m_ApplicationBounds == null) m_ApplicationBounds = createApplicationBounds(); return m_ApplicationBounds; } protected Bounds createApplicationBounds() { m_ApplicationBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0); return m_ApplicationBounds; } protected Background createBackground() { Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f)); back.setApplicationBounds(createApplicationBounds()); return back; } public void initJava3d() { // m_Java3dTree = new com.tornadolabs.j3dtree.Java3dTree(); m_Universe = createVirtualUniverse(); Locale locale = createLocale(m_Universe); BranchGroup sceneBranchGroup = createSceneBranchGroup(); ViewPlatform vp = createViewPlatform(); BranchGroup viewBranchGroup = createViewBranchGroup( getViewTransformGroupArray(), vp); createView(vp); Background background = createBackground(); if (background != null) sceneBranchGroup.addChild(background); // m_Java3dTree.recursiveApplyCapability(sceneBranchGroup); // m_Java3dTree.recursiveApplyCapability(viewBranchGroup); locale.addBranchGraph(sceneBranchGroup); addViewBranchGroup(locale, viewBranchGroup); onDoneInit(); } protected void onDoneInit() { // m_Java3dTree.updateNodes(m_Universe); } protected double getScale() { return 1.0; } public TransformGroup[] getViewTransformGroupArray() { TransformGroup[] tgArray = new TransformGroup[1]; tgArray[0] = new TransformGroup(); // move the camera BACK a little... // note that we have to invert the matrix as // we are moving the viewer Transform3D t3d = new Transform3D(); t3d.setScale(getScale()); t3d.setTranslation(new Vector3d(0.0, 0.0, -20.0)); t3d.invert(); tgArray[0].setTransform(t3d); return tgArray; } protected void addViewBranchGroup(Locale locale, BranchGroup bg) { locale.addBranchGraph(bg); } protected Locale createLocale(VirtualUniverse u) { return new Locale(u); } protected BranchGroup createSceneBranchGroup() { m_SceneBranchGroup = new BranchGroup(); return m_SceneBranchGroup; } protected View createView(ViewPlatform vp) { View view = new View(); PhysicalBody pb = createPhysicalBody(); PhysicalEnvironment pe = createPhysicalEnvironment(); AudioDevice audioDevice = createAudioDevice(pe); if (audioDevice != null) { pe.setAudioDevice(audioDevice); audioDevice.initialize(); } view.setPhysicalEnvironment(pe); view.setPhysicalBody(pb); if (vp != null) view.attachViewPlatform(vp); view.setBackClipDistance(getBackClipDistance()); view.setFrontClipDistance(getFrontClipDistance()); Canvas3D c3d = createCanvas3D(); view.addCanvas3D(c3d); addCanvas3D(c3d); return view; } protected PhysicalBody createPhysicalBody() { return new PhysicalBody(); } protected AudioDevice createAudioDevice(PhysicalEnvironment pe) { JavaSoundMixer javaSoundMixer = new JavaSoundMixer(pe); if (javaSoundMixer == null) System.out.println("create of audiodevice failed"); return javaSoundMixer; } protected PhysicalEnvironment createPhysicalEnvironment() { return new PhysicalEnvironment(); } protected float getViewPlatformActivationRadius() { return 100; } protected ViewPlatform createViewPlatform() { ViewPlatform vp = new ViewPlatform(); vp.setViewAttachPolicy(View.RELATIVE_TO_FIELD_OF_VIEW); vp.setActivationRadius(getViewPlatformActivationRadius()); return vp; } protected Canvas3D createCanvas3D() { GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D(); gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED); GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment() .getScreenDevices(); Canvas3D c3d = new Canvas3D(gd[0].getBestConfiguration(gc3D)); c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d)); return c3d; } protected int getCanvas3dWidth(Canvas3D c3d) { return m_kWidth; } protected int getCanvas3dHeight(Canvas3D c3d) { return m_kHeight; } protected double getBackClipDistance() { return 100.0; } protected double getFrontClipDistance() { return 1.0; } protected BranchGroup createViewBranchGroup(TransformGroup[] tgArray, ViewPlatform vp) { BranchGroup vpBranchGroup = new BranchGroup(); if (tgArray != null && tgArray.length > 0) { Group parentGroup = vpBranchGroup; TransformGroup curTg = null; for (int n = 0; n < tgArray.length; n++) { curTg = tgArray[n]; parentGroup.addChild(curTg); parentGroup = curTg; } tgArray[tgArray.length - 1].addChild(vp); } else vpBranchGroup.addChild(vp); return vpBranchGroup; } protected void addCanvas3D(Canvas3D c3d) { setLayout(new BorderLayout()); add(c3d, BorderLayout.CENTER); doLayout(); } protected VirtualUniverse createVirtualUniverse() { return new VirtualUniverse(); } protected void saveCommandLineArguments(String[] szArgs) { m_szCommandLineArray = szArgs; } protected String[] getCommandLineArguments() { return m_szCommandLineArray; } }