001: /*
002: * $RCSfile: LwoParser.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:07 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.loaders.lw3d;
046:
047: import java.io.File;
048: import java.io.FileNotFoundException;
049: import java.io.IOException;
050: import java.util.Vector;
051: import java.util.Date;
052: import java.util.Enumeration;
053: import com.sun.j3d.loaders.lw3d.LWOBFileReader;
054: import com.sun.j3d.internal.J3dUtilsI18N;
055: import java.net.*;
056: import com.sun.j3d.loaders.ParsingErrorException;
057: import com.sun.j3d.loaders.IncorrectFormatException;
058:
059: /**
060: * This class is responsible for parsing a binary Object file and storing
061: * the data. This class is not called directly, but is the parent class of
062: * J3dLwoObject. The subclass calls this class to parse the file, then it
063: * turns the resulting data into Java3D objects. LwoObject instantiates
064: * an LWOBFileReader object to parse the data. Then the class creates a
065: * list of ShapeHolder objects to hold all of the vertex/facet data and
066: * surface references and creates a list of LwoSurface objects to hold
067: * the data for each surface.<BR>
068: * Rather than describe in detail how the file is parsed for each method,
069: * I advise the user of this code to understand the lw3d file format
070: * specs, which are pretty clear.
071: */
072:
073: class LwoParser extends ParserObject {
074:
075: LWOBFileReader theReader;
076: int currLength;
077: float coordsArray[];
078: float normalCoordsArray[];
079: int facetIndicesArray[];
080: int facetSizesArray[];
081: int normalIndicesArray[];
082: int red = 255, green = 255, blue = 255;
083: float diffuse = 0.0f, specular = 0.0f, transparency = 0.0f,
084: luminosity = 0.0f;
085: int gloss = 128;
086: Vector surfNameList = null;
087: Vector surfaceList = new Vector(200);
088: Vector shapeList = new Vector(200);
089:
090: /**
091: * Constructor: Creates file reader and calls parseFile() to actually
092: * read the file and grab the data
093: */
094: LwoParser(String fileName, int debugVals)
095: throws FileNotFoundException {
096:
097: super (debugVals);
098: debugOutputLn(TRACE, "parser()");
099: long start = System.currentTimeMillis();
100: theReader = new LWOBFileReader(fileName);
101: debugOutputLn(TIME, " file opened in "
102: + (System.currentTimeMillis() - start));
103: parseFile();
104: }
105:
106: LwoParser(URL url, int debugVals) throws FileNotFoundException {
107: super (debugVals);
108: debugOutputLn(TRACE, "parser()");
109: try {
110: long start = System.currentTimeMillis();
111: theReader = new LWOBFileReader(url);
112: debugOutputLn(TIME, " file opened in "
113: + (System.currentTimeMillis() - start));
114: } catch (IOException ex) {
115: throw new FileNotFoundException(url.toString());
116: }
117: parseFile();
118: }
119:
120: /**
121: * Detail polygons are currently not implemented by this loader. Their
122: * structure in geometry files is a bit complex, so there's this separate
123: * method for simply parsing through and ignoring the data for detail
124: * polygons
125: */
126: int skipDetailPolygons(int numPolys) throws ParsingErrorException {
127: debugOutputLn(TRACE, "skipDetailPolygons(), numPolys = "
128: + numPolys);
129: int lengthRead = 0;
130: int vert;
131:
132: try {
133: for (int polyNum = 0; polyNum < numPolys; ++polyNum) {
134: debugOutputLn(VALUES, "polyNum = " + polyNum);
135: int numVerts = theReader.getShortInt();
136: theReader.skip(numVerts * 2 + 2); // skip indices plus surf
137: lengthRead += (numVerts * 2) + 4; // increment counter
138: }
139: } catch (IOException e) {
140: debugOutputLn(EXCEPTION,
141: "Exception in reading detail polys: " + e);
142: throw new ParsingErrorException(e.getMessage());
143: }
144: return lengthRead;
145: }
146:
147: /**
148: * Returns already-existing ShapeHolder if one exists with the same
149: * surface and the same geometry type (point, line, or poly)
150: */
151: ShapeHolder getAppropriateShape(int numSurf, int numVerts) {
152: for (Enumeration e = shapeList.elements(); e.hasMoreElements();) {
153: ShapeHolder shape = (ShapeHolder) e.nextElement();
154: if (shape.numSurf == numSurf)
155: if (shape.numVerts == numVerts
156: || (shape.numVerts > 3 && numVerts > 3))
157: return shape;
158: }
159: return null;
160: }
161:
162: /**
163: * Parse the file for all the data for a POLS object (polygon
164: * description)
165: */
166: void getPols(int length) {
167: debugOutputLn(TRACE, "getPols(len), len = " + length);
168: int vert;
169: int lengthRead = 0;
170: int prevNumVerts = -1;
171: int prevNumSurf = 0;
172: Vector facetSizesList;
173: int facetIndicesArray[];
174: facetSizesList = new Vector(length / 6); // worst case size (every poly one vert)
175: // Note that our array sizes are hardcoded because we don't
176: // know until we're done how large they will be
177: facetIndicesArray = new int[length / 2];
178: ShapeHolder shape = new ShapeHolder(debugPrinter
179: .getValidOutput());
180: debugOutputLn(VALUES, "new shape = " + shape);
181: shape.coordsArray = coordsArray;
182: shape.facetSizesList = facetSizesList;
183: //shape.facetIndicesList = facetIndicesList;
184: shape.facetIndicesArray = facetIndicesArray;
185: shapeList.addElement(shape);
186:
187: //long startTime = (new Date()).getTime();
188: boolean firstTime = true;
189: while (lengthRead < length) {
190: int numVerts = theReader.getShortInt();
191: lengthRead += 2;
192: int intArray[] = new int[numVerts];
193: for (int i = 0; i < numVerts; ++i) {
194: intArray[i] = theReader.getShortInt();
195: lengthRead += 2;
196: }
197:
198: int numSurf = theReader.getShortInt();
199: lengthRead += 2;
200: long startTimeBuff = 0, startTimeList = 0;
201: if (!firstTime
202: && (numSurf != prevNumSurf || ((numVerts != prevNumVerts) && ((prevNumVerts < 3) || (numVerts < 3))))) {
203: // If above true, then start new shape
204: shape = getAppropriateShape(numSurf, numVerts);
205: if (shape == null) {
206: //debugOutputLn(LINE_TRACE, "Starting new shape");
207: facetSizesList = new Vector(length / 6);
208: facetIndicesArray = new int[length / 2];
209: shape = new ShapeHolder(debugPrinter
210: .getValidOutput());
211: shape.coordsArray = coordsArray;
212: shape.facetSizesList = facetSizesList;
213: //shape.facetIndicesList = facetIndicesList;
214: shape.facetIndicesArray = facetIndicesArray;
215: shape.numSurf = numSurf;
216: shape.numVerts = numVerts;
217: shapeList.addElement(shape);
218: } else {
219: facetSizesList = shape.facetSizesList;
220: facetIndicesArray = shape.facetIndicesArray;
221: }
222: } else {
223: shape.numSurf = numSurf;
224: shape.numVerts = numVerts;
225: }
226: prevNumVerts = numVerts;
227: prevNumSurf = numSurf;
228: facetSizesList.addElement(new Integer(numVerts));
229:
230: int currPtr = 0;
231: System.arraycopy(intArray, 0, facetIndicesArray,
232: shape.currentNumIndices, numVerts);
233: shape.currentNumIndices += numVerts;
234: if (numSurf < 0) { // neg number means detail poly
235: int numPolys = theReader.getShortInt();
236: lengthRead += skipDetailPolygons(numPolys);
237: shape.numSurf = ~shape.numSurf & 0xffff;
238: if (shape.numSurf == 0)
239: shape.numSurf = 1; // Can't have surface = 0
240: }
241: firstTime = false;
242: }
243: }
244:
245: /**
246: * Parses file to get the names of all surfaces. Each polygon will
247: * be associated with a particular surface number, which is the index
248: * number of these names
249: */
250: void getSrfs(int length) {
251: String surfName = new String();
252: surfNameList = new Vector(length / 2); // worst case size (each name 2 chars long)
253: int lengthRead = 0;
254: int stopMarker = theReader.getMarker() + length;
255:
256: int surfIndex = 0;
257: while (theReader.getMarker() < stopMarker) {
258: debugOutputLn(VALUES, "marker, stop = "
259: + theReader.getMarker() + ", " + stopMarker);
260: debugOutputLn(LINE_TRACE, "About to call getString");
261: surfName = theReader.getString();
262: debugOutputLn(VALUES, "Surfname = " + surfName);
263: surfNameList.addElement(surfName);
264: }
265: }
266:
267: /**
268: * Parses file to get all vertices
269: */
270: void getPnts(int length) throws ParsingErrorException {
271: int numVerts = length / 12;
272: float x, y, z;
273:
274: coordsArray = new float[numVerts * 3];
275: theReader.getVerts(coordsArray, numVerts);
276: }
277:
278: /**
279: * Creates new LwoSurface object that parses file and gets all
280: * surface parameters for a particular surface
281: */
282: void getSurf(int length) throws FileNotFoundException {
283: debugOutputLn(TRACE, "getSurf()");
284:
285: // Create LwoSurface object to read and hold each surface, then
286: // store that surface in a vector of all surfaces.
287:
288: LwoSurface surf = new LwoSurface(theReader, length,
289: debugPrinter.getValidOutput());
290: surfaceList.addElement(surf);
291: }
292:
293: /**
294: * parses entire file.
295: * return -1 on error or 0 on completion
296: */
297: int parseFile() throws FileNotFoundException,
298: IncorrectFormatException {
299: debugOutputLn(TRACE, "parseFile()");
300: int length = 0;
301: int lengthRead = 0;
302: int fileLength = 100000;
303:
304: long loopStartTime = System.currentTimeMillis();
305: // Every parsing unit begins with a four character string
306: String tokenString = theReader.getToken();
307:
308: while (!(tokenString == null) && lengthRead < fileLength) {
309: long startTime = System.currentTimeMillis();
310: // Based on value of tokenString, go to correct parsing method
311: length = theReader.getInt();
312:
313: lengthRead += 4;
314: //debugOutputLn(VALUES, "length, lengthRead, fileLength = " +
315: // length + ", " + lengthRead + ", " + fileLength);
316: //debugOutputLn(VALUES, "LWOB marker is at: " + theReader.getMarker());
317:
318: if (tokenString.equals("FORM")) {
319: //debugOutputLn(LINE_TRACE, "got a form");
320: fileLength = length + 4;
321: length = 0;
322: tokenString = theReader.getToken();
323: lengthRead += 4;
324: if (!tokenString.equals("LWOB"))
325: throw new IncorrectFormatException(
326: "File not of FORM-length-LWOB format");
327: } else if (tokenString.equals("PNTS")) {
328: //debugOutputLn(LINE_TRACE, "PNTS");
329: getPnts(length);
330: debugOutputLn(TIME, "done with " + tokenString + " in "
331: + (System.currentTimeMillis() - startTime));
332: } else if (tokenString.equals("POLS")) {
333: //debugOutputLn(LINE_TRACE, "POLS");
334: getPols(length);
335: debugOutputLn(TIME, "done with " + tokenString + " in "
336: + (System.currentTimeMillis() - startTime));
337: } else if (tokenString.equals("SRFS")) {
338: //debugOutputLn(LINE_TRACE, "SRFS");
339: getSrfs(length);
340: debugOutputLn(TIME, "done with " + tokenString + " in "
341: + (System.currentTimeMillis() - startTime));
342: } else if (tokenString.equals("CRVS")) {
343: //debugOutputLn(LINE_TRACE, "CRVS");
344: theReader.skipLength(length);
345: //debugOutputLn(TIME, "done with " + tokenString + " in " +
346: // (System.currentTimeMillis() - startTime));
347: } else if (tokenString.equals("PCHS")) {
348: //debugOutputLn(LINE_TRACE, "PCHS");
349: theReader.skipLength(length);
350: //debugOutputLn(TIME, "done with " + tokenString + " in " +
351: // (System.currentTimeMillis() - startTime));
352: } else if (tokenString.equals("SURF")) {
353: //debugOutputLn(LINE_TRACE, "SURF");
354: getSurf(length);
355: //debugOutputLn(VALUES, "Done with SURF, marker = " + theReader.getMarker());
356: debugOutputLn(TIME, "done with " + tokenString + " in "
357: + (System.currentTimeMillis() - startTime));
358: } else if (tokenString.equals("LWOB")) {
359: //debugOutputLn(LINE_TRACE, "LWOB");
360: } else {
361: //debugOutputLn(LINE_TRACE, "Unknown object = " + tokenString);
362: theReader.skipLength(length);
363: //debugOutputLn(TIME, "done with " + tokenString + " in " +
364: // (System.currentTimeMillis() - startTime));
365: }
366: lengthRead += length;
367: if (lengthRead < fileLength) {
368: //debugOutputLn(VALUES, "end of parseFile, length, lengthRead = " +
369: // length + ", " + lengthRead);
370: tokenString = theReader.getToken();
371: lengthRead += 4;
372: //debugOutputLn(VALUES, "just got tokenString = " + tokenString);
373: }
374: }
375: debugOutputLn(TIME, "done with parseFile in "
376: + (System.currentTimeMillis() - loopStartTime));
377: return 0;
378: }
379:
380: /**
381: * This method is used only for testing
382: */
383: static void main(String[] args) {
384: String fileName;
385: if (args.length == 0)
386: fileName = "cube.obj";
387: else
388: fileName = args[0];
389:
390: try {
391: LwoParser theParser = new LwoParser(fileName, 0);
392: } catch (FileNotFoundException e) {
393: System.err.println(e.getMessage());
394: e.printStackTrace();
395: System.exit(1);
396: }
397: }
398: }
|