/**
|
* Make a donation http://sourceforge.net/donate/index.php?group_id=98797
|
* Microcrowd.com
|
*
|
* This library is free software; you can redistribute it and/or
|
* modify it under the terms of the GNU Lesser General Public
|
* License as published by the Free Software Foundation; either
|
* version 2.1 of the License, or (at your option) any later version.
|
*
|
* This library 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
|
* Lesser General Public License for more details.
|
*
|
* You should have received a copy of the GNU Lesser General Public
|
* License along with this library; if not, write to the Free Software
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
*
|
* Contact Josh DeFord jdeford@microcrowd.com
|
*/
|
|
package com.microcrowd.loader.java3d.max3ds;
|
|
import java.applet.Applet;
|
import java.awt.BorderLayout;
|
import java.awt.GraphicsDevice;
|
import java.awt.GraphicsEnvironment;
|
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionListener;
|
import java.io.File;
|
import java.io.IOException;
|
import java.net.MalformedURLException;
|
import java.net.URL;
|
import javax.media.j3d.Behavior;
|
import javax.media.j3d.BoundingSphere;
|
import javax.media.j3d.BranchGroup;
|
import javax.media.j3d.Canvas3D;
|
import javax.media.j3d.GraphicsConfigTemplate3D;
|
import javax.media.j3d.Interpolator;
|
import javax.media.j3d.Locale;
|
import javax.media.j3d.PhysicalBody;
|
import javax.media.j3d.PhysicalEnvironment;
|
import javax.media.j3d.RotPosPathInterpolator;
|
import javax.media.j3d.Transform3D;
|
import javax.media.j3d.TransformGroup;
|
import javax.media.j3d.TransformInterpolator;
|
import javax.media.j3d.View;
|
import javax.media.j3d.ViewPlatform;
|
import javax.media.j3d.VirtualUniverse;
|
import javax.swing.JFileChooser;
|
import javax.swing.JMenu;
|
import javax.swing.JMenuBar;
|
import javax.swing.JMenuItem;
|
import javax.swing.filechooser.FileFilter;
|
import javax.vecmath.Point3d;
|
import javax.vecmath.Point3f;
|
import javax.vecmath.Quat4f;
|
import com.sun.j3d.loaders.Scene;
|
import com.sun.j3d.utils.applet.MainFrame;
|
import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior;
|
|
|
/**
|
* Provides an example of loader usage with key navigation.
|
* If loaded as an applet expects a 'url' parameter tag which
|
* must be specified as a fully qualified url. If there isn't a
|
* url tag it looks for an applet parameter called filename.
|
* If this is run from the command line it will try to load
|
* the file passed in at the prompt, unless a command line argument
|
* 'url' is the first argument. Then it will load the url represented
|
* as the second command argument.
|
*/
|
public class Main extends Applet
|
{
|
private BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0),3000.0);
|
private Canvas3D canvas;
|
private String modelLocation;
|
private static final String DEFAULT_MODEL = "bounce.3DS";
|
private BranchGroup universeBranch;
|
|
/**
|
* If loaded from the command line a modelFile must be provided.
|
* args are <filename> or url <url>
|
*/
|
public static void main(String args[])
|
{
|
Main self = new Main();
|
if(args.length > 0)
|
self.modelLocation = args[0];
|
|
MainFrame mainFrame = new MainFrame(self, 750, 550);
|
}
|
|
/**
|
* Initializes applet. If this is loaded from a command
|
* line the model is loaded from the parameters provided.
|
* If it is loaded from an applet the parameter tag 'model'
|
* is checked for a path to a model.
|
*/
|
public void init()
|
{
|
try
|
{
|
URL location = null;
|
if(modelLocation == null)
|
{
|
location = findAFile(DEFAULT_MODEL);
|
}
|
else
|
{
|
location = findAFile(modelLocation);
|
}
|
|
if(location == null)
|
throw new IllegalArgumentException("No model was found when attempting to retrieve " +
|
(modelLocation == null ? DEFAULT_MODEL : modelLocation));
|
|
GraphicsConfigTemplate3D config = new GraphicsConfigTemplate3D();
|
config.setSceneAntialiasing(GraphicsConfigTemplate3D.PREFERRED);
|
GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
|
canvas = new Canvas3D(gd[0].getBestConfiguration(config));
|
|
setLayout(new BorderLayout());
|
add("Center", canvas);
|
|
JMenuBar menuBar = new JMenuBar();
|
JMenu fileMenu = new JMenu("File");
|
JMenuItem menuItem = new JMenuItem("Open");
|
add(menuBar, "North");
|
menuBar.add(fileMenu);
|
fileMenu.add(menuItem);
|
menuItem.addActionListener(new BrowseListener());
|
|
View view = new View();
|
|
Scene scene = getScene(location);
|
universeBranch = createUniverse(view, scene);
|
view.addCanvas3D(canvas);
|
|
addSceneToBranch(universeBranch, scene);
|
}
|
catch(Exception e){
|
e.printStackTrace();
|
usage(e.getMessage());
|
}
|
}
|
|
/**
|
* Adds the scene to the branch and turns on the scene's
|
* behaviors.
|
*/
|
private void addSceneToBranch(BranchGroup branch, Scene scene)
|
{
|
turnOnBehaviors(scene.getBehaviorNodes());
|
BranchGroup modelGroup = scene.getSceneGroup();
|
modelGroup.compile();
|
branch.addChild(modelGroup);
|
}
|
|
/**
|
* This is called during initialization of the applet,
|
*/
|
public void Main()
|
{
|
}
|
|
/**
|
* load the scene.
|
*/
|
public Scene getScene(URL location)
|
{
|
Scene scene = null;
|
|
try
|
{
|
return new Loader3DS().load(location);
|
}
|
catch(IOException e){
|
e.printStackTrace();
|
usage(e.getMessage());
|
}
|
return null;
|
}
|
|
|
/**
|
* Turns on all the behaviors provided.
|
* @param bahaviors the behaviors to enable.
|
*/
|
public void turnOnBehaviors(Behavior[] behaviors)
|
{
|
if(behaviors == null)
|
return;
|
for(int i=0; i < behaviors.length; i++)
|
{
|
|
behaviors[i].setEnable(true);
|
if(behaviors[i] instanceof Interpolator)
|
{
|
((Interpolator)behaviors[i]).setSchedulingBounds(new BoundingSphere(new Point3d(), 3000));
|
}
|
if(behaviors[i] instanceof TransformInterpolator)
|
{
|
((TransformInterpolator)behaviors[i]).getTarget().setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
|
}
|
}
|
}
|
|
/**
|
* Adds an interpolator that will be added to
|
* the view transform so that it may be used to
|
* switched cameras later.
|
* @param target the target that the interpolator will operate on
|
*/
|
private void addCameraInterpolator(TransformGroup target)
|
{
|
Interpolator cameraInterpolator = new RotPosPathInterpolator(
|
null, target, new Transform3D(), new float[]{0,1},
|
new Quat4f[]{new Quat4f(), new Quat4f()}, new Point3f[]{new Point3f(), new Point3f()});
|
cameraInterpolator.setSchedulingBounds(bounds);
|
target.addChild(cameraInterpolator);
|
}
|
/**
|
* Constructs a scene graph.
|
* <ol>
|
* <li>Creates a branch group
|
* <li>Adds the parent transform group to it.
|
* </ol>
|
*/
|
public BranchGroup createSceneGraph() {
|
BranchGroup root = new BranchGroup();
|
TransformGroup parentGroup = new TransformGroup();
|
|
parentGroup.setCapability(TransformGroup.ENABLE_PICK_REPORTING);
|
parentGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
|
parentGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
|
parentGroup.setCapability(TransformGroup.ALLOW_CHILDREN_READ);
|
parentGroup.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
|
parentGroup.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
|
|
root.addChild(parentGroup);
|
|
return root;
|
}
|
|
/**
|
* Creates a universe with a locale turns the scene graph.
|
* Builds a scene branch group and adds it to the locale.
|
* Builds a view platform that uses the provided view and adds
|
* that to the locale.
|
* @param view the view to use in the view platform
|
* @param scene the scene to grab a camera from as a default view
|
*
|
* @return the root group of the scene branch of the universe. This
|
* is what other groups for display are added to.
|
*/
|
public BranchGroup createUniverse(View view, Scene scene)
|
{
|
VirtualUniverse universe = new VirtualUniverse();
|
Locale locale = new Locale(universe);
|
BranchGroup sceneBranch = createSceneGraph();
|
BranchGroup viewBranchGroup = new BranchGroup();
|
sceneBranch.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
|
viewBranchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
|
ViewPlatform platform = new ViewPlatform();
|
|
TransformGroup viewTransformGroup = new TransformGroup();
|
viewTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
|
viewTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
|
viewTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
|
|
TransformGroup[] viewGroups = scene.getViewGroups();
|
Transform3D viewTransform = new Transform3D();
|
if(viewGroups != null && viewGroups.length > 0)
|
{
|
viewGroups[0].getTransform(viewTransform);
|
}
|
|
addViewKeyBehavior(viewTransformGroup);
|
viewTransformGroup.setTransform(viewTransform);
|
|
addCameraInterpolator(viewTransformGroup);
|
viewTransformGroup.addChild(platform);
|
viewBranchGroup.addChild(viewTransformGroup);
|
|
platform.setViewAttachPolicy(View.RELATIVE_TO_FIELD_OF_VIEW);
|
platform.setActivationRadius(100);
|
|
configureView(platform, view);
|
sceneBranch.setCapability(BranchGroup.ALLOW_DETACH);
|
|
viewBranchGroup.compile();
|
sceneBranch.compile();
|
locale.addBranchGraph(viewBranchGroup);
|
locale.addBranchGraph(sceneBranch);
|
return sceneBranch;
|
}
|
|
/**
|
* Adds a behavior to the view that listens to the canvas.
|
* This allows 1st person navigation.
|
*/
|
public void addViewKeyBehavior(TransformGroup viewTransformGroup)
|
{
|
KeyNavigatorBehavior keyBehavior = new KeyNavigatorBehavior(canvas, viewTransformGroup);
|
keyBehavior.setSchedulingBounds(bounds);
|
//keyBehavior.setMovementRate(100.0f);
|
viewTransformGroup.addChild(keyBehavior);
|
}
|
|
/**
|
* Creates a physical environment and physical body and
|
* adds it them the view which is configured to use
|
* a regular screen display for configuration. The view is
|
* attached to the platform.
|
* @param platform the platform which will have the view attached to it.
|
* @param view the view to which the body and environment will be added.
|
* canvas 3d added to it.
|
*/
|
protected void configureView(ViewPlatform platform, View view)
|
{
|
PhysicalBody body = new PhysicalBody();
|
PhysicalEnvironment environment = new PhysicalEnvironment();
|
|
view.setPhysicalEnvironment(environment);
|
view.setPhysicalBody(body);
|
view.attachViewPlatform(platform);
|
view.setBackClipDistance(1000.0);
|
view.setFrontClipDistance(1.0);
|
|
|
}
|
|
public static void usage()
|
{
|
usage("");
|
}
|
|
public static void usage(String message)
|
{
|
System.out.println(message);
|
System.out.println("This is a sample program for the java3ds loader");
|
System.out.println("usage java -jar Loader3DS <model> where model is the 3ds file");
|
System.out.println("Textures for the file should be in the same directory as the model");
|
System.out.println("If this is being run as an applet a parameter named model (a relative url) may be provided");
|
System.exit(1);
|
}
|
|
/**
|
* Looks for a file to load. If one
|
* cannot be found looks for and loads
|
* the default one.
|
* @param name, or path of the file to find
|
* looks for the following:
|
* <ol>
|
* <li>a file with the path of fileName
|
* <li>a resource in the classpath with fileName
|
* <li>a resource in the classpath corresponding to
|
* the default file.
|
* <li>a url specified in the applet parameter "model"
|
* </ol>
|
*
|
**/
|
private URL findAFile(String fileName)
|
{
|
URL location = null;
|
if(fileName != null)
|
{
|
try
|
{
|
File file = new File(fileName);
|
if (file.exists())
|
{
|
return file.toURL();
|
}
|
}
|
catch(IOException e)
|
{
|
e.printStackTrace();
|
usage(e.getMessage());
|
}
|
}
|
|
if(fileName != null)
|
{
|
location = Main.class.getClassLoader().getResource(fileName);
|
}
|
if(location != null)
|
{
|
return location;
|
}
|
|
String relativeURL = getParameter("model");
|
if(relativeURL != null)
|
{
|
try
|
{
|
URL codeBase = getCodeBase();
|
return new URL(codeBase.toString() + relativeURL);
|
}
|
catch(MalformedURLException e){
|
e.printStackTrace();
|
usage(e.getMessage());
|
}
|
}
|
|
|
return location;
|
}
|
|
private class BrowseListener implements ActionListener
|
{
|
public void actionPerformed(ActionEvent event)
|
{
|
File file = null;
|
try {
|
JFileChooser chooser = new JFileChooser();
|
Filter3DS filter = new Filter3DS();
|
chooser.setFileFilter(filter);
|
chooser.showDialog(Main.this, "wee");
|
file = chooser.getSelectedFile();
|
if(file == null)
|
return;
|
Scene scene = getScene(file.toURL());
|
addSceneToBranch(universeBranch, scene);
|
}
|
catch(Exception e){
|
e.printStackTrace();
|
System.out.println("file not loadable " + file);
|
}
|
}
|
}
|
|
private class Filter3DS extends FileFilter
|
{
|
public String getDescription()
|
{
|
return "3DS Files";
|
}
|
public boolean accept(File file)
|
{
|
if (file.isDirectory())
|
return true;
|
String fileName = file.getName();
|
if(fileName.length() < 4)
|
return false;
|
|
String extension = fileName.substring(fileName.length() - 3, fileName.length());
|
if(extension.equalsIgnoreCase("3ds"))
|
return true;
|
return false;
|
}
|
}
|
}
|