From 77633b188d01228383ced79c26b41ebb2989624c Mon Sep 17 00:00:00 2001
From: Normand Briere <nbriere@noware.ca>
Date: Sun, 07 Jul 2019 10:19:34 -0400
Subject: [PATCH] New 3ds loader.
---
ObjEditor.java | 77
com/microcrowd/loader/java3d/max3ds/Main.java | 454 +++++
com/microcrowd/loader/java3d/max3ds/chunks/FacesMaterialChunk.java | 59
com/microcrowd/loader/java3d/max3ds/chunks/BooleanChunk.java | 46
ObjectFile.java | 12
com/microcrowd/loader/java3d/max3ds/Loader3DS.java | 317 +++
com/microcrowd/loader/java3d/max3ds/chunks/FloatChunk.java | 47
com/microcrowd/loader/java3d/max3ds/chunks/FramesChunk.java | 45
com/microcrowd/loader/java3d/max3ds/TextureImageLoader.java | 42
com/microcrowd/loader/java3d/max3ds/chunks/AxisChunk.java | 83 +
com/microcrowd/loader/java3d/max3ds/chunks/Vertex2ListChunk.java | 55
com/microcrowd/loader/java3d/max3ds/chunks/CameraChunk.java | 65
com/microcrowd/loader/java3d/max3ds/chunks/Vertex3ListChunk.java | 54
com/microcrowd/loader/java3d/max3ds/chunks/ScaleChunk.java | 67
com/microcrowd/loader/java3d/max3ds/CannotChopException.java | 40
CameraPane.java | 50
cRadio.java | 4
GroupEditor.java | 22
com/microcrowd/loader/java3d/max3ds/ChunkChopper.java | 635 +++++++
com/microcrowd/loader/java3d/max3ds/DefaultTextureImageLoader.java | 103 +
com/microcrowd/loader/java3d/max3ds/ChunkMap.java | 444 +++++
com/microcrowd/loader/java3d/max3ds/chunks/FacesDescriptionChunk.java | 322 +++
com/microcrowd/loader/java3d/max3ds/chunks/LightChunk.java | 80
com/microcrowd/loader/java3d/max3ds/chunks/PositionChunk.java | 63
com/microcrowd/loader/java3d/max3ds/chunks/SmoothingChunk.java | 65
com/microcrowd/loader/java3d/max3ds/chunks/BoundingBoxChunk.java | 55
com/microcrowd/loader/java3d/max3ds/chunks/ColorChunk.java | 82
com/microcrowd/loader/java3d/max3ds/chunks/PercentageChunk.java | 59
com/microcrowd/loader/java3d/max3ds/package.html | 3
com/microcrowd/loader/java3d/max3ds/chunks/FramesDescriptionChunk.java | 59
com/microcrowd/loader/java3d/max3ds/chunks/HierarchyInfoChunk.java | 46
com/microcrowd/loader/java3d/max3ds/chunks/RotationChunk.java | 129 +
ClickInfo.java | 2
com/microcrowd/loader/java3d/max3ds/chunks/KeyFramerInfoChunk.java | 68
com/microcrowd/loader/java3d/max3ds/chunks/SpotLightChunk.java | 73
com/microcrowd/loader/java3d/max3ds/chunks/Chunk.java | 139 +
com/microcrowd/loader/java3d/max3ds/chunks/MaterialChunk.java | 121 +
com/microcrowd/loader/java3d/max3ds/chunks/NamedObjectChunk.java | 50
com/microcrowd/loader/java3d/max3ds/ChunkTester.java | 31
com/microcrowd/loader/java3d/max3ds/data/KeyFramer.java | 526 ++++++
com/microcrowd/loader/java3d/max3ds/chunks/StringChunk.java | 52
com/microcrowd/loader/java3d/max3ds/chunks/PivotChunk.java | 45
com/realvue/sim/ui/loader/java3d/max3ds/Loader3DS.java | 34
cFileSystemPane.java | 31
com/microcrowd/loader/java3d/max3ds/chunks/TextureChunk.java | 47
com/microcrowd/loader/java3d/max3ds/chunks/GlobalColorChunk.java | 45
Object3D.java | 4
47 files changed, 4,897 insertions(+), 55 deletions(-)
diff --git a/CameraPane.java b/CameraPane.java
index d0c68fd..9699e8e 100644
--- a/CameraPane.java
+++ b/CameraPane.java
@@ -14604,7 +14604,8 @@
Globals.MOUSEDRAGGED = false;
movingcamera = false;
- X = Y = 0;
+ X = 0; // getBounds().width/2;
+ Y = 0; // getBounds().height/2;
//System.out.println("mouseReleased: " + e);
clickEnd(e.getX(), e.getY(), e.getModifiersEx());
}
@@ -15717,23 +15718,42 @@
*/
if (!isRenderer)
{
- object.drawEditHandles(info, 0);
-
- if (drag && (X != 0 || Y != 0) && object.selection.Size() > 0)
+ if (object.selection.Size() > 0)
{
- switch (object.selection.get(0).hitSomething)
+ int hitSomething = object.selection.get(0).hitSomething;
+
+ info.DX = 0;
+ info.DY = 0;
+ info.W = 1;
+ if (hitSomething == Object3D.hitCenter)
{
- case Object3D.hitCenter: gr.setColor(Color.pink);
- gr.drawLine(X, Y, info.bounds.width/2, info.bounds.height/2);
- break;
- case Object3D.hitRotate: gr.setColor(Color.yellow);
- gr.drawLine(X, Y, info.bounds.width/2, info.bounds.height/2);
- break;
- case Object3D.hitScale: gr.setColor(Color.cyan);
- gr.drawLine(X, Y, info.bounds.width/2, info.bounds.height/2);
- break;
+ info.DX = X;
+ if (X != 0)
+ info.DX -= info.bounds.width/2;
+
+ info.DY = Y;
+ if (Y != 0)
+ info.DY -= info.bounds.height/2;
}
-
+
+ object.drawEditHandles(info, 0);
+
+ if (drag && (X != 0 || Y != 0))
+ {
+ switch (hitSomething)
+ {
+ case Object3D.hitCenter: gr.setColor(Color.pink);
+ gr.drawLine(X, Y, info.bounds.width/2, info.bounds.height/2);
+ break;
+ case Object3D.hitRotate: gr.setColor(Color.yellow);
+ gr.drawLine(X, Y, info.bounds.width/2, info.bounds.height/2);
+ break;
+ case Object3D.hitScale: gr.setColor(Color.cyan);
+ gr.drawLine(X, Y, info.bounds.width/2, info.bounds.height/2);
+ break;
+ }
+
+ }
}
}
}
diff --git a/ClickInfo.java b/ClickInfo.java
index a73de9f..0377695 100644
--- a/ClickInfo.java
+++ b/ClickInfo.java
@@ -26,6 +26,8 @@
double toScreen[][];
iCameraPane pane;
Graphics g;
+ int DX, DY;
+ float W = 1;
static double matbuffer[][] = new double[4][4];
}
diff --git a/GroupEditor.java b/GroupEditor.java
index dab62a9..84ed69e 100644
--- a/GroupEditor.java
+++ b/GroupEditor.java
@@ -380,6 +380,7 @@
shadowYItem.addActionListener(this);
shadowZItem = menu.add(new MenuItem("Shadow Blue"));
shadowZItem.addActionListener(this);
+
if (Globals.ADVANCED)
{
menu.add("-");
@@ -601,6 +602,10 @@
fullButton.setToolTipText("Full-screen window");
fullButton.addActionListener(this);
+ oe.toolbarPanel.add(screenfitButton = GetButton("icons/fit.png", !Grafreed.NIMBUSLAF)); //, oe.aConstraints);
+ screenfitButton.setToolTipText("Screen fit");
+ screenfitButton.addActionListener(this);
+
oe.toolbarPanel.add(restoreCameraButton = GetButton("icons/eye.png", !Grafreed.NIMBUSLAF)); //, oe.aConstraints);
restoreCameraButton.setToolTipText("Restore viewpoint");
restoreCameraButton.addActionListener(this);
@@ -633,10 +638,6 @@
//oe.toolboxPanel.Return();
- copyOptionsPanel.add(screenfitButton = GetButton("icons/fit.png", !Grafreed.NIMBUSLAF)); //, oe.aConstraints);
- screenfitButton.setToolTipText("Screen fit");
- screenfitButton.addActionListener(this);
-
// copyOptionsPanel.add(trackCB = GetToggleButton("icons/track.png", CameraPane.TRACK)); //, oe.aConstraints);
// trackCB.setToolTipText("Enable tracking");
// trackCB.addItemListener(this);
@@ -1214,8 +1215,6 @@
}
}
- String string = (String) object;
-
System.out.println("Transfer = " + object + "; drop : " + target);
// if( object instanceof java.io.File[])
// {
@@ -1223,6 +1222,8 @@
// objEditor.DropFile((java.io.File[]) object, true);
// return;
// }
+
+ String string = (String) object;
// File path for Mac and Windows
if (string.charAt(0) == '/' || string.charAt(1) == ':')
@@ -2219,7 +2220,8 @@
} else
if (source == undoButton)
{
- Undo();
+ if (!Undo())
+ java.awt.Toolkit.getDefaultToolkit().beep();
} else
if (source == redoButton)
{
@@ -2227,7 +2229,8 @@
} else
if (source == saveButton)
{
- Save();
+ if (!Save(true))
+ java.awt.Toolkit.getDefaultToolkit().beep();
} else
if (source == oneStepButton)
{
@@ -2236,17 +2239,14 @@
} else
if (source == screenfitButton)
{
- //Reload(lastConverter, lastFilename, true);
ScreenFit();
} else
if (source == screenfitpointButton)
{
- //Reload(lastConverter, lastFilename, true);
ScreenFitPoint();
} else
if (source == snapobjectButton)
{
- //Reload(lastConverter, lastFilename, true);
SnapObject();
} else
// if (event.getSource() == recompileButton)
diff --git a/ObjEditor.java b/ObjEditor.java
index 93548e1..5d7d1bb 100644
--- a/ObjEditor.java
+++ b/ObjEditor.java
@@ -1979,8 +1979,9 @@
// 3D models
if (filename.endsWith(".3ds") || filename.endsWith(".3DS"))
{
- lastConverter = new com.jmex.model.converters.MaxToJme();
- LoadFile(filename, lastConverter);
+ //lastConverter = new com.jmex.model.converters.MaxToJme();
+ //LoadFile(filename, lastConverter);
+ LoadObjFile(filename); // New 3ds loader
continue;
}
if (filename.endsWith(".dae") || filename.endsWith(".DAE"))
@@ -2706,6 +2707,7 @@
LA.matXRotate(((Object3D) group.get(group.size() - 1)).toParent, -Math.PI / 2);
LA.matXRotate(((Object3D) group.get(group.size() - 1)).fromParent, Math.PI / 2);
}
+
//cJME.count++;
//cJME.count %= 12;
if (gc)
@@ -2889,6 +2891,7 @@
}
}
}
+
cFileSystemPane FSPane;
void SetMaterial(cMaterial mat, Object3D.cVector2[] others)
@@ -2942,6 +2945,7 @@
}
}
}
+
freezematerial = false;
}
@@ -3566,6 +3570,28 @@
public void Save()
{
+ // Default reduces the probability of heuristics errors.
+ Save(true);
+ }
+
+ private boolean Equal(byte[] compress, byte[] name)
+ {
+ if (compress.length != name.length)
+ {
+ return false;
+ }
+
+ for (int i=compress.length; --i>=0;)
+ {
+ if (compress[i] != name[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean Save(boolean user)
+ {
System.err.println("Save");
cRadio tab = GetCurrentTab();
@@ -3576,18 +3602,31 @@
copy.ExtractBigData(hashtable);
byte[] compress = Compress(copy);
-
- //EditorFrame.m_MainFrame.requestFocusInWindow();
- tab.graphs[tab.undoindex++] = compress;
-
- copy.RestoreBigData(hashtable);
CameraPane.SWITCH = temp;
+ boolean thesame = false;
+
+ // Quick heuristic using length. Works only when stream is compressed.
+ if (tab.undoindex > 0 && tab.graphs[tab.undoindex-1] != null && Equal(compress, tab.graphs[tab.undoindex-1]))
+ {
+ thesame = true;
+ }
+
+ //EditorFrame.m_MainFrame.requestFocusInWindow();
+ if (!thesame)
+ {
+ tab.user[tab.undoindex] = user;
+ tab.graphs[tab.undoindex++] = compress;
+ }
+
+ copy.RestoreBigData(hashtable);
+
//assert(hashtable.isEmpty());
for (int i = tab.undoindex; i < tab.graphs.length; i++)
{
+ tab.user[i] = false;
tab.graphs[i] = null;
}
@@ -3611,6 +3650,8 @@
e.printStackTrace();
}
}
+
+ return !thesame;
}
void CopyChanged(Object3D obj)
@@ -3667,7 +3708,7 @@
redoButton.setEnabled(tab.graphs[tab.undoindex + 1] != null);
}
- public void Undo()
+ public boolean Undo()
{
System.err.println("Undo");
@@ -3676,18 +3717,27 @@
if (tab.undoindex == 0)
{
java.awt.Toolkit.getDefaultToolkit().beep();
- return;
+ return false;
}
- if (tab.graphs[tab.undoindex] == null)
+ if (tab.graphs[tab.undoindex] == null || !tab.user[tab.undoindex])
{
- Save();
- tab.undoindex -= 1;
+ if (Save(false))
+ tab.undoindex -= 1;
+ else
+ {
+ if (tab.undoindex <= 0)
+ return false;
+ else
+ tab.undoindex -= 1;
+ }
}
tab.undoindex -= 1;
CopyChanged((Object3D)Uncompress(tab.graphs[tab.undoindex]));
+
+ return true;
}
public void Redo()
@@ -3703,6 +3753,9 @@
tab.undoindex += 1;
CopyChanged((Object3D)Uncompress(tab.graphs[tab.undoindex]));
+
+ if (!tab.user[tab.undoindex])
+ tab.graphs[tab.undoindex] = null;
}
void ImportGFD()
diff --git a/Object3D.java b/Object3D.java
index 2a9ae20..442b170 100644
--- a/Object3D.java
+++ b/Object3D.java
@@ -7288,8 +7288,8 @@
// {
// CameraPane.Ymax = spoth;
// }
- info.g.drawArc(boundary.x, boundary.y,
- boundary.width, boundary.height, 0, 360);
+ info.g.drawArc(boundary.x + info.DX, boundary.y + info.DY,
+ (int)(boundary.width * info.W), (int)(boundary.height * info.W), 0, 360);
//info.g.drawArc(spot.x, spotw, spot.width/2, boundary.height/2, 0, 360);
// if (CameraPane.Xmin > boundary.x)
// {
diff --git a/ObjectFile.java b/ObjectFile.java
index 5dad1c3..ceaa352 100644
--- a/ObjectFile.java
+++ b/ObjectFile.java
@@ -730,11 +730,15 @@
public Scene load(String filename) throws FileNotFoundException,
IncorrectFormatException, ParsingErrorException
{
+ if (filename.toLowerCase().endsWith(".obj"))
+ {
+ setBasePathFromFilename(filename);
- setBasePathFromFilename(filename);
-
- Reader reader = new BufferedReader(new FileReader(filename));
- return load(reader);
+ Reader reader = new BufferedReader(new FileReader(filename));
+ return load(reader);
+ }
+ else // new 3ds loader
+ return new com.microcrowd.loader.java3d.max3ds.Loader3DS().load(filename);
} // End of load(String)
private void setBaseUrlFromUrl(URL url)
diff --git a/cFileSystemPane.java b/cFileSystemPane.java
index 98b5413..05e14ef 100644
--- a/cFileSystemPane.java
+++ b/cFileSystemPane.java
@@ -18,6 +18,7 @@
iCallBack owner;
JButton refreshButton;
+ JButton rootButton;
JButton loadButton;
JButton printButton;
JButton replaceButton;
@@ -39,7 +40,7 @@
//ToolTipManager.sharedInstance().registerComponent(jTree);
jTree.setCellRenderer(new cFileSystemModel.Renderer());
- ResetModel();
+ ResetModel(true);
JScrollPane tree = new JScrollPane(jTree);
//jTree.addTreeSelectionListener(this);
@@ -64,11 +65,13 @@
fileCommsnds.add(loadButton = new JButton("Load")); //, aConstraints);
loadButton.setToolTipText("Load selected file(s)");
- fileCommsnds.add(refreshButton = new JButton("Refresh")); //, aConstraints);
- refreshButton.setToolTipText("Refresh entire tree");
-
- refreshButton.addActionListener(this);
- loadButton.addActionListener(this);
+ loadButton.addActionListener(this);
+ fileCommsnds.add(refreshButton = new JButton("User")); //, aConstraints);
+ refreshButton.setToolTipText("Refresh user tree");
+ refreshButton.addActionListener(this);
+ fileCommsnds.add(rootButton = new JButton("Root")); //, aConstraints);
+ rootButton.setToolTipText("Refresh root tree");
+ rootButton.addActionListener(this);
if (Globals.ADVANCED)
{
@@ -114,7 +117,7 @@
// /*DropTarget dropTarget =*/ new DropTarget(oe.cameraView, this);
}
- void ResetModel()
+ void ResetModel(boolean user)
{
cFilter filter = new cFilter();
@@ -134,9 +137,11 @@
filter.add("tga");
filter.add("bmp"); // not supported
+ File root = java.io.File.listRoots()[0];
+ File defaultDirectory = javax.swing.filechooser.FileSystemView.getFileSystemView().getDefaultDirectory();
+
jTree.setModel(new cFileSystemModel(
- //java.io.File.listRoots()[1])
- javax.swing.filechooser.FileSystemView.getFileSystemView().getDefaultDirectory(),
+ user?defaultDirectory:root,
filter
));
}
@@ -167,7 +172,13 @@
{
if(event.getSource() == refreshButton)
{
- ResetModel();
+ ResetModel(true);
+ return;
+ }
+
+ if(event.getSource() == rootButton)
+ {
+ ResetModel(false);
return;
}
diff --git a/cRadio.java b/cRadio.java
index 1ab12b3..03fab54 100644
--- a/cRadio.java
+++ b/cRadio.java
@@ -35,7 +35,9 @@
camera = (Camera)Grafreed.clone(c);
}
- byte[] graphs[] = new byte[10000][];
+ byte[] graphs[] = new byte[100][];
+ boolean[] user = new boolean[100];
+
int undoindex = 0;
// Patch to avoid bug with transparency.
diff --git a/com/microcrowd/loader/java3d/max3ds/CannotChopException.java b/com/microcrowd/loader/java3d/max3ds/CannotChopException.java
new file mode 100644
index 0000000..4985364
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/CannotChopException.java
@@ -0,0 +1,40 @@
+/**
+ * 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;
+
+/**
+ * Exception thrown by chunks to indicate that the
+ * chopper cannot appropriately chop(parse) it.
+ * This Exception won't return null for getCause()
+ */
+public class CannotChopException extends Exception
+{
+ public CannotChopException(Throwable cause)
+ {
+ this("", cause);
+ }
+
+ public CannotChopException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/ChunkChopper.java b/com/microcrowd/loader/java3d/max3ds/ChunkChopper.java
new file mode 100644
index 0000000..83b91e1
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/ChunkChopper.java
@@ -0,0 +1,635 @@
+/**
+ * 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@realvue.com
+ */
+
+package com.microcrowd.loader.java3d.max3ds;
+
+import java.awt.Image;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.util.HashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.media.j3d.Behavior;
+import javax.media.j3d.BranchGroup;
+import javax.media.j3d.Light;
+import javax.media.j3d.Texture;
+import javax.media.j3d.TransformGroup;
+import javax.vecmath.Point3f;
+import javax.vecmath.Vector3f;
+import com.microcrowd.loader.java3d.max3ds.chunks.Chunk;
+import com.microcrowd.loader.java3d.max3ds.data.KeyFramer;
+import com.sun.j3d.loaders.SceneBase;
+import com.sun.j3d.utils.image.TextureLoader;
+
+/**
+ * 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.
+ * This will sequentially read a 3ds file, load or
+ * skip chunks and subchunks and initialize the data
+ * for the chunks.
+ * <p>
+ * Retrieved data may be stored as state in the ChunkChopper
+ * via {@link #pushData} for use by other chunks.
+ * <p>
+ * Features not supported; unknown chunks are skipped.
+ */
+public class ChunkChopper
+{
+ private Logger logger = Logger.getLogger(ChunkChopper.class.getName());
+
+ private Loader3DS loader;
+ private BranchGroup sceneGroup;
+ private SceneBase base;
+ private HashMap dataMap;
+ private ByteBuffer chunkBuffer;
+ private Integer chunkID;
+
+ private TransformGroup currentGroup;
+ private String currentObjectName;
+ private ChunkTester chunkTester = new ChunkTester();
+ private Chunk mainChunk = new Chunk("MainChunk");
+ private ChunkMap chunkMap = new ChunkMap(mainChunk);
+
+ private KeyFramer keyFramer = new KeyFramer();
+
+ /** This should be turned on by Loader3DS to view debugging information. */
+ public static boolean debug;
+
+ /** Current chunk for which debugging info is viewed if debug == true */
+ public static Chunk debugChunk;
+
+ /**
+ * private singleton constructor.
+ */
+ public ChunkChopper(){}
+
+ /**
+ * This sequentially parses the chunks out of the input stream and
+ * constructs the 3D entities represented within.
+ * A Chunk is a little endian data structure consists of a
+ * 6 byte header followed by subchunks and or data.
+ * The first short int(little endian) represent the id
+ * of the chunk. The next int represent the total
+ * length of the chunk(total of data, subchunks and chunk header).
+ * <p>
+ * The first chunk is the main chunk (id=4D4D) and its length
+ * is always the length of the file. It only contains sub chunks.
+ * Other chunks may contain data, subchunks or both. If the format
+ * of a chunk is unknown skipped.
+ * <p>
+ * Subclasses of chunk will all automagically load the subchunks.
+ * It is the programmers responsibility to ensure that the data
+ * preceeding the subchunks is loaded or skipped as
+ * required and that something useful is done with the data. If data from the
+ * subchunks is needed in order to initialize components then that code should be
+ * placed in {@link Chunk#initialize}. Otherwise the data may be dealt with in
+ * {@link Chunk#loadData}. Also, if a chunk has data preceeding its subchunks
+ * it communicates how many bytes long that data is by returning it from loadData.
+ * <p>
+ * This chopper reads a file in order from beginning to end
+ * @param inputStream the stream with the data to be parsed.
+ * @param loader the loader that will be configured from the data.
+ * @param modelName name of the model file for display purposes.
+ * @param modelSize size in bytes of the file to read.
+ */
+ public synchronized SceneBase loadSceneBase(InputStream inputStream, Loader3DS loader, int modelSize)
+ {
+ this.loader = loader;
+ this.sceneGroup = new BranchGroup();
+ this.base = new SceneBase();
+ this.dataMap = new HashMap();
+ base.setSceneGroup(sceneGroup);
+
+ //FileChannel channel = null;
+ ReadableByteChannel channel = null;
+ try {
+ channel = Channels.newChannel(inputStream);
+ chunkBuffer = getByteBuffer(channel, modelSize);
+ //chunkBuffer = getDirectByteBuffer(channel, modelSize);
+
+ int mainChunkID = chunkBuffer.getShort();
+ long mainChunkLength = chunkBuffer.getInt();
+
+ long begin = System.currentTimeMillis();
+ logger.finest("\n\n\n STARTING SUBCUNKS " + (mainChunkLength - 61));
+ try {
+ loadSubChunks(mainChunk, 0);
+ }
+ catch(CannotChopException e){
+
+ }
+ logger.finest("FINISHED WITH THE SUBCHUNKS");
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ finally
+ {
+ try {
+ if(channel != null) {
+ channel.close();
+ }
+ } catch (Exception e){
+ //Just closing file.. don't care.
+ }
+ }
+ return base;
+ }
+
+ /**
+ * Allocates and loads a byte buffer from the channel
+ * @param channel the file channel to load the data from
+ * @return a direct byte buffer containing all the data of the channel at position 0
+ */
+ public ByteBuffer getByteBuffer(ReadableByteChannel channel, int channelSize) throws IOException
+ {
+ ByteBuffer chunkBuffer = ByteBuffer.allocate(channelSize);
+ chunkBuffer.order(ByteOrder.LITTLE_ENDIAN);
+ channel.read(chunkBuffer);
+ chunkBuffer.position(0);
+ return chunkBuffer;
+ }
+
+
+ /**
+ * The base class Chunk takes care of loading subchunks for
+ * all chunks types. It occurs as follows:
+ * <ol>
+ * <li>The chunk id (short) is read
+ * <li>The chunk length(int) is read
+ * <li>A subchunk is looked up from the map of publish
+ * subchunk types of the current chunk.
+ * <li>If it isn't found during the lookup it is skipped.
+ * <li>Otherwise it is requested to {@link #pushData}
+ * <li>The return value, if there is one, is used to determine
+ * where its next subchunk is. A return value of 0 signifies
+ * that the next subchunk is nigh.
+ * <li>The chunk's subchunks are then loaded.
+ * <li>The chunks initialize method is called.
+ * </ol>
+ */
+ protected void loadSubChunks(Chunk parentChunk, int level) throws CannotChopException
+ {
+ level++;
+ while(chunkBuffer.hasRemaining())//hasRemaining() evaluates limit - position.
+ {
+ chunkID = new Integer(chunkBuffer.getShort());
+ Chunk chunk = parentChunk.getSubChunk(chunkID);
+
+ int currentChunkLength = chunkBuffer.getInt() - 6; //length includes this 6 byte header.
+ int finishedPosition = chunkBuffer.position() + currentChunkLength;
+ int previousLimit = chunkBuffer.limit();
+ chunkBuffer.limit(chunkBuffer.position() + currentChunkLength);
+
+ if(debug) {
+ debug(parentChunk, level, chunkID, currentChunkLength, chunkBuffer.position(), chunkBuffer.limit());
+ }
+ if(chunk != null && currentChunkLength != 0) {
+ try {
+ chunk.loadData(this);
+ }
+ catch(BufferUnderflowException e){
+ chunkBuffer.position(finishedPosition);
+ chunkBuffer.limit(previousLimit);
+ throw new CannotChopException(" tried to read too much data from the buffer. Trying to recover.", e);
+ }
+ try {
+ if(chunkBuffer.hasRemaining()) {
+ loadSubChunks(chunk, level);
+ }
+ chunk.initialize(this);
+ }
+ catch(CannotChopException e){
+ logger.log(Level.SEVERE, chunk.toString() + "Trying to continue");
+ }
+ }
+
+ chunkBuffer.position(finishedPosition);
+ chunkBuffer.limit(previousLimit);
+ }
+ }
+
+ /**
+ * Gets the key framer chunk
+ * These should be their own objects instead of chunks.
+ */
+ public KeyFramer getKeyFramer()
+ {
+ return keyFramer;
+ }
+
+ /**
+ * Adds a group to the choppers scene group
+ * and sets the current name and group.
+ * @param the name of the object to add which
+ * will also be the current name of the object
+ * the chopper is working with.
+ * @param group the current group that the chopper
+ * will be adding things too.
+ */
+ public void addObject(String name, TransformGroup group)
+ {
+ sceneGroup.addChild(group);
+ currentGroup = group;
+ currentObjectName = name;
+ base.addNamedObject(name, group);
+ }
+
+
+
+ /**
+ * Gets the name of the current object
+ * the chopper is working with. The value returned
+ * from this generally is either set by a NamedObjectChunk
+ * and is the name of the name of the last object added
+ * or is the name set by setObjectName.
+ * @return the name of the current object being
+ * constructed.
+ */
+ public String getObjectName()
+ {
+ return currentObjectName;
+ }
+
+
+ /**
+ * Sets the name of the current object.
+ * The name of the current object can also be set
+ * with {@link #addObject}
+ * @param name the name that the current object should be set to.
+ */
+ public void setObjectName(String name)
+ {
+ currentObjectName = name;
+ }
+
+ /**
+ * Gets the group for the current object
+ * the chopper is working with. The value returned
+ * from this generally gets set by a NamedObjectChunk
+ * and is the name of the last object added.
+ * @return the group for the current object being
+ * constructed.
+ */
+ public TransformGroup getGroup()
+ {
+ return currentGroup;
+ }
+
+ /**
+ * Used to store data that may later be used
+ * by another chunk.
+ * @param key the look up key.
+ * @param data the data to store.
+ */
+ public void pushData(Object key, Object data)
+ {
+ dataMap.put(key, data);
+ }
+
+ /**
+ * Gets a datum that had been retrieved and stored
+ * via {@link #pushData} earlier and removes it.
+ * @param key the key used to store the datum earlier.
+ */
+ public Object popData(Object key)
+ {
+ Object retVal = dataMap.remove(key);
+ return retVal;
+ }
+
+ /**
+ * Sets a named object in the loader.
+ * @param key the key name of the object
+ * @param value the named Object.
+ */
+ public void setNamedObject(String key, Object value)
+ {
+ base.addNamedObject(key, value);
+ }
+
+ /**
+ * Returns true if there have been lights loaded.
+ * @return true if there are lights.
+ */
+ public boolean hasLights()
+ {
+ return (base.getLightNodes() != null && base.getLightNodes().length > 0);
+ }
+
+ /**
+ * Adds a behavior to the scene base.
+ * @param behavior the behavior to add to the scene base.
+ */
+ public void addBehaviorNode(Behavior behavior)
+ {
+ base.addBehaviorNode(behavior);
+ }
+
+
+ /**
+ * Adds a light to the scene base.
+ * @param light the light to add to the scene base.
+ */
+ public void addLightNode(Light light)
+ {
+ base.addLightNode(light);
+ }
+
+
+ /**
+ * Adds a camera transform to the scene base.
+ * @param viewGroup the transform group to add as a view.
+ */
+ public void addViewGroup(TransformGroup viewGroup)
+ {
+ base.addViewGroup(viewGroup);
+ }
+
+ /**
+ * Sets a named Object in the loader.
+ * @param key the key used as the name for which the object will be returned
+ */
+ public Object getNamedObject(String key)
+ {
+ if(key == null)
+ return null;
+ return base.getNamedObjects().get(key);
+ }
+
+ /**
+ * Gets and cast the named object for the
+ * key provided. Its an error if its not
+ * a transform group.
+ */
+ public TransformGroup getNamedTransformGroup(String key)
+ {
+ Object object = getNamedObject(key);
+ if(object instanceof TransformGroup)
+ {
+ return (TransformGroup)object;
+ }
+ else if (object != null)
+ {
+ logger.log(Level.INFO, "Retrieving " + key + " which is a named object but not useable because "+
+ " its not a transform group. Its a " + object.getClass().getName());
+ }
+ return null;
+ }
+
+
+ /**
+ * Gets a long from the chunk Buffer
+ */
+ public long getLong()
+ {
+ return chunkBuffer.getLong();
+ }
+
+ /**
+ * Reads a short and returns it as a signed
+ * int.
+ */
+ public int getShort()
+ {
+ return chunkBuffer.getShort();
+ }
+
+ /**
+ * Reads a short and returns it as an unsigned
+ * int.
+ */
+ public int getUnsignedShort()
+ {
+ return chunkBuffer.getShort()&0xFFFF;
+ }
+
+ /**
+ * reads a float from the chunkBuffer.
+ */
+ public float getFloat()
+ {
+ return chunkBuffer.getFloat();
+ }
+
+ /**
+ * Reads 3 floats x,z,y from the chunkbuffer.
+ * Since 3ds has z as up and y as pointing in whereas
+ * java3d has z as pointing forward and y as pointing up;
+ * this returns new Vector3f(x,-z,y)
+ *
+ */
+ public Vector3f getVector()
+ {
+ return new Vector3f(getPoint());
+ }
+ /**
+ * Reads 3 floats x,z,y from the chunkbuffer.
+ * Since 3ds has z as up and y as pointing in whereas
+ * java3d has z as pointing forward and y as pointing up;
+ * this returns new Point3f(x,-z,y)
+ */
+ public Point3f getPoint()
+ {
+ float x = chunkBuffer.getFloat();
+ float z = -chunkBuffer.getFloat();
+ float y = chunkBuffer.getFloat();
+ return new Point3f(x,y,z);
+ }
+
+ /**
+ * Reads an int and returns it
+ * @return the int read
+ */
+ public int getInt()
+ {
+ return chunkBuffer.getInt();
+ }
+
+ /**
+ * Reads an int and returns it
+ * unsigned, any ints greater than MAX_INT
+ * will break.
+ */
+ public int getUnsignedInt()
+ {
+ return chunkBuffer.getInt()&0xFFFFFFFF;
+ }
+
+ /**
+ * Reads a byte, unsigns it, returns the corresponding int.
+ * @return the unsigned int corresponding to the read byte.
+ */
+ public int getUnsignedByte()
+ {
+ return chunkBuffer.get()&0xFF;
+ }
+
+ /**
+ * Reads a number of bytes corresponding to the
+ * number of bytes left in the current chunk and returns an array
+ * containing them.
+ * @return an array containing all the bytes for the current chunk.
+ */
+ public byte[] getChunkBytes()
+ {
+ byte[] retVal = new byte[chunkBuffer.limit() - chunkBuffer.position()];
+ get(retVal);
+ return retVal;
+ }
+
+ /**
+ * Fills bytes with data from the chunk buffer.
+ * @param bytes the array to fill with data.
+ */
+ public void get(byte[] bytes)
+ {
+ chunkBuffer.get(bytes);
+ }
+
+
+ /**
+ * Sets the data map used to store values
+ * that chunks may need to retrieve later.
+ * @param dataMap the hashmap that will be used to store
+ * and retrieve values for use by chunks.
+ */
+ public void setDataMap(HashMap dataMap)
+ {
+ this.dataMap = dataMap;
+ }
+
+
+ /**
+ * This reads bytes until it gets 0x00 and returns
+ * the corresponding string.
+ */
+ public String getString()
+ {
+ StringBuffer stringBuffer = new StringBuffer();
+ char charIn = (char)chunkBuffer.get();
+ while(charIn != 0x00)
+ {
+ stringBuffer.append(charIn);
+ charIn = (char)chunkBuffer.get();
+ }
+ return stringBuffer.toString();
+ }
+
+ /**
+ * Gets the id of the current chunk.
+ * @return id of the current chunk as read
+ * from the chunkBuffer. It will be a signed <code>short</code>.
+ */
+ public Integer getID()
+ {
+ return chunkID;
+ }
+
+ /**
+ * Loads the image to server as a texture.
+ * @param textureImageName name of the image that
+ * is going to be set to be the texture.
+ */
+ public Texture createTexture(String textureImageName)
+ {
+ Image image = loader.getTextureImage(textureImageName);
+ if(image == null)
+ {
+ System.err.println("Cannot load texture image " + textureImageName +
+ ". Make sure it is in the directory with the model file. " +
+ "If its a bmp make sure JAI is installed.");
+ return null;
+ }
+ try
+ {
+ TextureLoader textureLoader = new TextureLoader(image, null);
+ return textureLoader.getTexture();
+ }
+ catch(Exception e){
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * prints some handy information... the chunk hierarchy.
+ */
+ protected void debug(Chunk parentChunk, int level, Integer chunkID, long chunkLength, int position, long limit)
+ {
+ try {
+ for(int i=0; i<level; i++)
+ {
+ System.out.print(" ");
+ }
+ Object child = parentChunk.getSubChunk(chunkID);
+ int id = ((short)chunkID.intValue()) & 0xFFFF;
+ System.out.println(parentChunk + " is " +
+ (child==null?"skipping":"LOADING")+
+ ": [id=" + Integer.toHexString(id) +
+ ", object= <" + parentChunk.getSubChunk(chunkID) +
+ ">, chunkLength=" + chunkLength +
+ ", position=" + position +
+ " limit=" + limit + "]");
+ }
+ catch(Exception e){
+ //We're debugging.. its ok
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Prints an exception and exits.
+ */
+ private void exceptAndExit(Throwable exception)
+ {
+ logger.log(Level.SEVERE, "\nThe chunk for loadData method read too much or not enough data from the stream." +
+ " It needs be skipped or adjusted to read more or less data.");
+ exception.printStackTrace();
+ System.exit(3);
+ }
+
+ /**
+ * Convert the integer to an unsigned number.
+ * @param i the integer to convert.
+ */
+ private static String byteString(int i)
+ {
+ final char[] digits = {
+ '0' , '1' , '2' , '3' , '4' , '5' ,
+ '6' , '7' , '8' , '9' , 'a' , 'b' ,
+ 'c' , 'd' , 'e' , 'f' };
+
+ char[] buf = new char[2];
+ buf[1] = digits[i & 0xF];
+ i >>>= 4;
+ buf[0] = digits[i & 0xF];
+
+ return "0x" + new String(buf).toUpperCase();
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/ChunkMap.java b/com/microcrowd/loader/java3d/max3ds/ChunkMap.java
new file mode 100644
index 0000000..63a777d
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/ChunkMap.java
@@ -0,0 +1,444 @@
+/**
+ * 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.util.HashMap;
+import com.microcrowd.loader.java3d.max3ds.chunks.AxisChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.BooleanChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.BoundingBoxChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.CameraChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.Chunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.ColorChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.FacesDescriptionChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.FacesMaterialChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.FloatChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.FramesChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.FramesDescriptionChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.GlobalColorChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.HierarchyInfoChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.KeyFramerInfoChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.LightChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.MaterialChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.NamedObjectChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.PercentageChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.PivotChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.PositionChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.RotationChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.ScaleChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.SmoothingChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.SpotLightChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.StringChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.TextureChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.Vertex2ListChunk;
+import com.microcrowd.loader.java3d.max3ds.chunks.Vertex3ListChunk;
+
+
+/**
+ * A Hashmap with the chunk names as values with keys
+ * being the chunk id.
+ */
+public class ChunkMap extends HashMap
+{
+ private Chunk mainChunk;
+
+ /** Constant designating a chunk as a frames chunk*/
+ public static final Integer FRAMES_CHUNK = new Integer((short)0x0B008);
+ /** Constant designating a chunk as a mesh info chunk*/
+ //public static final Integer AMBIENT_LIGHT_INFO = new Integer((short)0x0B001);
+ public static final Integer MESH_INFO = new Integer((short)0x0B002);
+ //public static final Integer CAMERA_INFO = new Integer((short)0x0B003);
+ //public static final Integer CAMERA_TARGET_INFO = new Integer((short)0x0B004);
+ //public static final Integer OMNI_LIGHT_INFO = new Integer((short)0x0B005);
+ //public static final Integer SPOT_LIGHT_TARGET_INFO = new Integer((short)0x0B006);
+ public static final Integer SPOT_LIGHT_INFO = new Integer((short)0x0B007);
+ /** Key for the name and flags chunk */
+ public static final Integer NAME_AND_FLAGS = new Integer((short)0xB010);
+ /** Key for the pivot chunk */
+ public static final Integer PIVOT = new Integer((short)0xB013);
+ /** Indicates a position track chunk **/
+ public static final Integer POSITION = new Integer((short)0xB020);
+ /** Indicates a scale track chunk */
+ public static final Integer SCALE_TRACK= new Integer((short)0xB022);
+ /** Indicates a rotation track chunk */
+ public static final Integer ROTATION= new Integer((short)0xB021);
+ public static final Integer BOUNDING_BOX = new Integer((short)0x0B014);
+ /** Indicates a hierarchy info chunk **/
+ public static final Integer HIERARCHY_INFO= new Integer((short)0xB030);
+ /** Signifies that the light is off **/
+ //public static final Integer LIGHT_OFF = new Integer((short)0x4620);
+ /** Signifies that the light is attenuated **/
+ public static final Integer ATTENUATED = new Integer((short)0x4625);
+ public static final Integer RANGE_START = new Integer((short)0x4659);
+ public static final Integer RANGE_END = new Integer((short)0x465A);
+ public static final Integer MULTIPLIER = new Integer((short)0x465B);
+ public static final Integer SPOTLIGHT = new Integer((short)0x4610);
+ public static final Integer COLOR = new Integer((short)0x0010);
+ public static final Integer VERSION = new Integer((short)0x2);
+ public static final Integer EDITOR = new Integer((short)0x3D3D);
+ public static final Integer KEYFRAMER = new Integer((short)0xB000);
+ /** These are the chunk ids for colors */
+ public static final Integer MATERIAL_NAME = new Integer((short)0xA000);
+ /** ID of the chunk that will be used to represent the ambient color. **/
+ public static final Integer AMBIENT_COLOR = new Integer((short)0xA010);
+ /** ID of the chunk that will be used to represent the diffuse color. **/
+ public static final Integer DIFFUSE_COLOR = new Integer((short)0xA020);
+ /** ID of the chunk that will be used to represent the specular color. **/
+ public static final Integer SPECULAR_COLOR = new Integer((short)0xA030);
+ /** ID of the chunk that will be used to represent the shinines. **/
+ public static final Integer SHININESS = new Integer((short)0xA040);
+ //public static final Integer SHININESS = new Integer((short)0xA041);
+ /** ID of the chunk that will be used to represent the transparency. **/
+ public static final Integer TRANSPARENCY = new Integer((short)0xA050);
+ /** ID of the chunk that will be used to represent the two sided. **/
+ public static final Integer TWO_SIDED = new Integer((short)0xA081);
+ /** ID of the chunk that will be used to represent the texture. **/
+ public static final Integer TEXTURE = new Integer((short)0xA200);
+ /** ID of the chunk that will be used to represent the self illumination. **/
+ /** Represent a mesh object for shapes. */
+ public static final Integer MESH = new Integer((short)0x4100);
+ /** Represent a camera for viewing */
+ public static final Integer CAMERA = new Integer((short)0x4700);
+ /** Represent a light */
+ public static final Integer LIGHT = new Integer((short)0x4600);
+ /** Signifies that the light is off **/
+ //public static final Integer LIGHT_OFF = new Integer((short)0x4620);
+ //public static final Integer RAYTRACE = new Integer((short)0x4627);
+ //public static final Integer SHADOWED = new Integer((short)0x4630);
+ //public static final Integer SHADOW_MAP = new Integer((short)0x4641);
+ //public static final Integer SHOW_CONE = new Integer((short)0x4650);
+ //public static final Integer RECTANGULAR = new Integer((short)0x4651);
+ //public static final Integer OVERSHOOT = new Integer((short)0x4652);
+ //public static final Integer SPOT_MAP = new Integer((short)0x4653);
+ //public static final Integer SPOT_ROLL = new Integer((short)0x4656);
+ //public static final Integer RAY_TRACE_BIAS = new Integer((short)0x4658);
+ /** the id of a texture name chunk.*/
+ public static final Integer TEXTURE_NAME = new Integer((short)0xA300);
+ public static final int TEXTURE_TILING = 0xA351;
+ public static final int TEXBLUR = 0xA353;
+ /** The vertex list from which vertices of a face array will be used. */
+ public static final Integer VERTEX_LIST = new Integer((short)0x4110);
+ /** reference coordinates into the vertex list which represent texture coordinates. */
+ public static final Integer TEXTURE_COORDINATES = new Integer((short)0x4140);
+ /** Local coordinate system of the mesh. */
+ public static final Integer COORDINATE_AXES = new Integer((short)0x4160);
+ /** reference coordinates into the vertex list which represent shape vertex coordinates. */
+ public static final Integer FACES_DESCRIPTION = new Integer((short)0x4120);
+ public static final Integer MATERIAL = new Integer((short)0xAFFF);
+ public static final Integer SCALE = new Integer((short)0x100);
+ public static final Integer NAMED_OBJECT = new Integer((short)0x4000);
+ /** Key mapping faces material chunk as a child of this chunk */
+ public static final Integer FACES_MATERIAL = new Integer((short)0x4130);
+ /** Key mapping smoothing chunk as a child of this chunk */
+ public static final Integer SMOOTH = new Integer((short)0x4150);
+
+ /**
+ * singleton constructor.
+ */
+ public ChunkMap(Chunk mainChunk)
+ {
+ this.mainChunk = mainChunk;
+ initializeDataMap();
+ }
+
+ public Chunk get(Integer chunkID)
+ {
+ return (Chunk)super.get(chunkID);
+ }
+
+ /**
+ * looks up the chunk corresponding to chunkID
+ * in the chopper's cache. If its not there
+ * look it up from the parent chunk provided.
+ * @param chunkID the id of the chunk to lookup
+ * @return the chunk for chunkID
+ public synchronized Chunk getChunk(Chunk parentChunk, Integer chunkID)
+ {
+ Chunk chunk = (Chunk)get(chunkID);
+ if(chunk == null && parentChunk != null)
+ {
+ chunk = (Chunk)(parentChunk.getChunkMap().get(chunkID)); //look up chunk from its parent.
+ put(chunkID, chunk);
+ }
+ return chunk;
+ }
+ */
+
+ /**
+ * Called when debugging is turned on. The keys are cast to short so that
+ * they are improperly signed since java will be reading improperly signed
+ * ids out of the file.
+ */
+ private void initializeDataMap()
+ {
+ Chunk keyFramerChunk = new Chunk("KeyFramerChunk");
+ Chunk editorChunk = new Chunk("EditorChunk");
+ Chunk triangularMeshChunk = new Chunk("TriangularMeshChunk");
+
+ Chunk facesDescriptionChunk = new FacesDescriptionChunk();
+ Chunk framesDescriptionChunk = new FramesDescriptionChunk();
+ Chunk textureChunk = new TextureChunk();
+ Chunk lightChunk = new LightChunk();
+ Chunk namedObjectChunk = new NamedObjectChunk();
+ Chunk materialChunk = new MaterialChunk();
+ Chunk keyFramerInfoChunk = new KeyFramerInfoChunk();
+ Chunk spotLightChunk = new SpotLightChunk();
+ Chunk floatChunk = new FloatChunk();
+ Chunk framesChunk = new FramesChunk();
+ Chunk pivotChunk = new PivotChunk();
+ Chunk positionChunk = new PositionChunk();
+ Chunk rotationChunk = new RotationChunk();
+ Chunk scaleChunk = new ScaleChunk();
+ Chunk hierarchyInfoChunk = new HierarchyInfoChunk();
+ Chunk boundingBoxChunk = new BoundingBoxChunk();
+ Chunk stringChunk = new StringChunk();
+ Chunk globalColorChunk = new GlobalColorChunk();
+ Chunk booleanChunk = new BooleanChunk();
+ Chunk percentageChunk = new PercentageChunk();
+ Chunk cameraChunk = new CameraChunk();
+ Chunk colorChunk = new ColorChunk();
+ Chunk vertex3ListChunk = new Vertex3ListChunk();
+ Chunk vertex2ListChunk = new Vertex2ListChunk();
+ Chunk axisChunk = new AxisChunk();
+ Chunk facesMaterialChunk = new FacesMaterialChunk();
+ Chunk smoothingChunk = new SmoothingChunk();
+
+
+ //mainChunk.addSubChunk(VERSION, stringChunk);
+ mainChunk.addSubChunk(EDITOR, editorChunk);
+ mainChunk.addSubChunk(KEYFRAMER, keyFramerChunk);
+
+ editorChunk.addSubChunk(MATERIAL, materialChunk);
+ editorChunk.addSubChunk(SCALE, floatChunk);
+ editorChunk.addSubChunk(NAMED_OBJECT, namedObjectChunk);
+
+ keyFramerChunk.addSubChunk(FRAMES_CHUNK, framesChunk);
+ keyFramerChunk.addSubChunk(MESH_INFO, keyFramerInfoChunk);
+ //keyFramerChunk.addSubChunk(AMBIENT_LIGHT_INFO, keyFramerInfoChunk);
+ //keyFramerChunk.addSubChunk(CAMERA_INFO, keyFramerInfoChunk);
+ //keyFramerChunk.addSubChunk(CAMERA_TARGET_INFO, keyFramerInfoChunk);
+ //keyFramerChunk.addSubChunk(OMNI_LIGHT_INFO, keyFramerInfoChunk);
+ //keyFramerChunk.addSubChunk(SPOT_LIGHT_TARGET_INFO, keyFramerInfoChunk);
+ //keyFramerChunk.addSubChunk(SPOT_LIGHT_INFO, keyFramerInfoChunk);
+
+ keyFramerInfoChunk.addSubChunk(NAME_AND_FLAGS, framesDescriptionChunk);
+ keyFramerInfoChunk.addSubChunk(PIVOT, pivotChunk);
+ keyFramerInfoChunk.addSubChunk(POSITION, positionChunk);
+ keyFramerInfoChunk.addSubChunk(ROTATION, rotationChunk);
+ keyFramerInfoChunk.addSubChunk(SCALE_TRACK, scaleChunk);
+ keyFramerInfoChunk.addSubChunk(HIERARCHY_INFO, hierarchyInfoChunk);
+ keyFramerInfoChunk.addSubChunk(BOUNDING_BOX, boundingBoxChunk);
+
+ //spotLightChunk.addSubChunk(LIGHT_OFF, booleanChunk);
+ //spotLightChunk.addSubChunk(RAYTRACE, booleanChunk);
+ //spotLightChunk.addSubChunk(SHADOWED, booleanChunk);
+ //spotLightChunk.addSubChunk(SHOW_CONE, booleanChunk);
+ //spotLightChunk.addSubChunk(RECTANGULAR, booleanChunk);
+ //spotLightChunk.addSubChunk(SHADOW_MAP, booleanChunk);
+ //spotLightChunk.addSubChunk(OVERSHOOT, booleanChunk);
+ //spotLightChunk.addSubChunk(SPOT_MAP, booleanChunk);
+ //spotLightChunk.addSubChunk(SPOT_ROLL, booleanChunk);
+ //spotLightChunk.addSubChunk(RAY_TRACE_BIAS, booleanChunk);
+
+ materialChunk.addSubChunk(MATERIAL_NAME, stringChunk);
+
+ materialChunk.addSubChunk(AMBIENT_COLOR, globalColorChunk);
+ materialChunk.addSubChunk(DIFFUSE_COLOR, globalColorChunk);
+ materialChunk.addSubChunk(SPECULAR_COLOR, globalColorChunk);
+ materialChunk.addSubChunk(TEXTURE, textureChunk);
+
+ materialChunk.addSubChunk(TWO_SIDED, booleanChunk);
+
+ materialChunk.addSubChunk(SHININESS, percentageChunk);
+ materialChunk.addSubChunk(TRANSPARENCY, percentageChunk);
+
+ namedObjectChunk.addSubChunk(MESH, triangularMeshChunk);
+ namedObjectChunk.addSubChunk(CAMERA, cameraChunk);
+ namedObjectChunk.addSubChunk(LIGHT, lightChunk);
+
+ lightChunk.addSubChunk(RANGE_START, floatChunk);
+ lightChunk.addSubChunk(COLOR, colorChunk);
+ lightChunk.addSubChunk(RANGE_END, floatChunk);
+ lightChunk.addSubChunk(MULTIPLIER, floatChunk);
+ lightChunk.addSubChunk(SPOTLIGHT, spotLightChunk);
+
+
+ textureChunk.addSubChunk(TEXTURE_NAME, stringChunk);
+
+ triangularMeshChunk.addSubChunk(VERTEX_LIST, vertex3ListChunk);
+ triangularMeshChunk.addSubChunk(TEXTURE_COORDINATES, vertex2ListChunk);
+ triangularMeshChunk.addSubChunk(FACES_DESCRIPTION, facesDescriptionChunk);
+ triangularMeshChunk.addSubChunk(COORDINATE_AXES, axisChunk);
+
+ facesDescriptionChunk.addSubChunk(FACES_MATERIAL, facesMaterialChunk);
+ facesDescriptionChunk.addSubChunk(SMOOTH, smoothingChunk);
+
+ /*
+ put(new Integer((short)0x0010), "Rgb (float)");
+ put(new Integer((short)0x0011), "Rgb (byte)");
+ put(new Integer((short)0x0012), "Rgb (byte) gamma corrected");
+ put(new Integer((short)0x0013), "Rgb (float) gamma corrected");
+ put(new Integer((short)0x0030), "percent (int)");
+ put(new Integer((short)0x0031), "percent (float)");
+ put(new Integer((short)0x0002), "3DS-Version");
+ put(new Integer((short)0x3D3D), "3D editor chunk");
+ put(new Integer((short)0x0100), "One unit");
+ put(new Integer((short)0x1100), "Background bitmap");
+ put(new Integer((short)0x1101), "Use background bitmap");
+ put(new Integer((short)0x1200), "Background color");
+ put(new Integer((short)0x1201), "Use background color");
+ put(new Integer((short)0x1300), "Gradient colors");
+ put(new Integer((short)0x1301), "Use gradient");
+ put(new Integer((short)0x1400), "Shadow map bias");
+ put(new Integer((short)0x1420), "Shadow map size");
+ put(new Integer((short)0x1450), "Shadow map sample range");
+ put(new Integer((short)0x1460), "Raytrace bias");
+ put(new Integer((short)0x1470), "Raytrace on");
+ put(new Integer((short)0x2100), "Ambient color");
+ put(new Integer((short)0x2200), "Fog");
+ put(new Integer((short)0x2210), "fog background");
+ put(new Integer((short)0x2201), "Use fog");
+ put(new Integer((short)0x2210), "Fog background");
+ put(new Integer((short)0x2300), "Distance queue");
+ put(new Integer((short)0x2310), "Dim background");
+ put(new Integer((short)0x2301), "Use distance queue");
+ put(new Integer((short)0x2302), "Layered fog options");
+ put(new Integer((short)0x2303), "Use layered fog");
+ put(new Integer((short)0x3D3E), "Mesh version");
+ put(new Integer((short)0x4000), "Object block");
+ put(new Integer((short)0x4010), "Object hidden");
+ put(new Integer((short)0x4012), "Object doesn't cast");
+ put(new Integer((short)0x4013), "Matte object");
+ put(new Integer((short)0x4015), "External process on");
+ put(new Integer((short)0x4017), "Object doesn't receive shadows");
+ put(new Integer((short)0x4100), "Triangular mesh");
+ put(new Integer((short)0x4110), "Vertices list");
+ put(new Integer((short)0x4120), "Faces description");
+ put(new Integer((short)0x4130), "Faces material list");
+ put(new Integer((short)0x4140), "Mapping coordinates list");
+ put(new Integer((short)0x4150), "Smoothing group list");
+ put(new Integer((short)0x4160), "Local coordinate system");
+ put(new Integer((short)0x4165), "Object color in editor");
+ put(new Integer((short)0x4181), "External process name");
+ put(new Integer((short)0x4182), "External process parameters");
+ put(new Integer((short)0x4600), "Light");
+ put(new Integer((short)0x4610), "Spotlight");
+ put(new Integer((short)0x4627), "Spot raytrace");
+ put(new Integer((short)0x4630), "Light shadowed");
+ put(new Integer((short)0x4641), "Spot shadow map");
+ put(new Integer((short)0x4650), "Spot show cone");
+ put(new Integer((short)0x4651), "Spot is rectangular");
+ put(new Integer((short)0x4652), "Spot overshoot");
+ put(new Integer((short)0x4653), "Spot map");
+ put(new Integer((short)0x4656), "Spot roll");
+ put(new Integer((short)0x4658), "Spot ray trace bias");
+ put(new Integer((short)0x4620), "Light off");
+ put(new Integer((short)0x4625), "Attenuation on");
+ put(new Integer((short)0x4659), "Range start");
+ put(new Integer((short)0x465A), "Range end");
+ put(new Integer((short)0x465B), "Multiplier");
+ put(new Integer((short)0x4700), "Camera");
+ put(new Integer((short)0x7001), "Window settings");
+ put(new Integer((short)0x7011), "Window description #2 ...");
+ put(new Integer((short)0x7012), "Window description #1 ...");
+ put(new Integer((short)0x7020), "Mesh windows ...");
+ put(new Integer((short)0xAFFF), "Material block");
+ put(new Integer((short)0xA000), "Material name");
+ put(new Integer((short)0xA010), "Ambient color");
+ put(new Integer((short)0xA020), "Diffuse color");
+ put(new Integer((short)0xA030), "Specular color");
+ put(new Integer((short)0xA040), "Shininess percent");
+ put(new Integer((short)0xA041), "Shininess strength percent");
+ put(new Integer((short)0xA050), "Transparency percent");
+ put(new Integer((short)0xA052), "Transparency falloff percent");
+ put(new Integer((short)0xA053), "Reflection blur percent");
+ put(new Integer((short)0xA081), "2 sided");
+ put(new Integer((short)0xA083), "Add trans");
+ put(new Integer((short)0xA084), "Self illum");
+ put(new Integer((short)0xA085), "Wire frame on");
+ put(new Integer((short)0xA087), "Wire thickness");
+ put(new Integer((short)0xA088), "Face map");
+ put(new Integer((short)0xA08A), "In tranc");
+ put(new Integer((short)0xA08C), "Soften");
+ put(new Integer((short)0xA08E), "Wire in units");
+ put(new Integer((short)0xA100), "Render type");
+ put(new Integer((short)0xA240), "Transparency falloff percent present");
+ put(new Integer((short)0xA250), "Reflection blur percent present");
+ put(new Integer((short)0xA252), "Bump map present (true percent)");
+ put(new Integer((short)0xA200), "Texture map 1");
+ put(new Integer((short)0xA33A), "Texture map 2");
+ put(new Integer((short)0xA210), "Opacity map");
+ put(new Integer((short)0xA230), "Bump map");
+ put(new Integer((short)0xA33C), "Shininess map");
+ put(new Integer((short)0xA204), "Specular map");
+ put(new Integer((short)0xA33D), "Self illum. map");
+ put(new Integer((short)0xA220), "Reflection map");
+ put(new Integer((short)0xA33E), "Mask for texture map 1");
+ put(new Integer((short)0xA340), "Mask for texture map 2");
+ put(new Integer((short)0xA342), "Mask for opacity map");
+ put(new Integer((short)0xA344), "Mask for bump map");
+ put(new Integer((short)0xA346), "Mask for shininess map");
+ put(new Integer((short)0xA348), "Mask for specular map");
+ put(new Integer((short)0xA34A), "Mask for self illum. map");
+ put(new Integer((short)0xA34C), "Mask for reflection map");
+ put(new Integer((short)0xA300), "Mapping filename");
+ put(new Integer((short)0xA351), "Mapping parameters");
+ put(new Integer((short)0xA353), "Blur percent");
+ put(new Integer((short)0xA354), "V scale");
+ put(new Integer((short)0xA356), "U scale");
+ put(new Integer((short)0xA358), "U offset");
+ put(new Integer((short)0xA35A), "V offset");
+ put(new Integer((short)0xA35C), "Rotation angle");
+ put(new Integer((short)0xA360), "RGB Luma/Alpha tint 1");
+ put(new Integer((short)0xA362), "RGB Luma/Alpha tint 2");
+ put(new Integer((short)0xA364), "RGB tint R");
+ put(new Integer((short)0xA366), "RGB tint G");
+ put(new Integer((short)0xA368), "RGB tint B");
+ put(new Integer((short)0xB000), "Key Framer");
+ put(new Integer((short)0xB001), "Ambient light information block");
+ put(new Integer((short)0xB002), "Mesh information block");
+ put(new Integer((short)0xB003), "Camera information block");
+ put(new Integer((short)0xB004), "Camera target information block");
+ put(new Integer((short)0xB005), "Omni light information block");
+ put(new Integer((short)0xB006), "Spot light target information block");
+ put(new Integer((short)0xB007), "Spot light information block");
+ put(new Integer((short)0xB008), "Frames (Start and End)");
+ put(new Integer((short)0xB009), "Current Frame");
+ put(new Integer((short)0xB00A), "Animation revision, filename and length");
+ put(new Integer((short)0xB010), "Object name, parameters and hierarchy father");
+ put(new Integer((short)0xB013), "Object pivot point");
+ put(new Integer((short)0xB014), "Bounding Box");
+ put(new Integer((short)0xB015), "Object morph angle");
+ put(new Integer((short)0xB020), "Position track");
+ put(new Integer((short)0xB021), "Rotation track");
+ put(new Integer((short)0xB022), "Scale track");
+ put(new Integer((short)0xB023), "FOV track");
+ put(new Integer((short)0xB024), "Roll track");
+ put(new Integer((short)0xB025), "Color track");
+ put(new Integer((short)0xB026), "Morph track");
+ put(new Integer((short)0xB027), "Hotspot track");
+ put(new Integer((short)0xB028), "Falloff track");
+ put(new Integer((short)0xB029), "Hide track");
+ put(new Integer((short)0xB030), "Hierarchy position");
+ */
+ }
+
+ }
diff --git a/com/microcrowd/loader/java3d/max3ds/ChunkTester.java b/com/microcrowd/loader/java3d/max3ds/ChunkTester.java
new file mode 100644
index 0000000..55cf0ed
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/ChunkTester.java
@@ -0,0 +1,31 @@
+/**
+ * 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.com
+ */
+
+package com.microcrowd.loader.java3d.max3ds;
+
+/**
+ * Used to test and create test data for chunks.
+ */
+public class ChunkTester
+{
+
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/DefaultTextureImageLoader.java b/com/microcrowd/loader/java3d/max3ds/DefaultTextureImageLoader.java
new file mode 100644
index 0000000..639e01f
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/DefaultTextureImageLoader.java
@@ -0,0 +1,103 @@
+/**
+ * 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@realvue.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.InputStream;
+import java.net.URL;
+import javax.imageio.ImageIO;
+
+/**
+ * General purpose implementation of TextureImageLoader.
+ * Gets the base path from loader and prepends it to the
+ * file name to load an image.
+ */
+public class DefaultTextureImageLoader implements TextureImageLoader
+{
+
+ private Loader3DS loader;
+
+ /**
+ * Constructs an image loader that will resolve image
+ * locations to the base path of the loader provided.
+ * @param the loader that will specify the base path
+ * used to retrieve images.
+ */
+ public DefaultTextureImageLoader(Loader3DS loader)
+ {
+ this.loader = loader;
+ }
+
+
+ /**
+ * Gets the image to be loaded as a texture.
+ * @param imageName the name of the image to load.
+ * @return image to be used.
+ */
+ public Image getTextureImage(String imageName)
+ {
+ File file = null;
+ InputStream in = null;
+ if(loader.fromUrl())
+ {
+ try
+ {
+ in = new URL(loader.getBaseUrl() + imageName).openStream();
+ return ImageIO.read(in);
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new IllegalArgumentException(" Can't load texture: " + imageName +
+ " Make sure it is located in the " +
+ " same server and directory with the model file."+
+ " the loader's base path is: " + loader.getBaseUrl());
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ throw new IllegalArgumentException(" Can't load texture: " + imageName +
+ " Make sure it is located in the " +
+ " same server and directory with the model file."+
+ " the loader's base path is: " + loader.getBaseUrl());
+ }
+ }
+ else
+ {
+ try
+ {
+ in = new FileInputStream(new File(loader.getBasePath() + imageName));
+ return ImageIO.read(in);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ throw new IllegalArgumentException(" Can't load texture: " + imageName +
+ " Make sure it is located in the " +
+ " same server and directory with the model file."+
+ " the loader's base path is: " + loader.getBasePath());
+ }
+ }
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/Loader3DS.java b/com/microcrowd/loader/java3d/max3ds/Loader3DS.java
new file mode 100644
index 0000000..2246ac1
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/Loader3DS.java
@@ -0,0 +1,317 @@
+/**
+ * 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;
+ }
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/Main.java b/com/microcrowd/loader/java3d/max3ds/Main.java
new file mode 100644
index 0000000..191e4b8
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/Main.java
@@ -0,0 +1,454 @@
+/**
+ * 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;
+ }
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/TextureImageLoader.java b/com/microcrowd/loader/java3d/max3ds/TextureImageLoader.java
new file mode 100644
index 0000000..17a4daf
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/TextureImageLoader.java
@@ -0,0 +1,42 @@
+/**
+ * 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;
+
+/**
+ * Interface specifying a lookup for images to be loaded
+ * in textures. Implementations using this loader may need
+ * to use different methods to resolve images. In these
+ * cases a class should be created that implements
+ * this interface. For general purpose applications
+ * DefaultTextureImageLoader should be used.
+ */
+public interface TextureImageLoader
+{
+
+ /**
+ * Gets the image to be loaded as a texture.
+ * @param imageName the name of the image with which it will be
+ * looked up.
+ */
+ public Image getTextureImage(String imageaName) throws Exception;
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/AxisChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/AxisChunk.java
new file mode 100644
index 0000000..bd800d4
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/AxisChunk.java
@@ -0,0 +1,83 @@
+/**
+ * Make a donation http://sourceforge.net/donate/index.php?group_id=98797
+ * Microcrowd
+ *
+ * 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.chunks;
+
+import javax.media.j3d.Transform3D;
+import javax.vecmath.Point3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * Extracts the local coordinate that will act
+ * as a shape's axis that will be used by the mesh
+ * info chunk.
+ */
+public class AxisChunk extends Chunk
+{
+ private float value;
+
+ /**
+ * Loads the local coordinate system for the current mesh.
+ *
+ * @param chopper the ChunkChopper containing the state of the parser.
+ *
+ * The location of the local coordinate system is defined relative to
+ * positions and rotations at frame 0. But the orientation is absolutely
+ * defined.
+ *
+ * With either 3x3 or 4x4 rotation, translation, there
+ * is a simple relationship between each matrix and the resulting coordinate
+ * system. The first three columns of the matrix define the direction vector of the
+ * X, Y and Z axii respectively.
+ * If a 4x4 matrix is defined as:
+ * <code>
+ * | A B C D |
+ * M = | E F G H |
+ * | I J K L |
+ * | M N O P |
+ * </code>
+ * Then the direction vector for each axis is as follows:
+ *
+ * <code>
+ * X-axis = [ A E I ]
+ * Y-axis = [ B F J ]
+ * Z-axis = [ C G K ]
+ * </code>
+ *
+ * @return the actual number of bytes read.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ Point3f xAxis = new Point3f();
+ xAxis = chopper.getPoint();
+ Point3f zAxis = chopper.getPoint();
+ Point3f yAxis = chopper.getPoint();
+ Point3f origin = chopper.getPoint();
+
+ Transform3D transform = new Transform3D(new double[]{
+ xAxis.x, xAxis.y, xAxis.z, origin.x,
+ yAxis.x, yAxis.y, yAxis.z, origin.y,
+ -zAxis.x, -zAxis.y, -zAxis.z, origin.z,
+ 0,0,0,1});
+ String meshName = chopper.getObjectName();
+ chopper.getKeyFramer().setCoordinateSystem(meshName, transform);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/BooleanChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/BooleanChunk.java
new file mode 100644
index 0000000..2a27f7c
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/BooleanChunk.java
@@ -0,0 +1,46 @@
+/**
+ * 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.chunks;
+
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * A boolean chunk is true if it is present otherwise
+ * there is no chunk and that represents false. This chunk
+ * will set chopper data to Boolean true with a key that is the id of the chunk.
+ * These have no subchunks. Only String data.
+ */
+public class BooleanChunk extends Chunk
+{
+ /**
+ * If this method is being called then
+ * a boolean true will be set on the chunk chopper
+ * with a key that is the id of this chunk.
+ *
+ * @param chopper the chopper on which the boolean true data is to be set
+ *
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ chopper.pushData(chopper.getID(), new Boolean(true));
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/BoundingBoxChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/BoundingBoxChunk.java
new file mode 100644
index 0000000..e7ca85c
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/BoundingBoxChunk.java
@@ -0,0 +1,55 @@
+/**
+ * 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.chunks;
+
+import javax.media.j3d.BoundingBox;
+import javax.vecmath.Point3d;
+import javax.vecmath.Point3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * Loads the bounding box for keyframer of mesh. The pivot
+ * is relative to it.
+ * {@see KeyFramerInfoChunk} for more information about using
+ * animations from a 3ds file
+ */
+public class BoundingBoxChunk extends Chunk
+{
+ /**
+ * Gets the bounding box and associates it with the current mes.
+ * @param chopper the ChunkChopper containing the state of the parser.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ Point3f min = chopper.getPoint();
+ Point3f max = chopper.getPoint();
+ BoundingBox box = new BoundingBox(new Point3d(min), new Point3d(max));
+
+ Point3f center = new Point3f(max.x - min.x,
+ max.y - min.y,
+ max.z - min.z);
+
+ //chopper.getKeyFramer().setBoundingBox(box);
+ chopper.getKeyFramer().setPivotCenter(center);
+ }
+
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/CameraChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/CameraChunk.java
new file mode 100644
index 0000000..0044347
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/CameraChunk.java
@@ -0,0 +1,65 @@
+/**
+ * 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.chunks;
+
+import javax.media.j3d.Transform3D;
+import javax.media.j3d.TransformGroup;
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector3d;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+/**
+ * Loads percentage values from binary data representing them.
+ */
+public class CameraChunk extends Chunk
+{
+ /**
+ * Reads the position and target vectors and subtracts them to get
+ * an axis of rotation. Translate a transform to position and rotate
+ * on the axis of rotation to point at the target. The angle
+ * between the z axis and the axis of rotation is the angle used to
+ * rotate. The translated and rotated vector is stored it the
+ * chopper as a named object since camera chunks are named.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ Vector3d yVector = new Vector3d(0,1,0);
+ Point3d position = new Point3d(chopper.getPoint());
+ Point3d target = new Point3d(chopper.getPoint());
+ float bank = chopper.getFloat();
+ float lens = chopper.getFloat();
+
+ //This is the vector for the direction
+ //of the camera. Represented as a line
+ //from target to position. We'll use it
+ //as an axis when we bank.
+ //Vector3d cameraDirection = new Vector3d();
+ //cameraDirection.sub(target,position);
+ //AxisAngle4f bankAxisAngle = new AxisAngle4f(cameraDirection, bankAngle);
+
+
+ Transform3D transform = new Transform3D();
+ transform.lookAt(position, target, yVector);
+ transform.invert();
+ ((TransformGroup)chopper.getGroup()).setTransform(transform);
+ chopper.addViewGroup(chopper.getGroup());
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/Chunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/Chunk.java
new file mode 100644
index 0000000..a25bae7
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/Chunk.java
@@ -0,0 +1,139 @@
+/**
+ * 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.chunks;
+
+import java.util.HashMap;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * The base class for all chunks. Chunks are flyweights and should be managed
+ * by {@link ChunkChopper} Every chunk should know how many bytes of data(or
+ * be able figure out) to read before its subchunks are found. Chunks that only have
+ * subchunks need not overrided loadData.
+ * Chunks may store data for later use in loadData with {@link pushData}
+ * If a chunk needs to initialize components with from subchunks, that data
+ * can be retrieved with {@link ChunkChopper#popData} inside the {@link
+ * #initialize} method. {@link #loadData} is called at the beginning of the
+ * loading process, before any data or subchunks have been loaded(the chunk
+ * itself must load its data).
+ * <p>
+ * During loadData, if the length of data before subchunks is unknown,
+ * {@link ChunkChopper#getChunkBytes} may be called and all the data
+ * for the chunk(including subchunks) will be read and returned.
+ */
+public class Chunk
+{
+ private HashMap subChunkMap = new HashMap();
+ private String name;
+ private String description;
+
+ /**
+ * default no-arg constructror.
+ */
+ public Chunk(String chunkName)
+ {
+ name = chunkName;
+ }
+
+ /**
+ * default no-arg constructror.
+ */
+ public Chunk()
+ {
+ }
+
+ public void addSubChunk(Integer id, Chunk subChunk)
+ {
+ subChunkMap.put(id, subChunk);
+ }
+
+ public Chunk getSubChunk(Integer id)
+ {
+ return (Chunk)subChunkMap.get(id);
+ }
+
+ /**
+ * This method is called after all the current chunks subchunks are
+ * loaded. Any data stored by those subchunks may be retrieved via {@link
+ * ChunkChopper#popData}
+ * The default implementation does nothing.
+ *
+ * @param chopper may contain data loaded by subchunks.
+ */
+ public void initialize(ChunkChopper chopper)
+ {
+ }
+
+ /**
+ * This is called by the chunk chopper before any of the chunk's
+ * subchunks are loaded. Any data loaded that may need to be
+ * used later by superchunks should be stored in
+ * the chunk chopper via {@link ChunkChopper#popData}
+ * The default implementation does nothing.
+ * @param chopper may contain data loaded by subchunks.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ }
+
+ /**
+ * Sets nice human readable name for the chunk.
+ * @param name to use for display of this chunk.
+ */
+ public final void setName(String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * Gets a human readable name for the chunk.
+ * @return name used to display the chunk.
+ */
+ public final String getName()
+ {
+ return name;
+ }
+
+ public final String getDescription()
+ {
+ return description;
+ }
+
+ public final void setDescription(String desc)
+ {
+ description = desc;
+ }
+
+ /**
+ * Returns the name of this chunk.
+ * If the name is null then it just
+ * returns the unqualified class name.
+ */
+ public String toString()
+ {
+ if (getName() != null)
+ return getName();
+ String className = getClass().getName();
+ return className.substring(className.lastIndexOf('.') + 1,
+ className.length());
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/ColorChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/ColorChunk.java
new file mode 100644
index 0000000..c6e24df
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/ColorChunk.java
@@ -0,0 +1,82 @@
+/**
+ * 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.chunks;
+
+import javax.vecmath.Color3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * Loads colors from binary data representing them.
+ */
+public class ColorChunk extends Chunk
+{
+ protected int currentColorType;
+
+ private static final int FLOAT_COLOR = 0x10;
+ private static final int BYTE_COLOR = 0x11;
+ private static final int BYTE_COLOR_GAMMA = 0x12;
+ private static final int FLOAT_COLOR_GAMMA = 0x13;
+
+ /**
+ * Based on the color type retrieved
+ * from {@link #getColorType} loads
+ * an rgb or float color and pushes
+ * it onto the chunk chopper.
+ *
+ * @param chopper the chopper that will store the color data.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ int colorType = getColorType(chopper);
+ if (colorType == BYTE_COLOR)
+ {
+ float r = (chopper.getUnsignedByte()) / 255f;
+ float g = (chopper.getUnsignedByte()) / 255f;
+ float b = (chopper.getUnsignedByte()) / 255f;
+ Color3f color = new Color3f(r, g, b);
+ chopper.pushData(chopper.getID(), color);
+ }
+ else if (colorType == FLOAT_COLOR)
+ {
+ Color3f color = new Color3f(chopper.getFloat(), chopper.getFloat(), chopper.getFloat());
+ chopper.pushData(chopper.getID(), color);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Only RGB colors are enabled. ChunkID="
+ + Integer.toHexString((byte)chopper.getID().intValue())
+ + " Color type = " + Integer.toHexString((byte)colorType));
+ }
+ }
+
+ /**
+ * Gets the color type for this chunk.
+ * @param chopper with the information the
+ * chunk may use to determine color type
+ * @return the color type for the chunk retrieved
+ * from the chopper using this chunks id.
+ */
+ protected int getColorType(ChunkChopper chopper)
+ {
+ return chopper.getID().intValue();
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/FacesDescriptionChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/FacesDescriptionChunk.java
new file mode 100644
index 0000000..12cad0a
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/FacesDescriptionChunk.java
@@ -0,0 +1,322 @@
+/**
+ * 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.chunks;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import javax.media.j3d.Appearance;
+import javax.media.j3d.Geometry;
+import javax.media.j3d.Material;
+import javax.media.j3d.Shape3D;
+import javax.media.j3d.TransformGroup;
+import javax.vecmath.Color3f;
+import javax.vecmath.Point3f;
+import javax.vecmath.TexCoord2f;
+import javax.vecmath.Vector3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+import com.microcrowd.loader.java3d.max3ds.ChunkMap;
+import com.sun.j3d.utils.geometry.GeometryInfo;
+import com.sun.j3d.utils.geometry.NormalGenerator;
+import com.sun.j3d.utils.geometry.Stripifier;
+
+/**
+ * This chunk describes all the triangles that make up a mesh.
+ * Each triangle is defined in terms of three indexes each of which
+ * is a point reference to a vertex in the vertex list loaded
+ * by the triangular mesh chunk.
+ * After loading the Smoothing chunk the normals for the mesh
+ * are generated accordingly.
+ */
+public class FacesDescriptionChunk extends Chunk
+{
+ public static final Appearance DEFAULT_APPEARANCE;
+
+ private Point3f[] currentVertices;
+ private TexCoord2f[] textureTriangles;
+ private PointMapper shareMap;
+
+ static {
+ DEFAULT_APPEARANCE= new Appearance();
+ Material defaultMaterial = new Material();
+ defaultMaterial.setAmbientColor(new Color3f(.5f, .5f, .5f));
+ //defaultMaterial.setDiffuseColor(new Color3f(.5f, .5f, .5f));
+ //defaultMaterial.setSpecularColor(new Color3f(.5f, .5f, .5f));
+ DEFAULT_APPEARANCE.setMaterial(defaultMaterial);
+ }
+
+
+
+ /**
+ * Maintains a two way mapping between coordinates
+ * and vertices. A coordinate to vertex is one to many
+ * Vertex to coordinate is one to one.
+ * In this class we maintain the definition that a coordinate
+ * is a point in 3D space and a vertex is a coordinate serving
+ * as one of three defining a face.
+ */
+ private class PointMapper extends HashMap
+ {
+ private Set[] coordinateSet;
+ /**
+ * Constructs a PointMapper with a
+ * the number of coordinates initialized to size.
+ * @param size the number of coordinates in the set.
+ */
+ public PointMapper(int size)
+ {
+ coordinateSet = new Set[size];
+ }
+
+ /**
+ * Adds an index for a coordinate to the set of vertices mapped
+ * to that coordinate. All coordinates may have one or more vertices
+ * that use them.
+ * @param coordinate the coordinate being mapped to the vertexNum
+ * @param vertexNum the number of the vertex using the coordinate
+ */
+ public void addCoordinate(Point3f coordinate, int vertexNum)
+ {
+ Set sharedCoordinates = (Set)get(coordinate);
+ if(sharedCoordinates == null)
+ {
+ sharedCoordinates = new HashSet();
+ put(coordinate, sharedCoordinates);
+ }
+ sharedCoordinates.add(new Integer(vertexNum));
+ coordinateSet[vertexNum] = sharedCoordinates;
+ }
+
+ /**
+ * Gets all the coordinates for a particular vertex that
+ * also share that vertex after the smoothing groups have been
+ * accounted for. Any coordinates that are not both shared
+ * by the vertex and do not share a smoothing group with the coordinate
+ * will not be returned.
+ * @param coordinateNum the number of the coordinate to get the set
+ * of vertices for that share it.
+ * @param smoothGroups the group of coordinates used to filter out the
+ * non-shared vertices.
+ */
+ public Set getSharedCoordinates(int coordinateNum, int[] smoothGroups)
+ {
+ Set returnSet = new HashSet();
+ Set sharingVertices = coordinateSet[coordinateNum];
+ Iterator vertices = sharingVertices.iterator();
+ int coordinateMask = smoothGroups[coordinateNum];
+ while(vertices.hasNext())
+ {
+ Integer vertex = (Integer)vertices.next();
+ int nextMask = smoothGroups[vertex.intValue()];
+ if((nextMask & coordinateMask) != 0)
+ {
+ returnSet.add(vertex);
+ }
+ }
+ return returnSet;
+ }
+ }
+
+ /**
+ * Reads the number of faces from the ChunkChopper.
+ * For each face read three shorts representing
+ * indices of vertices loaded by the TriangularMeshChunk
+ *
+ * @param chopper chopper the has the data
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ int numFaces = chopper.getUnsignedShort();
+ shareMap = new PointMapper(numFaces*3);
+ Point3f[] coordinates = (Point3f[])chopper.popData(ChunkMap.VERTEX_LIST);
+ TexCoord2f[] texturePoints = (TexCoord2f[])chopper.popData(ChunkMap.TEXTURE_COORDINATES);
+
+ currentVertices = new Point3f[numFaces * 3];
+ chopper.pushData(chopper.getID(), currentVertices);
+ if (texturePoints != null)
+ {
+ textureTriangles = new TexCoord2f[numFaces * 3];
+ }
+
+ for (int i = 0; i < numFaces; i++) {
+ int vertexIndex = i * 3;
+ int index0 = chopper.getUnsignedShort();
+ int index1 = chopper.getUnsignedShort();
+ int index2 = chopper.getUnsignedShort();
+
+ currentVertices[vertexIndex] = coordinates[index0];
+ currentVertices[vertexIndex + 1] = coordinates[index1];
+ currentVertices[vertexIndex + 2] = coordinates[index2];
+
+ shareMap.addCoordinate(coordinates[index0], vertexIndex);
+ shareMap.addCoordinate(coordinates[index1], vertexIndex+1);
+ shareMap.addCoordinate(coordinates[index2], vertexIndex+2);
+
+
+ if (textureTriangles != null) {
+ textureTriangles[vertexIndex] = texturePoints[index0];
+ textureTriangles[vertexIndex + 1] = texturePoints[index1];
+ textureTriangles[vertexIndex + 2] = texturePoints[index2];
+ }
+
+ //This is a bit masked value that is used to determine which edges are visible... not needed.
+ chopper.getUnsignedShort();
+ }
+ }
+
+ /**
+ * Loads a mesh onto the scene graph with the specified data
+ * from subchunks.
+ * If there is no material, this will put a default
+ * material on the shape.
+ */
+ public void initialize(ChunkChopper chopper)
+ {
+ final String materialName = (String)chopper.popData(ChunkMap.FACES_MATERIAL);
+ final int[] smoothGroups = (int[])chopper.popData(ChunkMap.SMOOTH);
+ Shape3D shape = new Shape3D();
+ GeometryInfo geometryInfo = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);
+
+ geometryInfo.setCoordinates(currentVertices);
+ TransformGroup transformGroup = (TransformGroup)chopper.getGroup();
+ transformGroup.addChild(shape);
+
+ if (textureTriangles != null)
+ {
+ geometryInfo.setTextureCoordinateParams(1, 2);
+ geometryInfo.setTextureCoordinates(0, textureTriangles);
+ }
+
+ if(materialName != null)
+ {
+ shape.setAppearance((Appearance)chopper.getNamedObject(materialName));
+ }
+ else
+ {
+ shape.setAppearance(DEFAULT_APPEARANCE);
+ }
+ if(smoothGroups == null)
+ {
+ NormalGenerator normalGenerator = new NormalGenerator();
+ geometryInfo.recomputeIndices();
+ normalGenerator.generateNormals(geometryInfo);
+ }
+ else
+ {
+ Vector3f[] normals = generateNormals(currentVertices);
+ Vector3f[] smoothNormals = smoothNormals(normals, shareMap, smoothGroups);
+ geometryInfo.setNormals(smoothNormals);
+ }
+
+ new Stripifier().stripify(geometryInfo);
+ shape.setGeometry(geometryInfo.getGeometryArray());
+ shape.setCapability(Geometry.ALLOW_INTERSECT);
+ com.sun.j3d.utils.picking.PickTool.setCapabilities(shape, com.sun.j3d.utils.picking.PickTool.INTERSECT_FULL);
+
+ currentVertices=null;
+ textureTriangles=null;
+ }
+
+ /**
+ * Takes all the normals for all the vertices and averages them with
+ * normals with which they share a coordinate and at least one smooth group.
+ * @param currentNormals the normals for each face.
+ * @param sharedPoints the point mapper that will choose which points are
+ * and which are not shared.
+ * @param smoothGroups the indexed list of group masks loaded by the smooth chunk.
+ * @return normals averaged among the shared vertices in their smoothing groups.
+ */
+ public Vector3f[] smoothNormals(Vector3f[] currentNormals, PointMapper sharedPoints, int[] smoothGroups)
+ {
+ Vector3f[] smoothNormals = new Vector3f[currentNormals.length];
+ for(int i=0; i < currentNormals.length; i++)
+ {
+ Set otherPoints = sharedPoints.getSharedCoordinates(i, smoothGroups);
+ if(otherPoints != null)
+ {
+ Vector3f[] sharedNormals = new Vector3f[otherPoints.size()];
+ Iterator pointIterator = otherPoints.iterator();
+ for(int j = 0; j < sharedNormals.length; j++)
+ {
+ sharedNormals[j] = currentNormals[((Integer)pointIterator.next()).intValue()];
+ }
+ smoothNormals[i] = averageNormals(sharedNormals);
+ }
+ else
+ {
+ smoothNormals[i] = currentNormals[i];
+ }
+ }
+ return smoothNormals;
+ }
+
+ /**
+ * Averages the normals provided in order to provide
+ * smooth, noncreased appearances for meshes.
+ * @param normals the normals that should be averaged
+ * @return a normalized normal that can be used in place
+ * of all the normals provided.
+ */
+ public Vector3f averageNormals(Vector3f[] normals)
+ {
+ Vector3f newNormal = new Vector3f();
+ for(int i=0; i < normals.length; i++)
+ {
+ newNormal.add(normals[i]);
+ }
+ newNormal.normalize();
+ return newNormal;
+ }
+
+ /**
+ * Generates normals for each vertex of each
+ * face that are absolutely normal to the face.
+ * @param point0 The first point of the face
+ * @param point1 The second point of the face
+ * @param point2 The third point of the face
+ * @return the three normals that should be
+ * used for the triangle represented by the parameters.
+ */
+ private Vector3f[] generateNormals(Point3f points[])
+ {
+ Vector3f[] normals = new Vector3f[points.length];
+ for(int i=0; i < normals.length;)
+ {
+ Vector3f normal = new Vector3f();
+ Vector3f v1 = new Vector3f();
+ Vector3f v2 = new Vector3f();
+
+ v1.sub(points[i+1], points[i]);
+ v2.sub(points[i+2], points[i]);
+ normal.cross(v1, v2);
+ normal.normalize();
+
+
+ normals[i++] = new Vector3f(normal);
+ normals[i++] = new Vector3f(normal);
+ normals[i++] = new Vector3f(normal);
+ }
+
+ return normals;
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/FacesMaterialChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/FacesMaterialChunk.java
new file mode 100644
index 0000000..7fbe4be
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/FacesMaterialChunk.java
@@ -0,0 +1,59 @@
+/**
+ * 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.chunks;
+
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * FacesMaterialsChunk contains the materials information
+ * from the 3ds file. It contains information pertaining to
+ * which faces of a mesh have materials on them and the
+ * texture coordinates for texture mapping.
+ * Right now, its just putting the name of the material
+ * that needs to be applied to the mesh under construction.
+ *
+ * @author jdeford
+ */
+public class FacesMaterialChunk extends Chunk
+{
+ /**
+ * Loads the texture coordinates for a mesh,
+ *
+ * @param chopper the ChunkChopper containing the state of the parser.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ final String materialName = chopper.getString();
+ int numFaces = chopper.getUnsignedShort();
+ if (numFaces > 0)
+ {
+ for (int j = 0; j < numFaces; j++)
+ {
+ int index = j * 3;
+ int position = chopper.getUnsignedShort() * 3;
+ }
+ }
+
+ chopper.pushData(chopper.getID(), materialName);
+ }
+}
+
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/FloatChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/FloatChunk.java
new file mode 100644
index 0000000..d408714
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/FloatChunk.java
@@ -0,0 +1,47 @@
+/**
+ * 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.chunks;
+
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * These have no subchunks. Only data.
+ * Any objects that have a float chunk
+ * as a sub chunk may retrieve the float
+ * value from {@link ChunkChopper.popData()}
+ * using the current chunk id as an argument.
+ */
+public class FloatChunk extends Chunk
+{
+ /**
+ * Loads a Float value into the chopper
+ * for use later when parent chunks are
+ * initializing
+ *
+ * @param chopper the chopper in which the float
+ * chunk will be stored by the id of this chunk.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ chopper.pushData(chopper.getID(), new Float(chopper.getFloat()));
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/FramesChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/FramesChunk.java
new file mode 100644
index 0000000..2677928
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/FramesChunk.java
@@ -0,0 +1,45 @@
+/**
+ * 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.chunks;
+
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * This chunk specifies the beginning and end frames.
+ *
+ * @author jdeford
+ */
+public class FramesChunk extends Chunk
+{
+ /**
+ * Reads two ints. Start frame and stop frame.
+ *
+ * @param chopper the chopper that may be used to store the starting and
+ * stopping frames.
+ *
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ long start = chopper.getUnsignedInt();
+ long stop = chopper.getUnsignedInt();
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/FramesDescriptionChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/FramesDescriptionChunk.java
new file mode 100644
index 0000000..a570ef9
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/FramesDescriptionChunk.java
@@ -0,0 +1,59 @@
+/**
+ * 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.chunks;
+
+
+import javax.media.j3d.TransformGroup;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+import com.microcrowd.loader.java3d.max3ds.data.KeyFramer;
+/**
+ * This chunk contains the name of the object
+ * the frames belong to and the parameters and
+ * hierarchy information for it.
+ */
+public class FramesDescriptionChunk extends Chunk
+{
+ /**
+ * reads the name of the object for these frames
+ * and stores it in the chopper.
+ *
+ * @param chopper the chopper used to store the transient data
+ * for this chunk.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ KeyFramer keyFramer = chopper.getKeyFramer();
+ String objectName = chopper.getString();
+ chopper.setObjectName(objectName);
+ chopper.getUnsignedShort();
+ chopper.getUnsignedShort();
+ int fatherID = chopper.getShort();
+ TransformGroup transformGroup = chopper.getNamedTransformGroup(objectName);
+ if(transformGroup == null)//its a dummy transformGroup.
+ {
+ transformGroup = new TransformGroup();
+ keyFramer.setDummyObject(transformGroup);
+ }
+
+ keyFramer.addFather(fatherID, transformGroup);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/GlobalColorChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/GlobalColorChunk.java
new file mode 100644
index 0000000..e8b3ed0
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/GlobalColorChunk.java
@@ -0,0 +1,45 @@
+/**
+ * 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.chunks;
+
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * Loads colors from binary data representing them.
+ * Its a global in the manner that it reads its own
+ * header information.
+ */
+public class GlobalColorChunk extends ColorChunk
+{
+ /**
+ * Gets the color type for this chunk.
+ * @param chopper with the information the
+ * chunk may use to determine color type
+ * @return the color type for the chunk.
+ */
+ protected int getColorType(ChunkChopper chopper)
+ {
+ int type = chopper.getUnsignedShort();
+ int colorLength = chopper.getUnsignedInt();
+ return type;
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/HierarchyInfoChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/HierarchyInfoChunk.java
new file mode 100644
index 0000000..a5c48db
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/HierarchyInfoChunk.java
@@ -0,0 +1,46 @@
+/**
+ * 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.chunks;
+
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * A HierarchyInfoChunk stores information about
+ * where an object belong in a hierarchy of object that
+ * have animations which may or may not be related.
+ * Each object, including dummy objects, have an identifier
+ * used to specify them as hierarchical parents of other
+ * objects for the purpose of key framing.
+ *
+ * @author Josh DeFord
+ */
+public class HierarchyInfoChunk extends Chunk
+{
+ /**
+ * Loads a word of data that describes the parent.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ int hierarchyIdentifier = chopper.getShort();
+ chopper.getKeyFramer().setID(hierarchyIdentifier);
+ }
+
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/KeyFramerInfoChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/KeyFramerInfoChunk.java
new file mode 100644
index 0000000..6d6d6d4
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/KeyFramerInfoChunk.java
@@ -0,0 +1,68 @@
+/**
+ * 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.chunks;
+
+import javax.media.j3d.Behavior;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * A KeyFramerInfoChunk stores information about things
+ * that happen to meshes: Position information, rotation
+ * information, scale information, pivot information
+ * and frame information.
+ * Together with the frames chunk thes are used
+ * display animation behaviors.
+ *
+ * @author Josh DeFord
+ */
+public class KeyFramerInfoChunk extends Chunk
+{
+
+ /**
+ * Retrieves the named object for the current key framer
+ * inserts the rotation, position and pivot transformations for frame 0
+ * and assigns the coordinate system to it.
+ *
+ * The inverse of the local coordinate system converts from 3ds
+ * semi-absolute coordinates (what is in the file) to local coordinates.
+ *
+ * Then these local coordinates are converted with matrix
+ * that will instantiate them to absolute coordinates:
+ * Xabs = sx a1 (Xl-Px) + sy a2 (Yl-Py) + sz a3 (Zl-Pz) + Tx
+ * Yabs = sx b1 (Xl-Px) + sy b2 (Yl-Py) + sz b3 (Zl-Pz) + Ty
+ * Zabs = sx c1 (Xl-Px) + sy c2 (Yl-Py) + sz c3 (Zl-Pz) + Tz
+ * Where:
+ * (Xabs,Yabs,Zabs) = absolute coordinate
+ * (Px,Py,Pz) = mesh pivot (constant)
+ * (X1,Y1,Z1) = local coordinates
+ *
+ * @param chopper the ChunkChopper containing the current state of the parser.
+ */
+ public void initialize(ChunkChopper chopper)
+ {
+ String meshName = (String)chopper.getObjectName();
+ Behavior frameBehavior = chopper.getKeyFramer().createBehavior(meshName,
+ chopper.getNamedTransformGroup(meshName),
+ chopper.getNamedObject(meshName));
+ if(frameBehavior != null)
+ chopper.addBehaviorNode(frameBehavior);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/LightChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/LightChunk.java
new file mode 100644
index 0000000..501697d
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/LightChunk.java
@@ -0,0 +1,80 @@
+/**
+ * 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.chunks;
+
+import javax.media.j3d.BoundingSphere;
+import javax.media.j3d.PointLight;
+import javax.media.j3d.Transform3D;
+import javax.media.j3d.TransformGroup;
+import javax.vecmath.Color3f;
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+import com.microcrowd.loader.java3d.max3ds.ChunkMap;
+/**
+ * Lights to be placed in a scene.
+ * Only point lights and target spot lights are supported.
+ * All the default parameters are used for lights as well.
+ * Only position is specified.
+ */
+public class LightChunk extends Chunk
+{
+ private Vector3f currentPosition;
+
+ /**
+ * This is called by the chunk chopper before any of the chunk's
+ * subchunks are loaded. Any data loaded that may need to be
+ * used later by superchunks should be stored in
+ * the chunk chopper via {@link ChunkChopper#pushData}
+ *
+ * @param chopper used to store the position of the light.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ currentPosition = chopper.getVector();
+ TransformGroup group = chopper.getGroup();
+ Transform3D transform = new Transform3D();
+ group.getTransform(transform);
+ transform.setTranslation(currentPosition);
+ group.setTransform(transform);
+ chopper.pushData(chopper.getID(), currentPosition);
+ }
+
+ /**
+ * Gets the data put into the chopper by the subchunks
+ * and creates a light, adding it to the scene as a named object.
+ * @param chopper the ChunkChopper containing sub chunk data.
+ */
+ public void initialize(ChunkChopper chopper)
+ {
+ Color3f color = (Color3f)chopper.popData(ChunkMap.COLOR);
+ PointLight light = (PointLight)chopper.popData(ChunkMap.SPOTLIGHT);
+ if(light == null)
+ {
+ light = new PointLight();
+ chopper.addLightNode(light);
+ }
+
+ light.setColor(color);
+ light.setInfluencingBounds(new BoundingSphere(new Point3d(0,0,0), 3000));
+ chopper.getGroup().addChild(light);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/MaterialChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/MaterialChunk.java
new file mode 100644
index 0000000..e22c161
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/MaterialChunk.java
@@ -0,0 +1,121 @@
+/**
+ * Make a donation http://sourceforge.net/donate/index.php?group_id=98797
+ * Microcrowd
+ *
+ * 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.chunks;
+
+import javax.media.j3d.Appearance;
+import javax.media.j3d.Material;
+import javax.media.j3d.PolygonAttributes;
+import javax.media.j3d.Texture;
+import javax.media.j3d.TransparencyAttributes;
+import javax.vecmath.Color3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+import com.microcrowd.loader.java3d.max3ds.ChunkMap;
+
+
+
+/**
+ * Loads material chunks with ambient, diffuse and specular colors,
+ * shininess, transparency, two sidedness and texture.
+ */
+public class MaterialChunk extends Chunk
+{
+
+ //public static final Integer SELF_ILLUMINATED = new Integer((short)0xA084);
+
+
+ /**
+ * This will set the ambient, diffuse and specular
+ * colors as well as the textures, two sidedness
+ * and transparency of the material.
+ *
+ * @param chopper the chopper containing the data
+ * needed to set the attributes.
+ */
+ public void initialize(ChunkChopper chopper)
+ {
+ Appearance appearance = new Appearance();
+ Material material = new Material();
+
+ Color3f ambientColor = (Color3f)chopper.popData(ChunkMap.AMBIENT_COLOR);
+ if (ambientColor != null) {
+ material.setAmbientColor(ambientColor);
+ }
+
+ Color3f color = (Color3f)chopper.popData(ChunkMap.DIFFUSE_COLOR);
+ if (color != null) {
+ material.setDiffuseColor(color);
+ }
+
+ color = (Color3f)chopper.popData(ChunkMap.SPECULAR_COLOR);
+ if (color != null) {
+ material.setSpecularColor(color);
+ }
+
+ Texture texture = (Texture)chopper.popData(ChunkMap.TEXTURE);
+ if(texture != null)
+ {
+ appearance.setTexture(texture);
+ }
+
+ Boolean twoSided = (Boolean)chopper.popData(ChunkMap.TWO_SIDED);
+ if (twoSided != null) //Just being there is equivalent to a boolean true.
+ {
+
+ PolygonAttributes polyAttributes = appearance.getPolygonAttributes();
+ if(polyAttributes == null)
+ {
+ polyAttributes = new PolygonAttributes();
+ }
+
+ polyAttributes.setCullFace(PolygonAttributes.CULL_NONE);
+ appearance.setPolygonAttributes(polyAttributes);
+ }
+
+ Float transparency = (Float)chopper.popData(ChunkMap.TRANSPARENCY);
+ if (transparency != null) {
+ if (transparency.floatValue() > 0.01f) {
+
+ TransparencyAttributes transparencyAttributes = new TransparencyAttributes(TransparencyAttributes.FASTEST, transparency.floatValue());
+ appearance.setTransparencyAttributes(transparencyAttributes);
+ }
+ }
+
+ String name = (String)chopper.popData(ChunkMap.MATERIAL_NAME);
+ Float shininess = (Float)chopper.popData(ChunkMap.SHININESS);
+ if (shininess != null)
+ {
+ float shine = shininess.floatValue() * 1024f;
+ material.setShininess(shine);
+ }
+
+ /*
+ Boolean illuminated = (Boolean)chopper.popData(SELF_ILLUMINATED);
+ if(illuminated != null && illuminated.booleanValue() == true)
+ {
+ material.setEmissiveColor(ambientColor);
+ }
+ */
+
+ appearance.setMaterial(material);
+ chopper.setNamedObject(name, appearance);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/NamedObjectChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/NamedObjectChunk.java
new file mode 100644
index 0000000..ee063a9
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/NamedObjectChunk.java
@@ -0,0 +1,50 @@
+/**
+ * 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.chunks;
+
+import javax.media.j3d.TransformGroup;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * Loads information about a named object: Cameras, meshes and lights
+ */
+public class NamedObjectChunk extends Chunk
+{
+
+ /**
+ * Adds a TransformGroup the the chopper's branch
+ * group to which meshes will be added.
+ *
+ * @param chopper The chopper containing the state of parsing.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ final String name = chopper.getString();
+ TransformGroup transformGroup = new TransformGroup();
+
+ transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
+ transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
+ transformGroup.setCapability(TransformGroup.ENABLE_PICK_REPORTING);
+
+ chopper.addObject(name, transformGroup);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/PercentageChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/PercentageChunk.java
new file mode 100644
index 0000000..9036aff
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/PercentageChunk.java
@@ -0,0 +1,59 @@
+/**
+ * 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.chunks;
+
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * Loads percentage values from binary data representing them.
+ */
+public class PercentageChunk extends Chunk
+{
+ /** Represents an int percentage */
+ public static final int INT = 0x30;
+
+ /** Represents a float percentage */
+ public static final int FLOAT = 0x31;
+ private float percentage;
+
+ /**
+ * Gets tye type of percentage, reads it
+ * and sets the value on the chopper using
+ * the id of the current chunk as the key.
+ *
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ int percentageType = chopper.getUnsignedShort();
+ int percentageLength = chopper.getUnsignedInt();
+ if (percentageType == INT) {
+ percentage = (chopper.getUnsignedShort()) / 100f;
+ chopper.pushData(chopper.getID(), new Float(percentage));
+ } else if (percentageType == FLOAT) {
+ percentage = chopper.getFloat() / 100f;
+ chopper.pushData(chopper.getID(), new Float(percentage));
+ } else {
+ throw new IllegalArgumentException("Only float and int percentages are enabled.");
+ }
+
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/PivotChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/PivotChunk.java
new file mode 100644
index 0000000..f9631b1
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/PivotChunk.java
@@ -0,0 +1,45 @@
+/**
+ * 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.chunks;
+
+import javax.vecmath.Point3f;
+import javax.vecmath.Vector3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+/**
+ * Loads the pivot for a mesh.
+ * {@see KeyFramerInfoChunk} for more information about using
+ * animations from a 3ds file
+ */
+public class PivotChunk extends Chunk
+{
+ /**
+ * Gets the pivot and associates it with the current mes.
+ * @param chopper the ChunkChopper containing the state of the parser.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ Vector3f pivot = new Vector3f((Point3f)chopper.getPoint());
+
+ chopper.getKeyFramer().setPivot(pivot);
+ }
+
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/PositionChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/PositionChunk.java
new file mode 100644
index 0000000..52eea84
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/PositionChunk.java
@@ -0,0 +1,63 @@
+/**
+ * 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.chunks;
+
+import java.util.ArrayList;
+import javax.vecmath.Point3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * Loads the position of a mesh as defined in the 3ds file.
+ * This position may need to be converted to another coordinate
+ * system by KeyFramerInfoChunk.
+ * * {@see KeyFramerInfoChunk} for more information about using
+ * animations from a 3ds file
+ */
+public class PositionChunk extends Chunk
+{
+ /**
+ * Loads the position for a shape and KeyFramerInfoChunk
+ *
+ * @param chopper the ChunkChopper containing the state of the parser.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ int flags = chopper.getUnsignedShort();
+ chopper.getLong();
+ int numKeys = chopper.getUnsignedInt();
+
+ ArrayList pointList = new ArrayList();
+ for(int i =0; i < numKeys; i++)
+ {
+ long keyNumber = chopper.getUnsignedInt();
+ int accelerationData = chopper.getUnsignedShort();
+
+ Point3f position = chopper.getPoint();
+ if(i==0)
+ {
+ chopper.getKeyFramer().setPosition(position);
+ }
+ pointList.add(position);
+ }
+ chopper.getKeyFramer().setPositionKeys(pointList);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/RotationChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/RotationChunk.java
new file mode 100644
index 0000000..8f4f2c0
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/RotationChunk.java
@@ -0,0 +1,129 @@
+/*8
+ * 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.chunks;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.vecmath.Quat4f;
+import javax.vecmath.Vector3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * Extracts the rotation information from the 3ds file.
+ * Rotations occur about a pivot at a position within
+ * a local coordinate system. The rotation information
+ * is provided to the KeyFramerInfoChunk which then converts
+ * it to a global coordinate system and applies animation
+ * information.
+ * {@see KeyFramerInfoChunk} for more information about using
+ * animations from a 3ds file
+ */
+public class RotationChunk extends Chunk
+{
+ /**
+ * String that will be used as a data object in the transform that the
+ * RotationInterpolator will be a child of so it may be look up later.
+ **/
+ public static String ROTATION_TAG = "ROTATION_INTERPOLATOR";
+
+ /**
+ * Loads the quaternion for a rotation of a shape
+ * and notifies mesh info chunk.
+ *
+ * @param chopper the ChunkChopper containing the state of the parser.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ int flags = chopper.getUnsignedShort();
+ chopper.getLong();
+ int numKeys = chopper.getUnsignedInt();
+
+ Quat4f previousQuat = null;
+
+ List quats = new ArrayList();
+ for(int i =0; i < numKeys; i++)
+ {
+ long frameNumber = chopper.getUnsignedInt();//Part of the track header
+ int accelerationData = chopper.getUnsignedShort();//Part of the track header
+ getSplineTerms(accelerationData, chopper);//Part of the track header
+
+ float angle = chopper.getFloat();
+ Vector3f vector = chopper.getVector();
+
+ Quat4f quat = getQuaternion(vector, angle);
+ if(previousQuat != null) {
+ quat.mul(previousQuat, quat);
+ }
+ previousQuat = quat;
+
+ quats.add(quat);
+ if(i==0)
+ {
+ chopper.getKeyFramer().setRotation(quat);
+ }
+ }
+ chopper.getKeyFramer().setOrientationKeys(quats);
+ }
+
+ /**
+ * This only reads the spline data and should be part
+ * of the track header when it gets invented.
+ * @param chopper an integer representing the bits that
+ * determine which of the five possible spline terms are present in the
+ * data and should be read.
+ * @param chopper what to read the data from
+ * The possible spline values are are
+ * <ol>
+ * <li> Tension
+ * <li> Continuity
+ * <li> Bias
+ * <li> EaseTo
+ * <li> EaseFrom
+ * </ol>
+ */
+ private void getSplineTerms(final int accelerationData, ChunkChopper chopper)
+ {
+ int bits = accelerationData;
+ for(int i=0; i < 5; i++)
+ {
+ bits = bits >>> i;
+ if((bits & 1) == 1)
+ {
+ chopper.getFloat();
+ }
+ }
+ }
+
+ /**
+ * This converts a 3ds angle and axis to
+ * a quaternion rotation. Successive
+ * rotations are relative to the first so each
+ * rotation must be made absolute by multiplying
+ * it with its predecessor
+ */
+ public Quat4f getQuaternion(Vector3f axis, float angle)
+ {
+ float sinA = (float)(java.lang.Math.sin(angle/2.0f));
+ float cosA = (float)(java.lang.Math.cos(angle/2.0f));
+ return new Quat4f(axis.x * sinA, axis.y * sinA, axis.z * sinA, cosA);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/ScaleChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/ScaleChunk.java
new file mode 100644
index 0000000..30fb564
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/ScaleChunk.java
@@ -0,0 +1,67 @@
+/**
+ * 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.chunks;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.vecmath.Vector3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * Extracts scale information from the 3ds file which
+ * is then used by the mesh info chunk to construct a
+ * animation.
+ */
+public class ScaleChunk extends Chunk
+{
+ /**
+ * Loads the scale for a shape
+ * and notifies the KeyFramerInfoChunk
+ *
+ * @param chopper the ChunkChopper containing the state of the parser.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ int flags = chopper.getUnsignedShort();
+ chopper.getLong();
+ int numKeys = chopper.getUnsignedInt();
+
+ List scaleKeys = new ArrayList();
+
+ for(int i =0; i < numKeys; i++)
+ {
+ long keyNumber = chopper.getUnsignedInt();
+ int accelerationData = chopper.getUnsignedShort();
+
+ float scaleX = chopper.getFloat();
+ float scaleZ = chopper.getFloat();
+ float scaleY = chopper.getFloat();
+ Vector3f scale = new Vector3f(scaleX, scaleY, scaleZ);
+ if(i==0)
+ {
+ chopper.getKeyFramer().setScale(scale);
+ }
+ scaleKeys.add(scale);
+ }
+ chopper.getKeyFramer().setScaleKeys(scaleKeys);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/SmoothingChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/SmoothingChunk.java
new file mode 100644
index 0000000..ae92155
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/SmoothingChunk.java
@@ -0,0 +1,65 @@
+/**
+ * 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.chunks;
+
+import javax.vecmath.Point3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+import com.microcrowd.loader.java3d.max3ds.ChunkMap;
+
+/**
+ * This chunk is used to generate normals for a mesh according
+ * to the data in the smoothing groups chunk.
+ * Vertices that share coordinates will all use the same, averaged
+ * normal if they also belong to the same smoothing groups.
+ * @author jdeford
+ */
+public class SmoothingChunk extends Chunk
+{
+ /**
+ * Loads the vertices smoothing groups for
+ * a mesh and stores it in chopper
+ *
+ * @param chopper the ChunkChopper containing the state of the parser.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ Point3f[] vertices = (Point3f[])chopper.popData(ChunkMap.FACES_DESCRIPTION);
+ int[] smoothGroups = new int[vertices.length];
+ int numFaces = vertices.length/3;
+ for(int i=0; i < numFaces; i++)
+ {
+ int groupMask = chopper.getInt();
+ smoothGroups[i*3]=groupMask;
+ smoothGroups[(i*3)+1]=groupMask;
+ smoothGroups[(i*3)+2]=groupMask;
+
+ java.util.ArrayList list = new java.util.ArrayList();
+ for(int j=0; j < 32; j++)
+ {
+ if(((0x1l << j) & groupMask) > 0)
+ {
+ list.add(new Integer(j));
+ }
+ }
+ }
+ chopper.pushData(chopper.getID(), smoothGroups);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/SpotLightChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/SpotLightChunk.java
new file mode 100644
index 0000000..875da30
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/SpotLightChunk.java
@@ -0,0 +1,73 @@
+/**
+ * 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.chunks;
+
+import javax.media.j3d.SpotLight;
+import javax.media.j3d.Transform3D;
+import javax.media.j3d.TransformGroup;
+import javax.vecmath.Point3d;
+import javax.vecmath.Point3f;
+import javax.vecmath.Vector3d;
+import javax.vecmath.Vector3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+import com.microcrowd.loader.java3d.max3ds.ChunkMap;
+
+/**
+ * SpotLights to be placed in a scene.
+ *
+ * All the default parameters other than
+ * position and direction are used and
+ * not loaded from the 3ds file.
+ */
+public class SpotLightChunk extends Chunk
+{
+
+
+ /**
+ * This is called by the chunk chopper before any of the chunk's
+ * subchunks are loaded. Any data loaded that may need to be
+ * used later by superchunks should be stored in
+ * the chunk chopper via {@link ChunkChopper#popData}
+ *
+ * @param chopper the ChunkChopper that will have the light placed in it.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ Point3f target = chopper.getPoint();
+ float beam = chopper.getFloat();
+ float falloff = chopper.getFloat();
+ SpotLight light = new SpotLight();
+
+ Vector3f direction = new Vector3f(0,0,-1);
+
+ Vector3f position = (Vector3f)chopper.popData(ChunkMap.LIGHT);
+ TransformGroup group = chopper.getGroup();
+ Transform3D transform = new Transform3D();
+ group.getTransform(transform);
+ transform.lookAt(new Point3d(position), new Point3d(target), new Vector3d(0,1,0));
+ transform.invert();
+ transform.setTranslation(position);
+ group.setTransform(transform);
+
+ chopper.pushData(chopper.getID(), light);
+ chopper.addLightNode(light);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/StringChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/StringChunk.java
new file mode 100644
index 0000000..b9eb55e
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/StringChunk.java
@@ -0,0 +1,52 @@
+/**
+ * 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.chunks;
+
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * These have no subchunks. Only String data terminated with a null. For
+ * strings with unknown length use {@link ChunkChopper#getString} This can
+ * also be used for chunks that have data of a known length beginning with a
+ * string with unnessecary(you don't want to use it) data following.
+ */
+public class StringChunk extends Chunk
+{
+ /**
+ * Reads in all the data for this chunk and makes a string out of it.
+ * This will set the data in the chopper with a key of this chunks id.
+ *
+ *
+ * @param chopper the chopper that is doing the parsing.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ byte[] stringArray = chopper.getChunkBytes();
+
+ String value = new String(stringArray, 0, stringArray.length - 1);
+ if (value.indexOf((char)(0x0000)) > 0) {
+ value = value.substring(0, value.indexOf((char)(0x0000)));
+ }
+
+ chopper.pushData(chopper.getID(), value);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/TextureChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/TextureChunk.java
new file mode 100644
index 0000000..ebbb655
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/TextureChunk.java
@@ -0,0 +1,47 @@
+/**
+ * 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.chunks;
+
+
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+import com.microcrowd.loader.java3d.max3ds.ChunkMap;
+
+
+/**
+ * Loads percentage values from binary data representing them.
+ */
+public class TextureChunk extends Chunk
+{
+
+ /**
+ * Gets the current texture image from the chopper
+ * creates a texture with it and sets that texture
+ * on the chopper.
+ *
+ * @param chopper the parser containing the state of parsing
+ */
+ public void initialize(ChunkChopper chopper)
+ {
+ String textureName = (String)chopper.popData(ChunkMap.TEXTURE_NAME);
+ chopper.pushData(ChunkMap.TEXTURE, chopper.createTexture(textureName));
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/Vertex2ListChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/Vertex2ListChunk.java
new file mode 100644
index 0000000..7a8ed15
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/Vertex2ListChunk.java
@@ -0,0 +1,55 @@
+/**
+ * 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.chunks;
+
+import javax.vecmath.TexCoord2f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * Reads a list of x,y points that will be used
+ * later for texture mapping.
+ *
+ * @author jdeford
+ */
+public class Vertex2ListChunk extends Chunk
+{
+ private static final int POINT_2F_SIZE = 8;
+
+ /**
+ * Reads all the point data from the chopper and stores
+ * teh points in the chopper.
+ *
+ * @param chopper the chopper that will parse and store
+ * the data using this chunks id as the key.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ int numVertices = chopper.getUnsignedShort();
+ TexCoord2f[] points = new TexCoord2f[numVertices];
+ for (int i = 0; i < numVertices; i++) {
+ float point0 = chopper.getFloat();
+ float point1 = chopper.getFloat();
+ points[i] = new TexCoord2f(point0, point1);
+ }
+ chopper.pushData(chopper.getID(), points);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/chunks/Vertex3ListChunk.java b/com/microcrowd/loader/java3d/max3ds/chunks/Vertex3ListChunk.java
new file mode 100644
index 0000000..be5ae4e
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/chunks/Vertex3ListChunk.java
@@ -0,0 +1,54 @@
+/**
+ * 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.chunks;
+
+import javax.vecmath.Point3f;
+import com.microcrowd.loader.java3d.max3ds.ChunkChopper;
+
+/**
+ * Reads and store x,y,z vertex coordinates.
+ * The coordinates will be accessed with indexes to construct
+ * the mesh out of triangles.
+ * @author jdeford
+ */
+public class Vertex3ListChunk extends Chunk
+{
+ private static final int POINT_3F_SIZE = 12;
+
+ /**
+ * Reads all the point data from the chopper
+ * and stores it using this chunk's id as the key.
+ *
+ * @param chopper the chopper that will read and
+ * store the data.
+ */
+ public void loadData(ChunkChopper chopper)
+ {
+ int numVertices = chopper.getUnsignedShort();
+ Point3f[] points = new Point3f[numVertices];
+ for (int i = 0; i < numVertices; i++) {
+ points[i] = new Point3f(chopper.getPoint());
+ }
+
+ chopper.pushData(chopper.getID(), points);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/data/KeyFramer.java b/com/microcrowd/loader/java3d/max3ds/data/KeyFramer.java
new file mode 100644
index 0000000..d98d830
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/data/KeyFramer.java
@@ -0,0 +1,526 @@
+/**
+ * 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.data;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import javax.media.j3d.Alpha;
+import javax.media.j3d.Behavior;
+import javax.media.j3d.Group;
+import javax.media.j3d.Node;
+import javax.media.j3d.RotPosPathInterpolator;
+import javax.media.j3d.Transform3D;
+import javax.media.j3d.TransformGroup;
+import javax.media.j3d.TransformInterpolator;
+import javax.vecmath.Matrix4f;
+import javax.vecmath.Point3f;
+import javax.vecmath.Quat4f;
+import javax.vecmath.Vector3d;
+import javax.vecmath.Vector3f;
+
+/**
+ * @author Josh DeFord
+ */
+public class KeyFramer
+{
+ private HashMap lastGroupMap = new HashMap();
+ private HashMap fatherMap = new HashMap();
+
+ private Quat4f rotation;
+ private Point3f position;
+ private Point3f pivotCenter;
+ private Vector3f pivot;
+ private Vector3f scale;
+ private HashMap namedObjectCoordinateSystems = new HashMap();
+
+ private List positionKeys;
+ private List orientationKeys;
+ private List scaleKeys;
+
+ private Integer id;
+ private Group father;
+ private Group dummyObject;
+
+
+ /**
+ * Retrieves the named object for the current key framer
+ * inserts the rotation, position and pivot transformations for frame 0
+ * and assigns the coordinate system to it.
+ *
+ * The inverse of the local coordinate system converts from 3ds
+ * semi-absolute coordinates (what is in the file) to local coordinates.
+ *
+ * Then these local coordinates are converted with matrix
+ * that will instantiate them to absolute coordinates:
+ * Xabs = sx a1 (Xl-Px) + sy a2 (Yl-Py) + sz a3 (Zl-Pz) + Tx
+ * Yabs = sx b1 (Xl-Px) + sy b2 (Yl-Py) + sz b3 (Zl-Pz) + Ty
+ * Zabs = sx c1 (Xl-Px) + sy c2 (Yl-Py) + sz c3 (Zl-Pz) + Tz
+ * Where:
+ * (Xabs,Yabs,Zabs) = absolute coordinate
+ * (Px,Py,Pz) = mesh pivot (constant)
+ * (X1,Y1,Z1) = local coordinates
+ *
+ */
+ public Behavior createBehavior(String meshName, Group transformGroup, Object testObject)
+ {
+ Group objectGroup = getObjectByName(meshName, transformGroup, testObject);
+ //System.out.println("mesh " + meshName + " scale " + scale);
+ if(objectGroup == null)
+ return null;
+
+ insertFather(objectGroup, meshName);
+
+ TransformInterpolator behavior = null;
+ Transform3D coordinateSystem = (Transform3D)namedObjectCoordinateSystems.get(meshName);
+
+ //Gonna put these children back later.
+ Enumeration children = removeChildren(objectGroup);
+
+ Transform3D coordinateTransform = coordinateSystem == null ? new Transform3D() : new Transform3D(coordinateSystem);
+
+ Transform3D targetTransform = new Transform3D();
+ TransformGroup targetGroup = new TransformGroup(targetTransform);
+
+ TransformGroup localCoordinates = hasKeys() ? buildLocalCoordinates(coordinateSystem) : new TransformGroup();
+ TransformGroup lastGroup = (TransformGroup)addGroups(objectGroup, new Group[]
+ {
+ localCoordinates,
+ targetGroup,
+ buildPivotGroup(coordinateTransform, pivot),
+ buildKeysGroup(),
+ });
+
+ addChildren(children, lastGroup);
+ lastGroupMap.put(objectGroup, lastGroup);
+
+
+ behavior = buildInterpolator(targetGroup, coordinateSystem);
+ if(behavior != null)
+ {
+ behavior.setEnable(false);
+ targetGroup.addChild(behavior);
+
+ behavior.computeTransform(0f, targetTransform);
+ targetGroup.setTransform(targetTransform);
+ }
+ return behavior;
+ }
+
+ private Enumeration removeChildren(Group group)
+ {
+ Enumeration children = group.getAllChildren();
+ group.removeAllChildren();
+ return children;
+ }
+
+ private void addChildren(Enumeration children, Group group)
+ {
+ if(group == null)
+ return;
+ while(children.hasMoreElements())
+ {
+ Node node = (Node)(children.nextElement());
+ group.addChild(node);
+ }
+ }
+
+ /**
+ * Looks up the current object.
+ * objectGroup is returned if it is the right one to return
+ * otherwise a new dummy object may be returned.
+ * If it isn't there it gets the dummy object
+ * from the frames description chunk.
+ */
+ private Group getObjectByName(String objectName, Group objectGroup, Object testObject)
+ {
+
+ //This means its a dummy object. It needs to be created.
+ if(objectGroup == null && testObject == null)
+ {
+ namedObjectCoordinateSystems.put(objectName, new Transform3D());
+ objectGroup = dummyObject;
+ }
+
+ return objectGroup;
+ }
+
+ /**
+ * Locates the father for the object named objectName and inserts
+ * its transform cluster between the parent and all
+ * the parent's children. This only occurs in a hierarchical
+ * model. like bones and stuff. The fatherGroup, if found,
+ * is removed from whatever parent belonged to on before insertion.
+ */
+ private void insertFather(Group parentGroup, String objectName)
+ {
+ if(father == null)
+ return;
+ Group topGroup = new TransformGroup();
+ topGroup.addChild(father);
+ Group bottomGroup = (Group)lastGroupMap.get(father);
+
+ if(topGroup == null)
+ return;
+
+ Group fatherParent = (Group)topGroup.getParent();
+ if(fatherParent != null)
+ fatherParent.removeChild(topGroup);
+
+ Enumeration originalChildren = removeChildren(parentGroup);
+ parentGroup.addChild(topGroup);
+ addChildren(originalChildren, bottomGroup);
+ }
+
+ /**
+ * Builds a transform group from the zeroth key of the
+ * position and rotation tracks.
+ * @return transform group with position and rotation information
+ */
+ private TransformGroup buildKeysGroup()
+ {
+ Transform3D positionTransform = new Transform3D();
+ positionTransform.set(new Vector3f(position));
+
+ Transform3D rotationTransform = new Transform3D();
+ rotationTransform.set(rotation);
+
+ Transform3D scaleTransform = new Transform3D();
+ scaleTransform.setScale(new Vector3d(scale));
+ TransformGroup scaleGroup = new TransformGroup(scaleTransform);
+
+ Transform3D keyTransform = new Transform3D(positionTransform);
+ keyTransform.mul(scaleTransform);
+ keyTransform.mul(rotationTransform);
+ return new TransformGroup(keyTransform);
+ }
+
+ /**
+ * Builds a pivot group that will allow the objects
+ * to be positioned properly according to their rotations
+ * and positions.
+ * @param coordinateTransform the coordinate system defining the
+ * location and orientation of the local axis. This is not modified.
+ * @param pivot the pivot defined in the 3ds file loaded by pivot chunk.
+ * This is not changed.
+ */
+ private TransformGroup buildPivotGroup(Transform3D coordinateTransform, Vector3f pivot)
+ {
+ Transform3D pivotTransform = new Transform3D();
+ pivotTransform.mulInverse(coordinateTransform);
+ pivot = new Vector3f(pivot);
+ pivot.negate();
+ translatePivot(pivotTransform, pivot, pivotCenter);
+ return new TransformGroup(pivotTransform);
+ }
+
+ /**
+ * Builds a coordinate group that will allow the objects
+ * to be positioned properly according to their rotations
+ * and positions.
+ * @param coordinateSystem the coordinate system defining the
+ * location and orientation of the local axis. This is modified
+ * so it will be useful during the construction
+ * of the animations.
+ */
+ private TransformGroup buildLocalCoordinates(Transform3D coordinateSystem)
+ {
+ Matrix4f coordMatrix = new Matrix4f();
+ Vector3f translation = new Vector3f();
+
+ coordinateSystem.get(translation);
+ coordinateSystem.invert();
+
+ coordinateSystem.get(coordMatrix);
+ coordMatrix.m03 = translation.x;
+ coordMatrix.m13 = translation.y;
+ coordMatrix.m23 = translation.z;
+ coordinateSystem.set(coordMatrix);
+ coordinateSystem.invert();
+ TransformGroup systemGroup = new TransformGroup(coordinateSystem);
+ coordinateSystem.invert();
+ return systemGroup;
+ }
+
+ /**
+ * Hierarchically adds the provided groups in order to parentGroup.
+ * groups[0] is added to parentGroup, groups[1] is added to groups[0] etc.
+ * @return the last group added (groups[groups.length - 1]).
+ */
+ private Group addGroups(Group parentGroup, Group[] groups)
+ {
+ Group nextGroup = parentGroup;
+ for(int i=0; i < groups.length; i++)
+ {
+ nextGroup.addChild(groups[i]);
+ nextGroup = groups[i];
+ }
+ return groups[groups.length - 1];
+ }
+
+ /**
+ * Does a pre rotational translation of the pivot.
+ * @param transform the matrix that will have a translation concatenated to it.
+ * @param vector the vector which will be used to translate the matrix.
+ * @param offset the offset used to offset the pivot.
+ */
+ private void translatePivot(Transform3D transform, Vector3f vector, Point3f offset)
+ {
+ if(offset != null)
+ {
+ pivot.sub(offset);
+ }
+ Matrix4f matrix = new Matrix4f();
+ transform.get(matrix);
+
+ matrix.m03 += (matrix.m00*vector.x + matrix.m01*vector.y + matrix.m02*vector.z);
+ matrix.m13 += (matrix.m10*vector.x + matrix.m11*vector.y + matrix.m12*vector.z);
+ matrix.m23 += (matrix.m20*vector.x + matrix.m21*vector.y + matrix.m22*vector.z);
+
+ transform.set(matrix);
+ }
+
+
+ /**
+ * Builds a rotation position interpolator for use on this mesh using position and rotation information
+ * adds it to targetGroup.
+ * This does not set the capability bits that need to be set for the animation
+ * to be used. The capability bits of the targetGroup must be set by the client application.
+ * The alpha object on the Interpolator must also be enabled.
+ * The Interpolator must also have its scheduling bounds set.
+ * @param pivotGroup transform group which will be operated on by the interpolator.
+ * @param interpolatorAxis the axis that about which rotations will be centered.
+ */
+ //TODO... This needs to use both a rotation interpolator and a position interpolator
+ //in case there are keys with no position information but position information and
+ //vice versa right now its using RotPosPathInterpolator
+ private TransformInterpolator buildInterpolator(TransformGroup targetGroup, Transform3D axisOfTransform)
+ {
+ makeTwoListsTheSameSize(positionKeys, orientationKeys);
+ int numKeys = positionKeys.size();
+
+ Point3f currentPoint = position;
+ Quat4f currentQuat = rotation;
+ RotPosPathInterpolator rotator = null;
+ if(numKeys > 1)
+ {
+ float[] knots = new float[numKeys];
+ Point3f[] points = new Point3f[numKeys];
+ Quat4f[] quats = new Quat4f[numKeys];
+
+ for(int i=0; i < numKeys; i++)
+ {
+ //Knots need to be between 0(beginning) and 1(end)
+ knots[i]= (i==0?0:((float)i/((float)(numKeys-1))));
+ if(positionKeys.size() > i)
+ {
+ Point3f newPoint = (Point3f)positionKeys.get(i);
+ if(newPoint != null)
+ {
+ currentPoint = newPoint;
+ }
+
+ Quat4f newQuat = (Quat4f)orientationKeys.get(i);
+ if(newQuat != null)
+ {
+ currentQuat = newQuat;
+ }
+ }
+
+ points[i] = currentPoint;
+ quats[i] = currentQuat;
+ quats[i].inverse();
+ }
+
+ //This gives a continuous loop at a rate of 30 fps
+ Alpha alpha = new Alpha(-1, (long)(numKeys/.03));
+ alpha.setStartTime(System.currentTimeMillis());
+ alpha.setDuplicateOnCloneTree(true);
+
+ rotator = new RotPosPathInterpolator(alpha, targetGroup,
+ axisOfTransform, knots,
+ quats, points);
+ }
+ return rotator;
+ }
+
+ public void makeTwoListsTheSameSize(List list1, List list2)
+ {
+ growList(list2.size() - 1, list1);
+ growList(list1.size() - 1, list2);
+ }
+
+ /**
+ * Make sure the list is at least able to
+ * hold a value at index.
+ * @param index an int specifying the initial size
+ * @parame the list that may need to grow
+ */
+ public void growList(int index, List list)
+ {
+ int numNeeded = (index + 1) - list.size();
+ while(numNeeded-- > 0)
+ {
+ list.add(null);
+ }
+ }
+
+ /**
+ * Sets the center of the bounding box that the pivot
+ * should offset.
+ */
+ public void setPivotCenter(Point3f center)
+ {
+ this.pivotCenter = center;
+ }
+
+ /**
+ * Called to set the coordinate system transform for an object named
+ * objectName.
+ * This is the first t
+ */
+ public void setCoordinateSystem(String objectName, Transform3D coordinateSystem)
+ {
+ namedObjectCoordinateSystems.put(objectName, coordinateSystem);
+ }
+
+ /**
+ * Sets the group that will be used to center rotations.
+ * This is applied to the mesh after all other transforms
+ * have been applied.
+ * @param group the group that will act as the rotation transform.
+ */
+ public void setRotation(Quat4f rotation)
+ {
+ this.rotation = rotation;
+ }
+
+ /**
+ * Sets the pivot that will be used to as a pivot for
+ * these transfomations.
+ * @param group the group that will act as the pivot.
+ */
+ public void setPivot(Vector3f pivot)
+ {
+ this.pivot = pivot;
+ }
+
+ /**
+ * Sets the scale for x y and z axis for objects.
+ * This is applied to the mesh before the rotation transform
+ * has been applied.
+ * @param group the group that will act as the scale
+ */
+ public void setScale(Vector3f scale)
+ {
+ this.scale = scale;
+ }
+
+ /**
+ * Sets the scale information necessary for animation.s
+ * @param scaleKeys a list of Vector3f, which may contain null elements,
+ * containing a position for some keys.
+ */
+ public void setScaleKeys(List scaleKeys)
+ {
+ this.scaleKeys = scaleKeys;
+ }
+
+ /**
+ * Sets the group that will be used to translate the mesh..
+ * This is applied to the mesh just before the rotation transform
+ * has been applied.
+ * @param group the group that will act as the position transform.
+ */
+ public void setPosition(Point3f position)
+ {
+ this.position = position;
+ }
+
+ /**
+ * Sets the position information necessary for animation.s
+ * @param positions a list of Point3f, which may contain null elements,
+ * containing a position for some keys.
+ */
+ public void setPositionKeys(List positions)
+ {
+ positionKeys = positions;
+ }
+
+ /**
+ * Sets the orientation information necessary for animation.s
+ * @param positions a list of Quat4f, which may contain null elements,
+ * containing a orientation for some keys.
+ */
+ public void setOrientationKeys(List orientations)
+ {
+ orientationKeys = orientations;
+ }
+
+ /**
+ *
+ */
+ public void setDummyObject(Group object)
+ {
+ dummyObject = object;
+ }
+
+ /**
+ * returns true if position keys and orientation
+ * keys are longer than one element each.
+ */
+ public boolean hasKeys()
+ {
+ return (positionKeys.size() > 1 || orientationKeys.size() > 1);
+ }
+
+ /**
+ */
+ public void addFather(int fatherID, TransformGroup newFather)
+ {
+ if(fatherID < 0)
+ {
+ father = null;
+ }
+ else
+ {
+ father = (TransformGroup)(fatherMap.get(new Integer(fatherID)));
+ //Remove the father's father because the father will
+ //be inserted somewhere later.
+ Group grandFather = (Group)father.getParent();
+ if(grandFather != null)
+ {
+ grandFather.removeChild(father);
+ }
+ }
+ fatherMap.put(id, newFather);
+ }
+
+ /**
+ * Sets the id for these frames.
+ * @param id the id for these frames.
+ */
+ public void setID(int id)
+ {
+ this.id = new Integer(id);
+ }
+}
diff --git a/com/microcrowd/loader/java3d/max3ds/package.html b/com/microcrowd/loader/java3d/max3ds/package.html
new file mode 100644
index 0000000..7cc16ac
--- /dev/null
+++ b/com/microcrowd/loader/java3d/max3ds/package.html
@@ -0,0 +1,3 @@
+<html><body>
+ Contains classes used to load 3d studio max files.
+</body></html>
diff --git a/com/realvue/sim/ui/loader/java3d/max3ds/Loader3DS.java b/com/realvue/sim/ui/loader/java3d/max3ds/Loader3DS.java
new file mode 100644
index 0000000..f166d50
--- /dev/null
+++ b/com/realvue/sim/ui/loader/java3d/max3ds/Loader3DS.java
@@ -0,0 +1,34 @@
+/*
+ * 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.realvue.sim.ui.loader.java3d.max3ds;
+
+
+/**
+ * @author jdeford
+ *
+ * Fonzie makes the windmill go round.
+ */
+public class Loader3DS
+{
+ static
+ {
+ System.err.println("com.realvue.sim.ui.loader.java3d.max3ds.Loader has been replaced by com.microcrowd.loader.java3d.max3ds.Loader3DS. Just change the package and it will work.");
+ }
+}
--
Gitblit v1.6.2