001: /*
002: * $RCSfile: SequenceLine.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.4 $
041: * $Date: 2007/02/09 17:20:09 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.loaders.lw3d;
046:
047: import java.awt.Component;
048: import java.util.Enumeration;
049: import java.util.Hashtable;
050: import java.util.Vector;
051: import java.io.BufferedReader;
052: import java.io.File;
053: import java.io.FileReader;
054: import java.io.StreamTokenizer;
055: import java.io.IOException;
056: import javax.media.j3d.*;
057: import javax.vecmath.Point3d;
058:
059: import com.sun.j3d.loaders.IncorrectFormatException;
060: import com.sun.j3d.loaders.ParsingErrorException;
061: import java.io.FileNotFoundException;
062:
063: /**
064: * This class was created to handle "sequence files", which allow
065: * holosketch-type Tloop sequences to be loaded through the lw3d loader.
066: * The class reads a sequence file line by line and uses SequenceLine to
067: * load the file specified in each line.<BR>
068: * Idea behind the Tloop process:<BR>
069: * Artist creates "tloops" (animations with each keyframe's
070: * geometry saved out explicitly) where the geometries are spaced
071: * one frame apart. Then I can automatically create a SwitchValueInterpolator
072: * based on this spacing. If the number of frames in the sequence is
073: * greater than the number of frames in the tloop, then it will automatically
074: * loop until the end of the sequence.<BR>
075: * Process:<BR>
076: * 1) Artist creates an animation of a null group that has a child with some
077: * special name, such as "bucket_sequence_bucketsequence.txt.lwo", which tells
078: * the lw3d loader that it should look for a sequence file by the name of
079: * bucketsequence.txt. What happens to this object is irrelevant (as far as
080: * the loader is concerned); all animation information is taken from its
081: * parent instead.<BR>
082: * 2) Artist saves out the geometry of the bucket at whatever frames she wants
083: * to. If she's saving a tloop (a sequence of frames), she should save them
084: * under the names <filename>xxx.lwo, where xxx is the 3-digit sequence number
085: * (000, 001, 002, etc.).<BR>
086: * 3) Artist creates the sequence file, which lists all saved geometry files
087: * (except sequences - these can be referred to simply by the first file
088: * (...000.lwo)), along with their associated start/end frames. She also lists
089: * the number of files in the sequence, although this parameter is implied
090: * anyway, through the existence of the sequence files and their naming
091: * convention. Maybe we should trash this guy.<BR>
092: * 4) In the lw3d loader, when LwsObject encounters an object with the
093: * filename "..._sequence_<filename>.lwo", it searches for filename. If
094: * found, it parses the file (using the SequenceReader class) to retrieve
095: * all parameters.<BR>
096: * 5) Each SequenceLine creates a Java3D group containing its objects. This
097: * is either a plain-old-Group (if there is only one object) or a Switch group
098: * with a SwitchValueInterpolator.<BR>
099: * 6) SequenceReader constructs a Switch group and adds all SequenceLine groups
100: * to this new group. It also creates a SwitchPathInterpolator (child of
101: * PathInterolator) that contsructs an Alpha based on the startFrame values of
102: * each SequenceLine. It creates a group and adds the SwitchPathInterpolator
103: * plus any SequenceLine SwitchValueInterpolators to this group.<BR>
104: * 7) LwsObject adds the SequenceReader Switch group to its objectTransform.
105: * It does a getBehaviors() from SequenceReader and adds the result (the
106: * SwitchPathInterpolator group) to its objectBehaviors group.<BR>
107: * 8) Done.
108: */
109:
110: class SequenceLine {
111:
112: int startFrame;
113: int endFrame;
114: String fileName;
115:
116: Group geometryGroup = null;
117: Behavior behaviors;
118: int numFrames;
119: float totalTime;
120: int totalFrames;
121:
122: // storedRefList keeps references to already loaded objects
123: static Hashtable storedRefList = new Hashtable();
124:
125: SequenceLine(StreamTokenizer st, float time, int frames)
126: throws ParsingErrorException {
127: try {
128: totalTime = time;
129: totalFrames = frames;
130: startFrame = (int) st.nval;
131: st.nextToken();
132: endFrame = (int) st.nval;
133: st.nextToken();
134: fileName = st.sval;
135: numFrames = endFrame - startFrame + 1;
136: } catch (IOException e) {
137: throw new ParsingErrorException(e.getMessage());
138: }
139: }
140:
141: /**
142: * Creates a SwitchValueInterpolator which is used to switch between
143: * the objects specified for the sequence. This is done for files
144: * that end in "000", meaning that there are a sequence of files
145: * with that same base name that should specify every frame of a
146: * sequence for an object. The Switch node is used to hold all of the
147: * files and the Switch Behavior node is used to activate switching
148: * at the right time and to the right object.
149: */
150: private void createSwitchBehavior(Switch target) {
151:
152: int loopCount = -1;
153: float animTime = 1000.0f * totalTime
154: * (float) (target.numChildren()) / (float) totalFrames;
155: float startTime = 1000f * totalTime * (float) startFrame
156: / (float) totalFrames;
157: Alpha theAlpha = new Alpha(-1, (long) startTime, 0,
158: (long) animTime, 0, 0);
159:
160: SwitchValueInterpolator b = new SwitchValueInterpolator(
161: theAlpha, target);
162: behaviors = b;
163: BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,
164: 0.0, 0.0), 1000000.0);
165: b.setSchedulingBounds(bounds);
166: target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
167: target.addChild(behaviors);
168:
169: }
170:
171: /**
172: * Create Java3d objects from the data in the sequence line. This
173: * means that for a tloop file (ends in "000"), we're going to create
174: * the appropriate geometry for each file, put them all in a Switch
175: * node, then create a SwitchValueInterpolator to swap between the
176: * frames of the tloop. If it's not a tloop, then we're just going to
177: * create the geometry for that file.
178: */
179: void createJava3dObjects(int debugVals, int loadBehaviors)
180: throws IncorrectFormatException, FileNotFoundException {
181: if (fileName.indexOf("000") != -1) { // Tloop
182: int index = fileName.indexOf("000");
183: String fileNameBase = fileName.substring(0, index);
184: Switch s = new Switch();
185: s.setCapability(Switch.ALLOW_SWITCH_READ);
186: s.setCapability(Switch.ALLOW_SWITCH_WRITE);
187: String tempFileName = fileName;
188: int fileNum = 0;
189: while ((new File(tempFileName)).exists()) {
190: if (storedRefList.get(tempFileName) != null) {
191: // System.out.println("retrieve stored version of " +
192: // tempFileName);
193: SharedGroup storedGroup = (SharedGroup) storedRefList
194: .get(tempFileName);
195: Link newLink = new Link(storedGroup);
196: s.addChild(newLink);
197: } else {
198: // System.out.println("reading " + tempFileName);
199: J3dLwoParser objParser = new J3dLwoParser(
200: tempFileName, debugVals);
201: objParser.createJava3dGeometry();
202: TransformGroup t = new TransformGroup();
203: SharedGroup newSharedGroup = new SharedGroup();
204: storedRefList.put(tempFileName, newSharedGroup);
205: newSharedGroup.addChild(t);
206: Link newLink = new Link(newSharedGroup);
207: s.addChild(newLink);
208: if (objParser.getJava3dShapeList() != null) {
209: for (Enumeration e = objParser
210: .getJava3dShapeList().elements(); e
211: .hasMoreElements();) {
212: t.addChild((Shape3D) e.nextElement());
213: }
214: }
215: }
216: ++fileNum;
217: String fileNumString = String.valueOf(fileNum);
218: if (fileNum < 10)
219: fileNumString = "00" + fileNumString;
220: else if (fileNum < 100)
221: fileNumString = "0" + fileNumString;
222: tempFileName = fileNameBase + fileNumString + ".lwo";
223: }
224: behaviors = null;
225: if (loadBehaviors != 0) {
226: createSwitchBehavior(s);
227: }
228: geometryGroup = (Group) s;
229: } else {// Not a tloop, just a file
230: geometryGroup = new Group();
231: if (storedRefList.get(fileName) != null) {
232: // System.out.println("getting old ref to " + fileName);
233: SharedGroup storedGroup = (SharedGroup) storedRefList
234: .get(fileName);
235: Link newLink = new Link(storedGroup);
236: geometryGroup.addChild(newLink);
237: } else {
238: // System.out.println("reading " + fileName);
239: J3dLwoParser objParser = new J3dLwoParser(fileName,
240: debugVals);
241: objParser.createJava3dGeometry();
242: TransformGroup t = new TransformGroup();
243: if (objParser.getJava3dShapeList() != null) {
244: for (Enumeration e = objParser.getJava3dShapeList()
245: .elements(); e.hasMoreElements();) {
246: t.addChild((Shape3D) e.nextElement());
247: }
248: }
249: SharedGroup newSharedGroup = new SharedGroup();
250: newSharedGroup.addChild(t);
251: Link newLink = new Link(newSharedGroup);
252: geometryGroup.addChild(newLink);
253: storedRefList.put(fileName, newSharedGroup);
254: }
255: }
256: }
257:
258: Group getGeometry() {
259: return geometryGroup;
260: }
261:
262: Behavior getBehavior() {
263: return behaviors;
264: }
265:
266: }
|