0001: /*
0002: * $RCSfile: Controller.java,v $
0003: *
0004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: *
0010: * - Redistribution of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: *
0013: * - Redistribution in binary form must reproduce the above copyright
0014: * notice, this list of conditions and the following disclaimer in
0015: * the documentation and/or other materials provided with the
0016: * distribution.
0017: *
0018: * Neither the name of Sun Microsystems, Inc. or the names of
0019: * contributors may be used to endorse or promote products derived
0020: * from this software without specific prior written permission.
0021: *
0022: * This software is provided "AS IS," without a warranty of any
0023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
0024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
0025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
0026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
0027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
0028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
0029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
0030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
0031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
0032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
0033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
0034: * POSSIBILITY OF SUCH DAMAGES.
0035: *
0036: * You acknowledge that this software is not designed, licensed or
0037: * intended for use in the design, construction, operation or
0038: * maintenance of any nuclear facility.
0039: *
0040: * $Revision: 1.10 $
0041: * $Date: 2007/11/14 12:51:38 $
0042: * $State: Exp $
0043: */
0044:
0045: package com.sun.j3d.utils.scenegraph.io.retained;
0046:
0047: import java.io.ByteArrayInputStream;
0048: import java.io.ByteArrayOutputStream;
0049: import java.io.DataInput;
0050: import java.io.DataOutput;
0051: import java.io.IOException;
0052: import java.io.ObjectInputStream;
0053: import java.io.ObjectOutputStream;
0054: import java.lang.reflect.Constructor;
0055: import java.lang.reflect.InvocationTargetException;
0056: import java.util.ListIterator;
0057:
0058: import javax.media.j3d.BoundingBox;
0059: import javax.media.j3d.BoundingPolytope;
0060: import javax.media.j3d.BoundingSphere;
0061: import javax.media.j3d.Bounds;
0062: import javax.media.j3d.BranchGroup;
0063: import javax.media.j3d.Canvas3D;
0064: import javax.media.j3d.CapabilityNotSetException;
0065: import javax.media.j3d.SceneGraphObject;
0066: import javax.media.j3d.SharedGroup;
0067: import javax.media.j3d.Transform3D;
0068: import javax.vecmath.Color3f;
0069: import javax.vecmath.Color4f;
0070: import javax.vecmath.Matrix4d;
0071: import javax.vecmath.Point3d;
0072: import javax.vecmath.Point3f;
0073: import javax.vecmath.Quat4f;
0074: import javax.vecmath.Tuple3d;
0075: import javax.vecmath.Tuple3f;
0076: import javax.vecmath.Tuple4d;
0077: import javax.vecmath.Tuple4f;
0078: import javax.vecmath.Vector3f;
0079: import javax.vecmath.Vector4d;
0080: import javax.vecmath.Vector4f;
0081:
0082: import com.sun.j3d.utils.scenegraph.io.NamedObjectException;
0083: import com.sun.j3d.utils.scenegraph.io.ObjectNotLoadedException;
0084: import com.sun.j3d.utils.scenegraph.io.SceneGraphStateProvider;
0085: import com.sun.j3d.utils.scenegraph.io.UnsupportedUniverseException;
0086: import com.sun.j3d.utils.scenegraph.io.state.com.sun.j3d.utils.universe.SimpleUniverseState;
0087: import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.ImageComponentState;
0088: import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.NullSceneGraphObjectState;
0089: import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.SceneGraphObjectState;
0090: import com.sun.j3d.utils.universe.ConfiguredUniverse;
0091: import com.sun.j3d.utils.universe.SimpleUniverse;
0092:
0093: /**
0094: * Provides code to control the reading and writing of Java3D objects to and
0095: * from any Java IO mechanism.
0096: */
0097: public abstract class Controller extends java.lang.Object {
0098:
0099: protected static final long SYMBOL_TABLE_PTR = 30; // long - 8 bytes
0100: protected static final long BG_DIR_PTR = 38; // long - 8 bytes
0101: protected static final long NAMES_OBJECTS_TABLE_PTR = 46; // long - 8 bytes
0102: protected static final long NODE_TYPES_PTR = 52; // long - 8 bytes
0103: protected static final long UNIVERSE_CONFIG_PTR = 60; // long - 8 bytes
0104: protected static final long BRANCH_GRAPH_COUNT = 68; // int - 4 bytes
0105: protected static final long FILE_DESCRIPTION = 72; // UTF - n bytes
0106:
0107: protected SymbolTable symbolTable;
0108: protected NullSceneGraphObjectState nullObject = new NullSceneGraphObjectState(
0109: null, this );
0110:
0111: /**
0112: * The currentFileVersion being read
0113: */
0114: protected int currentFileVersion;
0115:
0116: /**
0117: * The File version which will be written
0118: *
0119: * 1 = Java3D 1.3 beta 1
0120: * 2 = Java3D 1.3 FCS, 1) fix to allow skipping user data written via
0121: SceneGraphIO interface
0122: 2) Add missing duplicateOnCloneTree flag
0123: (bug 4690159)
0124: * 3 = Java3D 1.5.1 1) Add support for SceneGraphObject Name field
0125: * 4 = Java3D 1.5.2 issue 532, for saving Background Geometry
0126: */
0127: protected int outputFileVersion = 4;
0128:
0129: /**
0130: * When running the application within webstart this may not be the
0131: * correct ClassLoader. If Java 3D is not installed in the local vm and
0132: * is instead installed by webstart then this definitely is NOT the correct
0133: * classloader, in this case Thread.getCurrent().getClass().getClassLoader()
0134: * would probably be a good default. The user can also set their preferred
0135: * classloader by calling setClassLoader in SceneGraph[Stream|File]Reader.
0136: */
0137: protected ClassLoader classLoader = ClassLoader
0138: .getSystemClassLoader();
0139:
0140: /**
0141: * If true when loading a scenegraph that contains nodes who's classes
0142: * are not in the classpath then use then first Java3D core superclass
0143: * to instantiate the node.
0144: *
0145: * If false a SGIORuntimeException will be thrown when classes cannot be
0146: * located
0147: */
0148: private boolean useSuperClass = false;
0149:
0150: private int imageCompression = ImageComponentState.NO_COMPRESSION;
0151:
0152: /** Creates new Controller */
0153: public Controller() {
0154: try {
0155: if (System
0156: .getProperty("j3d.io.UseSuperClassIfNoChildClass") != null)
0157: useSuperClass = true;
0158:
0159: String imageC = System
0160: .getProperty("j3d.io.ImageCompression");
0161: if (imageC != null) {
0162: if (imageC.equalsIgnoreCase("None"))
0163: imageCompression = ImageComponentState.NO_COMPRESSION;
0164: else if (imageC.equalsIgnoreCase("GZIP"))
0165: imageCompression = ImageComponentState.GZIP_COMPRESSION;
0166: else if (imageC.equalsIgnoreCase("JPEG"))
0167: imageCompression = ImageComponentState.JPEG_COMPRESSION;
0168: }
0169: } catch (Exception e) {
0170: }
0171:
0172: }
0173:
0174: public final SymbolTable getSymbolTable() {
0175: return symbolTable;
0176: }
0177:
0178: /**
0179: * Get the file version that we should write
0180: */
0181: public int getOutputFileVersion() {
0182: return outputFileVersion;
0183: }
0184:
0185: /**
0186: * Get the file version of the file we are reading
0187: */
0188: public int getCurrentFileVersion() {
0189: return currentFileVersion;
0190: }
0191:
0192: /**
0193: * Create a new state object and check for a pre-existing symbol table
0194: * entry
0195: */
0196: public SceneGraphObjectState createState(SceneGraphObject obj) {
0197: return createState(obj, symbolTable.getSymbol(obj));
0198: }
0199:
0200: /**
0201: * Given a scene graph object instantiate the correct State class
0202: * for that object. If the symbol already exists (is not null) then
0203: * increment the reference count, otherwise create a new symbol.
0204: */
0205: public SceneGraphObjectState createState(SceneGraphObject obj,
0206: SymbolTableData symbol) {
0207: if (obj == null)
0208: return nullObject;
0209:
0210: if (symbol != null) {
0211: symbol.incrementReferenceCount();
0212: symbolTable.setBranchGraphID(symbol);
0213: if (symbol.getNodeState() != null)
0214: return symbol.getNodeState();
0215: } else
0216: symbol = symbolTable.createSymbol(obj);
0217:
0218: return createState(symbol);
0219: }
0220:
0221: /**
0222: * Return the state class for the SceneGraphObject, creating one if it does
0223: * not already exist
0224: */
0225: public SceneGraphObjectState createState(SymbolTableData symbol) {
0226: SceneGraphObject obj = symbol.getJ3dNode();
0227: if (obj == null)
0228: return nullObject;
0229:
0230: String name = obj.getClass().getName();
0231: SceneGraphObjectState ret;
0232:
0233: try {
0234: Class state;
0235: if (obj instanceof SceneGraphStateProvider)
0236: state = ((SceneGraphStateProvider) obj).getStateClass();
0237: else
0238: state = Class
0239: .forName("com.sun.j3d.utils.scenegraph.io.state."
0240: + name + "State");
0241: ret = constructStateObj(symbol, state, obj.getClass());
0242: } catch (ClassNotFoundException e) {
0243: ret = checkSuperClasses(symbol);
0244: if (!(obj instanceof com.sun.j3d.utils.scenegraph.io.SceneGraphIO))
0245: System.out.println("Could not find "
0246: + "com.sun.j3d.utils.scenegraph.io.state."
0247: + name + "State, using superclass "
0248: + ret.getClass().getName());
0249: if (ret == null)
0250: throw new SGIORuntimeException("No State class for "
0251: + obj.getClass().getName());
0252: }
0253:
0254: symbol.nodeState = ret;
0255:
0256: return ret;
0257: }
0258:
0259: private SceneGraphObjectState constructStateObj(
0260: SymbolTableData symbol, Class state, Class objClass) {
0261:
0262: SceneGraphObjectState ret = null;
0263:
0264: try {
0265: Constructor construct = state
0266: .getConstructor(new Class[] {
0267: com.sun.j3d.utils.scenegraph.io.retained.SymbolTableData.class,
0268: com.sun.j3d.utils.scenegraph.io.retained.Controller.class });
0269: ret = (SceneGraphObjectState) construct
0270: .newInstance(new Object[] { symbol, this });
0271:
0272: } catch (NoSuchMethodException ex) {
0273: System.out.println("Looking for Constructor ("
0274: + symbol.j3dNode.getClass().getName()
0275: + ", Controller )");
0276: throw new SGIORuntimeException("1 Broken State class for "
0277: + state.getName());
0278: } catch (InvocationTargetException exc) {
0279: exc.printStackTrace();
0280: throw new SGIORuntimeException("2 Broken State class for "
0281: + state.getName());
0282: } catch (IllegalAccessException exce) {
0283: throw new SGIORuntimeException("3 Broken State class for "
0284: + state.getName());
0285: } catch (InstantiationException excep) {
0286: throw new SGIORuntimeException("4 Broken State class for "
0287: + state.getName());
0288: }
0289:
0290: return ret;
0291: }
0292:
0293: /**
0294: * Check to see if any of the superclasses of obj are
0295: * known to the Java3D IO package
0296: */
0297: private SceneGraphObjectState checkSuperClasses(
0298: SymbolTableData symbol) {
0299:
0300: Class cl = symbol.j3dNode.getClass().getSuperclass();
0301: Class state = null;
0302: boolean finished = false;
0303:
0304: while (cl != null & !finished) {
0305: String name = cl.getName();
0306: //System.out.println("Got superclass "+name);
0307: try {
0308: state = Class
0309: .forName("com.sun.j3d.utils.scenegraph.io.state."
0310: + name + "State");
0311: } catch (ClassNotFoundException e) {
0312: state = null;
0313: }
0314:
0315: if (state != null)
0316: finished = true;
0317: else
0318: cl = cl.getSuperclass();
0319: }
0320:
0321: if (cl == null)
0322: throw new SGIORuntimeException("Unsupported class "
0323: + symbol.j3dNode.getClass().getName());
0324:
0325: return constructStateObj(symbol, state, cl);
0326: }
0327:
0328: public void writeObject(DataOutput out, SceneGraphObjectState obj)
0329: throws IOException {
0330:
0331: int classID = getStateID(obj);
0332:
0333: out.writeInt(classID); // Node class id
0334:
0335: if (classID == 0) {
0336: out.writeUTF(obj.getClass().getName());
0337: }
0338:
0339: obj.writeObject(out);
0340: }
0341:
0342: public SceneGraphObjectState readObject(DataInput in)
0343: throws IOException {
0344: int classID = in.readInt();
0345:
0346: SceneGraphObjectState state = null;
0347:
0348: if (classID == -1)
0349: return nullObject;
0350: else if (classID == 0) {
0351: String stateClassName = in.readUTF();
0352:
0353: try {
0354: Class cl = Class.forName(stateClassName, true,
0355: classLoader);
0356: // System.out.println("Got class "+cl );
0357: Constructor construct = cl
0358: .getConstructor(new Class[] {
0359: com.sun.j3d.utils.scenegraph.io.retained.SymbolTableData.class,
0360: com.sun.j3d.utils.scenegraph.io.retained.Controller.class });
0361:
0362: // System.out.println("Got constructor "+construct );
0363: state = (SceneGraphObjectState) construct
0364: .newInstance(new Object[] { null, this });
0365:
0366: // System.out.println("Got state instance "+state);
0367: } catch (ClassNotFoundException e) {
0368: throw new java.io.IOException(
0369: "Error Loading State Class " + stateClassName
0370: + " " + e.getMessage());
0371: } catch (NoSuchMethodException ex) {
0372: throw new java.io.IOException(
0373: "1 Broken State class for " + stateClassName
0374: + " " + ex.getMessage());
0375: } catch (InvocationTargetException exc) {
0376: exc.printStackTrace();
0377: throw new java.io.IOException(
0378: "2 Broken State class for " + stateClassName);
0379: } catch (IllegalAccessException exce) {
0380: throw new java.io.IOException(
0381: "3 Broken State class for " + stateClassName);
0382: } catch (InstantiationException excep) {
0383: throw new java.io.IOException(
0384: "4 Broken State class for " + stateClassName);
0385: }
0386: } else {
0387: state = createCoreState(classID);
0388: }
0389:
0390: state.readObject(in);
0391:
0392: return state;
0393: }
0394:
0395: /**
0396: * Set the class loader used to load the Scene Graph Objects and
0397: * the serialized user data. The default is
0398: * ClassLoader.getSystemClassLoader()
0399: */
0400: public void setClassLoader(ClassLoader classLoader) {
0401: this .classLoader = classLoader;
0402: }
0403:
0404: /**
0405: * Get the class loader used to load the Scene Graph Objects and
0406: * the serialized user data. The default is
0407: * ClassLoader.getSystemClassLoader()
0408: */
0409: public ClassLoader getClassLoader() {
0410: return classLoader;
0411: }
0412:
0413: /**
0414: * Write all the unsaved NodeComponents and SharedGroups to DataOutput.
0415: * Mark all the NodeComponents as saved.
0416: */
0417: protected void writeNodeComponents(DataOutput out)
0418: throws IOException {
0419: // This method is overridden by RandomAccessFileControl
0420: // The RandomAccessFileControl version sets the pointer to
0421: // the next NodeComponent correclty
0422:
0423: ListIterator list = symbolTable.getUnsavedNodeComponents();
0424: out.writeInt(symbolTable.getUnsavedNodeComponentsSize());
0425: while (list.hasNext()) {
0426: SymbolTableData symbol = (SymbolTableData) list.next();
0427:
0428: out.writeInt(symbol.nodeID);
0429: out.writeLong(0L); // Pointer to next NodeComponent
0430:
0431: writeObject(out, symbol.getNodeState());
0432: }
0433: }
0434:
0435: /**
0436: * Read in all the node components in this block
0437: */
0438: protected void readNodeComponents(DataInput in) throws IOException {
0439: int count = in.readInt();
0440:
0441: for (int i = 0; i < count; i++) {
0442: // nodeID and nextNC data is used in RandomAccessFileControl
0443: // version of readNodeComponents
0444: int nodeID = in.readInt();
0445: long nextNC = in.readLong();
0446:
0447: SceneGraphObjectState nodeComponent = readObject(in);
0448: }
0449: }
0450:
0451: /**
0452: * Write the shared group and it's node components to the IO stream
0453: */
0454: public void writeSharedGroup(DataOutput out,
0455: SharedGroup sharedGroup, SymbolTableData symbol)
0456: throws IOException {
0457: SceneGraphObjectState state = createState(sharedGroup, symbol);
0458: symbolTable.startUnsavedNodeComponentFrame();
0459: writeObject(out, state);
0460: writeNodeComponents(out);
0461: symbolTable.endUnsavedNodeComponentFrame();
0462: }
0463:
0464: /**
0465: * Read a Shared group and it's node components from the IO Stream
0466: */
0467: public int readSharedGroup(DataInput in) throws IOException {
0468: SceneGraphObjectState state = readObject(in);
0469: readNodeComponents(in);
0470:
0471: return state.getNodeID();
0472: }
0473:
0474: /**
0475: * Write out the Universe information.
0476: */
0477: public void writeUniverse(DataOutput out, SimpleUniverse universe,
0478: boolean writeUniverseContent) throws IOException,
0479: UnsupportedUniverseException, CapabilityNotSetException {
0480: if (universe == null) {
0481: out.writeUTF("null");
0482: } else if (universe instanceof SimpleUniverse) {
0483: out.writeUTF(universe.getClass().getName());
0484: SimpleUniverseState state = new SimpleUniverseState(
0485: universe, this );
0486: state.writeObject(out);
0487:
0488: if (writeUniverseContent) {
0489: state.detachAllGraphs();
0490: int[] graphs = state.getAllGraphIDs();
0491: for (int i = 0; i < graphs.length; i++) {
0492: SymbolTableData symbol = symbolTable
0493: .getBranchGraphRoot(graphs[i]);
0494: System.out.println("Writing " + graphs[i] + " "
0495: + symbol.j3dNode);
0496: writeBranchGraph((BranchGroup) symbol.j3dNode, null);
0497: }
0498:
0499: state.attachAllGraphs();
0500: }
0501: } else {
0502: throw new UnsupportedUniverseException(
0503: "Current Implementation only support SimpleUniverse/ConfiguredUniverse.");
0504: }
0505: }
0506:
0507: /**
0508: * Read and create a new Universe matching the one used during save.
0509: *
0510: * @param attachBranchGraphs If true then all the branchGraph attached to
0511: * the universe when it was saved will be loaded and reattached.
0512: */
0513: public ConfiguredUniverse readUniverse(DataInput in,
0514: boolean attachBranchGraphs, Canvas3D canvas)
0515: throws IOException {
0516: String universeClass = in.readUTF();
0517: //System.out.println(universeClass);
0518: if (universeClass.equals("null"))
0519: return null;
0520: else if ((universeClass
0521: .equals("com.sun.j3d.utils.universe.SimpleUniverse"))
0522: || (universeClass
0523: .equals("com.sun.j3d.utils.universe.ConfiguredUniverse"))) {
0524: SimpleUniverseState state = new SimpleUniverseState(this );
0525: state.readObject(in, canvas);
0526:
0527: if (attachBranchGraphs) {
0528: int[] graphs = state.getAllGraphIDs();
0529: readBranchGraphs(graphs);
0530:
0531: state.buildGraph();
0532: }
0533:
0534: return state.getNode();
0535: }
0536: throw new IOException("Unrecognized universe class "
0537: + universeClass);
0538: }
0539:
0540: /**
0541: * Read the set of branchgraps.
0542: *
0543: * Used by readUniverse
0544: *
0545: * RandomAccessFileControl will read the graphs in the array,
0546: * StreamControl will read all graphs in the stream
0547: */
0548: protected abstract void readBranchGraphs(int[] graphs)
0549: throws IOException;
0550:
0551: public abstract void writeBranchGraph(BranchGroup bg,
0552: java.io.Serializable userData) throws IOException;
0553:
0554: /**
0555: * Reset the controller, ready to load/save data to a new file
0556: */
0557: public void reset() {
0558: symbolTable.clear();
0559: }
0560:
0561: /**
0562: * 'Core' classes (ie those hard coded in this API) are assigned a
0563: * numerical value representing their class. This simply saves space
0564: * and IO bandwidth
0565: */
0566: private SceneGraphObjectState createCoreState(int classID) {
0567:
0568: if (classID == -1)
0569: return nullObject;
0570: else if (classID == 0)
0571: return null;
0572:
0573: Class j3dClass = getNodeClassFromID(classID - 1);
0574: String j3dClassName = j3dClass.getName();
0575: String stateClassName = "com.sun.j3d.utils.scenegraph.io.state."
0576: + j3dClassName + "State";
0577:
0578: SceneGraphObjectState stateObj = null;
0579: try {
0580: Class stateClass = Class.forName(stateClassName);
0581: Constructor stateConstructor = stateClass
0582: .getConstructor(new Class[] {
0583: SymbolTableData.class, Controller.class });
0584: stateObj = (SceneGraphObjectState) stateConstructor
0585: .newInstance(new Object[] { null, this });
0586: } catch (Exception e) {
0587: e.printStackTrace();
0588: }
0589:
0590: return stateObj;
0591: }
0592:
0593: /**
0594: * Return the id of the state class
0595: */
0596: private int getStateID(SceneGraphObjectState state) {
0597:
0598: if (state instanceof NullSceneGraphObjectState)
0599: return -1;
0600:
0601: return getNodeClassID(state.getNode()) + 1;
0602: }
0603:
0604: // The order of this array dictates the ID's of classes therefore
0605: // changing the order of this array will break backward compatability
0606: Class[] j3dClasses = new Class[] { javax.media.j3d.Alpha.class,
0607: javax.media.j3d.Appearance.class,
0608: javax.media.j3d.Billboard.class,
0609: javax.media.j3d.BranchGroup.class,
0610: javax.media.j3d.ColoringAttributes.class,
0611: javax.media.j3d.ConeSound.class,
0612: javax.media.j3d.DecalGroup.class,
0613: javax.media.j3d.DirectionalLight.class,
0614: javax.media.j3d.DistanceLOD.class,
0615: javax.media.j3d.ExponentialFog.class,
0616: javax.media.j3d.Font3D.class, javax.media.j3d.Group.class,
0617: javax.media.j3d.ImageComponent2D.class,
0618: javax.media.j3d.ImageComponent3D.class,
0619: javax.media.j3d.IndexedLineArray.class,
0620: javax.media.j3d.IndexedLineStripArray.class,
0621: javax.media.j3d.IndexedPointArray.class,
0622: javax.media.j3d.IndexedQuadArray.class,
0623: javax.media.j3d.IndexedTriangleArray.class,
0624: javax.media.j3d.IndexedTriangleFanArray.class,
0625: javax.media.j3d.IndexedTriangleStripArray.class,
0626: javax.media.j3d.LinearFog.class,
0627: javax.media.j3d.LineArray.class,
0628: javax.media.j3d.LineAttributes.class,
0629: javax.media.j3d.LineStripArray.class,
0630: javax.media.j3d.Link.class, javax.media.j3d.Material.class,
0631: javax.media.j3d.Morph.class,
0632: javax.media.j3d.OrderedGroup.class,
0633: javax.media.j3d.OrientedShape3D.class,
0634: javax.media.j3d.PathInterpolator.class,
0635: javax.media.j3d.PointArray.class,
0636: javax.media.j3d.PointAttributes.class,
0637: javax.media.j3d.PositionInterpolator.class,
0638: javax.media.j3d.PositionPathInterpolator.class,
0639: javax.media.j3d.QuadArray.class,
0640: javax.media.j3d.RenderingAttributes.class,
0641: javax.media.j3d.RotationInterpolator.class,
0642: javax.media.j3d.RotationPathInterpolator.class,
0643: javax.media.j3d.RotPosPathInterpolator.class,
0644: javax.media.j3d.RotPosScalePathInterpolator.class,
0645: javax.media.j3d.ScaleInterpolator.class,
0646: javax.media.j3d.Shape3D.class,
0647: javax.media.j3d.SharedGroup.class,
0648: javax.media.j3d.Soundscape.class,
0649: javax.media.j3d.SpotLight.class,
0650: javax.media.j3d.Switch.class,
0651: javax.media.j3d.SwitchValueInterpolator.class,
0652: javax.media.j3d.Text3D.class,
0653: javax.media.j3d.Texture2D.class,
0654: javax.media.j3d.Texture3D.class,
0655: javax.media.j3d.TextureAttributes.class,
0656: javax.media.j3d.TextureCubeMap.class,
0657: javax.media.j3d.TextureUnitState.class,
0658: javax.media.j3d.TransformGroup.class,
0659: javax.media.j3d.TransformInterpolator.class,
0660: javax.media.j3d.TransparencyAttributes.class,
0661: javax.media.j3d.TransparencyInterpolator.class,
0662: javax.media.j3d.TriangleArray.class,
0663: javax.media.j3d.TriangleFanArray.class,
0664: javax.media.j3d.TriangleStripArray.class,
0665: javax.media.j3d.ViewPlatform.class };
0666:
0667: public Class getNodeClassFromID(int classID) {
0668: if (classID < 0)
0669: return null;
0670: else
0671: return j3dClasses[classID];
0672: }
0673:
0674: // TODO Use a HashMap to eliminate the linear search for the class
0675: //
0676: public int getNodeClassID(javax.media.j3d.SceneGraphObject node) {
0677:
0678: int ret = -1;
0679: Class cl = node.getClass();
0680:
0681: for (int i = 0; i < j3dClasses.length && ret == -1; i++)
0682: if (j3dClasses[i] == cl)
0683: ret = i;
0684:
0685: return ret;
0686: }
0687:
0688: /**
0689: * Associate the name with the scene graph object
0690: */
0691: public void addNamedObject(String name, SceneGraphObject object) {
0692: symbolTable.addNamedObject(name, object);
0693: }
0694:
0695: /**
0696: * Return the SceneGraphObject associated with the name
0697: */
0698: public SceneGraphObject getNamedObject(String name)
0699: throws NamedObjectException, ObjectNotLoadedException {
0700: return symbolTable.getNamedObject(name);
0701: }
0702:
0703: /**
0704: * Get all the names of the named objects
0705: */
0706: public String[] getNames() {
0707: return symbolTable.getNames();
0708: }
0709:
0710: /**
0711: * Write a serializable object to the current file position, proceeded by
0712: * the size of the object
0713: */
0714: public void writeSerializedData(DataOutput dataOutput,
0715: java.io.Serializable userData) throws IOException {
0716: ByteArrayOutputStream out = new ByteArrayOutputStream();
0717: ObjectOutputStream objOut = new ObjectOutputStream(out);
0718:
0719: objOut.writeObject(userData);
0720:
0721: out.close();
0722:
0723: byte[] bytes = out.toByteArray();
0724: dataOutput.writeInt(bytes.length);
0725: if (bytes.length != 0)
0726: dataOutput.write(bytes);
0727: }
0728:
0729: public Object readSerializedData(DataInput dataInput)
0730: throws IOException {
0731: int size = dataInput.readInt();
0732: Object userData = null;
0733:
0734: if (size != 0) {
0735: byte[] bytes = new byte[size];
0736: dataInput.readFully(bytes);
0737:
0738: ByteArrayInputStream in = new ByteArrayInputStream(bytes);
0739: J3dIOObjectInputStream objIn = new J3dIOObjectInputStream(
0740: in);
0741:
0742: try {
0743: userData = objIn.readObject();
0744: objIn.close();
0745: } catch (ClassNotFoundException e) {
0746: System.out.println("WARNING: Unable to load UserData");
0747: System.out.println("Class missing " + e);
0748: objIn.close();
0749: }
0750: }
0751:
0752: return userData;
0753: }
0754:
0755: /**
0756: * Skip past the user data object
0757: */
0758: public void skipUserData(DataInput dataInput) throws IOException {
0759: int size = dataInput.readInt();
0760: dataInput.skipBytes(size);
0761: }
0762:
0763: public void writeColor3f(DataOutput out, Color3f color)
0764: throws IOException {
0765: out.writeFloat(color.x);
0766: out.writeFloat(color.y);
0767: out.writeFloat(color.z);
0768: }
0769:
0770: public Color3f readColor3f(DataInput in) throws IOException {
0771: return new Color3f(in.readFloat(), in.readFloat(), in
0772: .readFloat());
0773: }
0774:
0775: public void writeColor4f(DataOutput out, Color4f vec)
0776: throws IOException {
0777: writeTuple4f(out, vec);
0778: }
0779:
0780: public Color4f readColor4f(DataInput in) throws IOException {
0781: return (Color4f) readTuple4f(in, new Color4f());
0782: }
0783:
0784: public void writePoint3f(DataOutput out, Point3f pt)
0785: throws IOException {
0786: writeTuple3f(out, pt);
0787: }
0788:
0789: public Point3f readPoint3f(DataInput in) throws IOException {
0790: return (Point3f) readTuple3f(in, new Point3f());
0791: }
0792:
0793: public void writePoint3d(DataOutput out, Point3d pt)
0794: throws IOException {
0795: writeTuple3d(out, pt);
0796: }
0797:
0798: public Point3d readPoint3d(DataInput in) throws IOException {
0799: return (Point3d) readTuple3d(in, new Point3d());
0800: }
0801:
0802: public void writeVector3f(DataOutput out, Vector3f vec)
0803: throws IOException {
0804: writeTuple3f(out, vec);
0805: }
0806:
0807: public Vector3f readVector3f(DataInput in) throws IOException {
0808: return (Vector3f) readTuple3f(in, new Vector3f());
0809: }
0810:
0811: public void writeVector4d(DataOutput out, Vector4d vec)
0812: throws IOException {
0813: writeTuple4d(out, vec);
0814: }
0815:
0816: public Vector4d readVector4d(DataInput in) throws IOException {
0817: return (Vector4d) readTuple4d(in, new Vector4d());
0818: }
0819:
0820: public void writeVector4f(DataOutput out, Vector4f vec)
0821: throws IOException {
0822: writeTuple4f(out, vec);
0823: }
0824:
0825: public Vector4f readVector4f(DataInput in) throws IOException {
0826: return (Vector4f) readTuple4f(in, new Vector4f());
0827: }
0828:
0829: public void writeQuat4f(DataOutput out, Quat4f vec)
0830: throws IOException {
0831: writeTuple4f(out, vec);
0832: }
0833:
0834: public Quat4f readQuat4f(DataInput in) throws IOException {
0835: return (Quat4f) readTuple4f(in, new Quat4f());
0836: }
0837:
0838: public void writeMatrix4d(DataOutput out, Matrix4d m)
0839: throws IOException {
0840: for (int r = 0; r < 4; r++)
0841: for (int c = 0; c < 4; c++)
0842: out.writeDouble(m.getElement(r, c));
0843: }
0844:
0845: public Matrix4d readMatrix4d(DataInput in) throws IOException {
0846: double elements[] = new double[16];
0847: for (int c = 0; c < 16; c++)
0848: elements[c] = in.readDouble();
0849:
0850: return new Matrix4d(elements);
0851: }
0852:
0853: public void writeTuple3f(DataOutput out, Tuple3f tuple)
0854: throws IOException {
0855: out.writeFloat(tuple.x);
0856: out.writeFloat(tuple.y);
0857: out.writeFloat(tuple.z);
0858: }
0859:
0860: public Tuple3f readTuple3f(DataInput in, Tuple3f tuple)
0861: throws IOException {
0862: tuple.x = in.readFloat();
0863: tuple.y = in.readFloat();
0864: tuple.z = in.readFloat();
0865: return tuple;
0866: }
0867:
0868: public void writeTuple3d(DataOutput out, Tuple3d tuple)
0869: throws IOException {
0870: out.writeDouble(tuple.x);
0871: out.writeDouble(tuple.y);
0872: out.writeDouble(tuple.z);
0873: }
0874:
0875: public Tuple3d readTuple3d(DataInput in, Tuple3d tuple)
0876: throws IOException {
0877: tuple.x = in.readDouble();
0878: tuple.y = in.readDouble();
0879: tuple.z = in.readDouble();
0880: return tuple;
0881: }
0882:
0883: public void writeTuple4d(DataOutput out, Tuple4d tuple)
0884: throws IOException {
0885: out.writeDouble(tuple.x);
0886: out.writeDouble(tuple.y);
0887: out.writeDouble(tuple.z);
0888: out.writeDouble(tuple.w);
0889: }
0890:
0891: public Tuple4d readTuple4d(DataInput in, Tuple4d tuple)
0892: throws IOException {
0893: tuple.x = in.readDouble();
0894: tuple.y = in.readDouble();
0895: tuple.z = in.readDouble();
0896: tuple.w = in.readDouble();
0897: return tuple;
0898: }
0899:
0900: public void writeTuple4f(DataOutput out, Tuple4f tuple)
0901: throws IOException {
0902: out.writeFloat(tuple.x);
0903: out.writeFloat(tuple.y);
0904: out.writeFloat(tuple.z);
0905: out.writeFloat(tuple.w);
0906: }
0907:
0908: public Tuple4f readTuple4f(DataInput in, Tuple4f tuple)
0909: throws IOException {
0910: tuple.x = in.readFloat();
0911: tuple.y = in.readFloat();
0912: tuple.z = in.readFloat();
0913: tuple.w = in.readFloat();
0914: return tuple;
0915: }
0916:
0917: public void writeTransform3D(DataOutput out, Transform3D tran)
0918: throws IOException {
0919: Matrix4d matrix = new Matrix4d();
0920: tran.get(matrix);
0921: writeMatrix4d(out, matrix);
0922: }
0923:
0924: public Transform3D readTransform3D(DataInput in) throws IOException {
0925: Transform3D ret = new Transform3D();
0926: ret.set(readMatrix4d(in));
0927: return ret;
0928: }
0929:
0930: public void writeBounds(DataOutput out, Bounds bounds)
0931: throws IOException {
0932: if (bounds == null) {
0933: out.writeInt(0);
0934: } else if (bounds instanceof BoundingBox) {
0935: out.writeInt(1); // Type
0936: Point3d p = new Point3d();
0937: ((BoundingBox) bounds).getLower(p);
0938: writePoint3d(out, p);
0939: ((BoundingBox) bounds).getUpper(p);
0940: writePoint3d(out, p);
0941: } else if (bounds instanceof BoundingSphere) {
0942: out.writeInt(2); // Type
0943: Point3d p = new Point3d();
0944: ((BoundingSphere) bounds).getCenter(p);
0945: writePoint3d(out, p);
0946: out.writeDouble(((BoundingSphere) bounds).getRadius());
0947: } else if (bounds instanceof BoundingPolytope) {
0948: out.writeInt(3); // Type
0949: Vector4d[] planes = new Vector4d[((BoundingPolytope) bounds)
0950: .getNumPlanes()];
0951: ((BoundingPolytope) bounds).getPlanes(planes);
0952: out.writeInt(planes.length);
0953: for (int i = 0; i < planes.length; i++)
0954: writeVector4d(out, planes[i]);
0955: } else {
0956: throw new IOException("Unsupported bounds class "
0957: + bounds.getClass().getName());
0958: }
0959: }
0960:
0961: public Bounds readBounds(DataInput in) throws IOException {
0962: Bounds bounds;
0963: switch (in.readInt()) {
0964: case 0:
0965: bounds = null;
0966: break;
0967: case 1:
0968: bounds = new BoundingBox(readPoint3d(in), readPoint3d(in));
0969: break;
0970: case 2:
0971: bounds = new BoundingSphere(readPoint3d(in), in
0972: .readDouble());
0973: break;
0974: case 3:
0975: Vector4d[] planes = new Vector4d[in.readInt()];
0976: for (int i = 0; i < planes.length; i++)
0977: planes[i] = readVector4d(in);
0978: bounds = new BoundingPolytope(planes);
0979: break;
0980: default:
0981: throw new SGIORuntimeException("Unrecognised bounds class");
0982: }
0983: return bounds;
0984: }
0985:
0986: /**
0987: * Get the current file 'pointer' location.
0988: */
0989: public abstract long getFilePointer();
0990:
0991: public abstract void close() throws IOException;
0992:
0993: /**
0994: * Indicates to SceneGraphObjectState that it should use the
0995: * Java3D core superclass for any tree nodes whose classes are
0996: * not in the classpath during a load.
0997: */
0998: public boolean useSuperClassIfNoChildClass() {
0999: return useSuperClass;
1000: }
1001:
1002: /**
1003: * Returns the imageCompression to be used
1004: * IMAGE_COMPRESSION_NONE, IMAGE_COMPRESSION_GZIP, IMAGE_COMPRESSION_JPEG
1005: */
1006: public int getImageCompression() {
1007: return imageCompression;
1008: }
1009:
1010: /**
1011: * An ObjectInputStream that uses a different classLoader
1012: */
1013: class J3dIOObjectInputStream extends ObjectInputStream {
1014: public J3dIOObjectInputStream(java.io.InputStream in)
1015: throws IOException {
1016: super (in);
1017: }
1018:
1019: protected Class resolveClass(java.io.ObjectStreamClass desc)
1020: throws IOException, ClassNotFoundException {
1021: return getClass()
1022: .forName(desc.getName(), true, classLoader);
1023: }
1024: }
1025: }
|