/**
|
* 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.awt.Image;
|
import java.io.File;
|
import java.io.FileInputStream;
|
import java.io.FileNotFoundException;
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.Reader;
|
import java.net.MalformedURLException;
|
import java.net.URL;
|
import java.net.URLConnection;
|
import javax.media.j3d.BoundingSphere;
|
import javax.media.j3d.Group;
|
import javax.media.j3d.PointLight;
|
import javax.media.j3d.Transform3D;
|
import javax.media.j3d.TransformGroup;
|
import javax.vecmath.Point3d;
|
import com.sun.j3d.loaders.LoaderBase;
|
import com.sun.j3d.loaders.Scene;
|
import com.sun.j3d.loaders.SceneBase;
|
|
/**
|
* Used to load a 3ds studio max file. This will sequentially read a 3ds file,
|
* load or skip chunks and subchunks and initialize the data for the chunks.
|
* A {@link ChunkChopper} is a singleton flyweight factory responsible for
|
* chopping the data up and sending it to the corresponding chunks(which are
|
* flyweights ala the flyweight pattern) for processing.
|
*
|
* <p>
|
* Features not supported; unknown chunks are skipped.
|
* </p>
|
*/
|
public class Loader3DS extends LoaderBase
|
{
|
private boolean dataMapInitialized;
|
|
private TextureImageLoader textureImageLoader;
|
private boolean fromUrl;
|
|
public Loader3DS()
|
{
|
//turnOnDebug();
|
}
|
|
/**
|
* Setting this will initialize a lot of debugging code that has lots of
|
* overhead.
|
*/
|
private boolean debugMode;
|
|
/**
|
* This is not supported
|
*
|
* @param reader loads a model from a reader
|
*
|
* @return nothing, this isn't implemented.
|
*
|
* @throws FileNotFoundException
|
* @throws UnsupportedOperationException
|
*/
|
public Scene load(Reader reader) throws FileNotFoundException
|
{
|
throw new UnsupportedOperationException("Not supported for 3DS");
|
}
|
|
/**
|
* Loads the model by parsing the file, modelPath and creating a 3D Scene.
|
*
|
* @param modelPath the path of the 3ds file.
|
*
|
* @return a loaded scene
|
*
|
* @throws FileNotFoundException if the file can't be located.
|
*/
|
public Scene load(String modelPath) throws FileNotFoundException
|
{
|
InputStream fileIn = null;
|
setBasePathFromFilename(modelPath);
|
|
try {
|
File modelFile = getFile(modelPath);
|
fileIn = new FileInputStream(modelFile);
|
return parseChunks(fileIn, (int)modelFile.length());
|
} finally {
|
try {
|
fileIn.close();
|
} catch (Exception e) {
|
e.printStackTrace();
|
//Don't care about exceptions at this point.
|
}
|
}
|
}
|
|
private void setBaseUrlFromUrl(URL url) throws FileNotFoundException
|
{
|
String u = url.toString();
|
String s;
|
if (u.lastIndexOf('/') == -1) {
|
s = url.getProtocol() + ":";
|
} else {
|
s = u.substring(0, u.lastIndexOf('/') + 1);
|
}
|
try {
|
setBaseUrl(new URL(s));
|
}
|
catch (MalformedURLException e) {
|
throw new FileNotFoundException(e.getMessage());
|
}
|
}
|
|
/*
|
* Takes a file name and sets the base path to the directory
|
* containing that file.
|
*/
|
private void setBasePathFromFilename(String fileName)
|
{
|
if (fileName.lastIndexOf(java.io.File.separator) == -1) {
|
// No path given - current directory
|
setBasePath("." + java.io.File.separator);
|
} else {
|
setBasePath(fileName.substring(0, fileName.lastIndexOf(java.io.File.separator)));
|
}
|
}
|
|
/**
|
* Set the path where files associated with this .obj file are
|
* located.
|
* Only needs to be called to set it to a different directory
|
* from that containing the .obj file.
|
*/
|
public void setBasePath(String pathName)
|
{
|
String basePath = pathName;
|
if (basePath == null || basePath == "")
|
basePath = "." + java.io.File.separator;
|
basePath = basePath.replace('/', java.io.File.separatorChar);
|
basePath = basePath.replace('\\', java.io.File.separatorChar);
|
if (!basePath.endsWith(java.io.File.separator))
|
basePath = basePath + java.io.File.separator;
|
super.setBasePath(basePath);
|
}
|
|
/**
|
* Returns true if this loader is loading files
|
* from a url.
|
*/
|
public boolean fromUrl()
|
{
|
return fromUrl;
|
}
|
|
/**
|
* gets an image with the specified name.
|
* This uses a DefaultTextureImageLoader
|
* to load the image if one hasn't been set for
|
* this loader.
|
* @param imageName name of image to load.
|
* @return image corresponding to imageName
|
*/
|
public Image getTextureImage(String imageName)
|
{
|
try {
|
if(textureImageLoader == null)
|
{
|
textureImageLoader = new DefaultTextureImageLoader(this);
|
}
|
return textureImageLoader.getTextureImage(imageName);
|
}
|
catch (IllegalArgumentException e)
|
{
|
System.out.println(e.getMessage());
|
}
|
catch (Exception e)
|
{
|
e.printStackTrace();
|
}
|
return null;
|
}
|
|
/**
|
* Sets the TextureImageLoader to be used
|
* when texture images are needed.
|
* @param loader the TextureImageLoader that will be used to load images.
|
*/
|
public void setTextureImageLoader(TextureImageLoader loader)
|
{
|
textureImageLoader = loader;
|
}
|
|
/**
|
* Gets a chunk chopper to do all the dirty work.
|
*
|
* @param inputStream the stream containing the model.
|
* @param modelSize size of the model file.
|
*
|
* @return a java3d scene built from input.
|
*/
|
protected Scene parseChunks(InputStream inputStream, int modelSize)
|
{
|
ChunkChopper chopper = new ChunkChopper();
|
SceneBase base = chopper.loadSceneBase(inputStream, this, modelSize);
|
if(!chopper.hasLights())
|
{
|
addDefaultLights(base.getSceneGroup());
|
addDefaultLights(chopper.getGroup());
|
}
|
return base;
|
}
|
|
/**
|
* Adds defaultlights to the group provided
|
* similar to the ones 3ds max adds when there are none in the scene.
|
* @param group to add the lighting to.
|
*/
|
public static void addDefaultLights(Group group)
|
{
|
PointLight light1 = new PointLight();
|
PointLight light2 = new PointLight();
|
light1.setInfluencingBounds(new BoundingSphere(new Point3d(0,0,0), 3000));
|
light2.setInfluencingBounds(new BoundingSphere(new Point3d(0,0,0), 3000));
|
|
Transform3D t1 = new Transform3D(new float[]{1.0f, 0.0f, 0.0f, -900f,
|
0.0f, 1.0f, 0.0f, 1500f,
|
0.0f, 0.0f, 1.0f, 1000f,
|
0.0f, 0.0f, 0.0f, 1.0f});
|
Transform3D t2 = new Transform3D(new float[]{1.0f, 0.0f, 0.0f, 900f,
|
0.0f, 1.0f, 0.0f, -1500f,
|
0.0f, 0.0f, 1.0f, -1000f,
|
0.0f, 0.0f, 0.0f, 1.0f});
|
TransformGroup group1 = new TransformGroup(t1);
|
TransformGroup group2 = new TransformGroup(t2);
|
group1.addChild(light1);
|
group2.addChild(light2);
|
group.addChild(group1);
|
group.addChild(group2);
|
}
|
|
/**
|
* Retrieves a file with a given name.
|
*
|
* @param fileName name of file to retrieve.
|
*
|
* @return retrieved file.
|
*/
|
private File getFile(String fileName)
|
{
|
File file = null;
|
try {
|
file = new File(fileName);
|
if (!file.exists()) {
|
throw new IOException(fileName + " doesn't exist");
|
}
|
} catch (IOException ioe) {
|
ioe.printStackTrace();
|
}
|
|
return file;
|
}
|
|
/**
|
* throws UnsupportedOperationException
|
*
|
* @param url url of model to be loaded.
|
*
|
* @return a java3d scene represented in url
|
*
|
* @throws FileNotFoundException if file couldn't be found.
|
*/
|
public Scene load(URL url) throws FileNotFoundException
|
{
|
fromUrl = true;
|
try {
|
URLConnection connection = url.openConnection();
|
if (baseUrl == null)
|
setBaseUrlFromUrl(url);
|
|
return parseChunks(connection.getInputStream(), connection.getContentLength());
|
} catch (Exception e) {
|
e.printStackTrace();
|
throw new IllegalArgumentException("Url " + url + " cannot be loaded");
|
|
}
|
}
|
|
/**
|
* Turn on debug mode for all 3ds xml.
|
*/
|
public void turnOnDebug()
|
{
|
if (!debugMode) {
|
ChunkChopper.debug = true;
|
debugMode = true;
|
}
|
}
|
}
|