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