1 /* 2 * $RCSfile: LwoParser.java,v $ 3 * 4 * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * - Redistribution of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * - Redistribution in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 18 * Neither the name of Sun Microsystems, Inc. or the names of 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * This software is provided "AS IS," without a warranty of any 23 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 24 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 25 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY 26 * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 27 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 28 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 29 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 30 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, 31 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND 32 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR 33 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGES. 35 * 36 * You acknowledge that this software is not designed, licensed or 37 * intended for use in the design, construction, operation or 38 * maintenance of any nuclear facility. 39 * 40 * $Revision: 1.4 $ 41 * $Date: 2007/02/09 17:20:07 $ 42 * $State: Exp $ 43 */ 44 45 package com.sun.j3d.loaders.lw3d; 46 47 48 49 import java.io.File; 50 import java.io.FileNotFoundException; 51 import java.io.IOException; 52 import java.util.Vector; 53 import java.util.Date; 54 import java.util.Enumeration; 55 import com.sun.j3d.loaders.lw3d.LWOBFileReader; 56 import com.sun.j3d.internal.J3dUtilsI18N; 57 import java.net.*; 58 import com.sun.j3d.loaders.ParsingErrorException; 59 import com.sun.j3d.loaders.IncorrectFormatException; 60 61 62 /** 63 * This class is responsible for parsing a binary Object file and storing 64 * the data. This class is not called directly, but is the parent class of 65 * J3dLwoObject. The subclass calls this class to parse the file, then it 66 * turns the resulting data into Java3D objects. LwoObject instantiates 67 * an LWOBFileReader object to parse the data. Then the class creates a 68 * list of ShapeHolder objects to hold all of the vertex/facet data and 69 * surface references and creates a list of LwoSurface objects to hold 70 * the data for each surface.<BR> 71 * Rather than describe in detail how the file is parsed for each method, 72 * I advise the user of this code to understand the lw3d file format 73 * specs, which are pretty clear. 74 */ 75 76 class LwoParser extends ParserObject { 77 78 LWOBFileReader theReader; 79 int currLength; 80 float coordsArray[]; 81 float normalCoordsArray[]; 82 int facetIndicesArray[]; 83 int facetSizesArray[]; 84 int normalIndicesArray[]; 85 int red = 255, green = 255, blue = 255; 86 float diffuse = 0.0f, specular = 0.0f, transparency = 0.0f, luminosity = 0.0f; 87 int gloss = 128; 88 Vector surfNameList = null; 89 Vector surfaceList = new Vector(200); 90 Vector shapeList = new Vector(200); 91 92 /** 93 * Constructor: Creates file reader and calls parseFile() to actually 94 * read the file and grab the data 95 */ LwoParser(String fileName, int debugVals)96 LwoParser(String fileName, int debugVals) 97 throws FileNotFoundException { 98 99 super(debugVals); 100 debugOutputLn(TRACE, "parser()"); 101 long start = System.currentTimeMillis(); 102 theReader = new LWOBFileReader(fileName); 103 debugOutputLn(TIME, " file opened in " + 104 (System.currentTimeMillis() - start)); 105 parseFile(); 106 } 107 LwoParser(URL url, int debugVals)108 LwoParser(URL url, int debugVals) 109 throws FileNotFoundException { 110 super(debugVals); 111 debugOutputLn(TRACE, "parser()"); 112 try { 113 long start = System.currentTimeMillis(); 114 theReader = new LWOBFileReader(url); 115 debugOutputLn(TIME, " file opened in " + 116 (System.currentTimeMillis() - start)); 117 } 118 catch (IOException ex) { 119 throw new FileNotFoundException(url.toString()); 120 } 121 parseFile(); 122 } 123 124 125 /** 126 * Detail polygons are currently not implemented by this loader. Their 127 * structure in geometry files is a bit complex, so there's this separate 128 * method for simply parsing through and ignoring the data for detail 129 * polygons 130 */ skipDetailPolygons(int numPolys)131 int skipDetailPolygons(int numPolys) throws ParsingErrorException { 132 debugOutputLn(TRACE, "skipDetailPolygons(), numPolys = " + numPolys); 133 int lengthRead = 0; 134 int vert; 135 136 try { 137 for (int polyNum = 0; polyNum < numPolys; ++polyNum) { 138 debugOutputLn(VALUES, "polyNum = " + polyNum); 139 int numVerts = theReader.getShortInt(); 140 theReader.skip(numVerts * 2 + 2); // skip indices plus surf 141 lengthRead += (numVerts * 2) + 4; // increment counter 142 } 143 } 144 catch (IOException e) { 145 debugOutputLn(EXCEPTION, "Exception in reading detail polys: " + e); 146 throw new ParsingErrorException(e.getMessage()); 147 } 148 return lengthRead; 149 } 150 151 /** 152 * Returns already-existing ShapeHolder if one exists with the same 153 * surface and the same geometry type (point, line, or poly) 154 */ getAppropriateShape(int numSurf, int numVerts)155 ShapeHolder getAppropriateShape(int numSurf, int numVerts) { 156 for (Enumeration e = shapeList.elements(); 157 e.hasMoreElements() ;) { 158 ShapeHolder shape = (ShapeHolder)e.nextElement(); 159 if (shape.numSurf == numSurf) 160 if (shape.numVerts == numVerts || 161 (shape.numVerts > 3 && 162 numVerts > 3)) 163 return shape; 164 } 165 return null; 166 } 167 168 169 /** 170 * Parse the file for all the data for a POLS object (polygon 171 * description) 172 */ getPols(int length)173 void getPols(int length) { 174 debugOutputLn(TRACE, "getPols(len), len = " + length); 175 int vert; 176 int lengthRead = 0; 177 int prevNumVerts = -1; 178 int prevNumSurf = 0; 179 Vector facetSizesList; 180 int facetIndicesArray[]; 181 facetSizesList = 182 new Vector(length/6); // worst case size (every poly one vert) 183 // Note that our array sizes are hardcoded because we don't 184 // know until we're done how large they will be 185 facetIndicesArray = new int[length/2]; 186 ShapeHolder shape = new ShapeHolder(debugPrinter.getValidOutput()); 187 debugOutputLn(VALUES, "new shape = " + shape); 188 shape.coordsArray = coordsArray; 189 shape.facetSizesList = facetSizesList; 190 //shape.facetIndicesList = facetIndicesList; 191 shape.facetIndicesArray = facetIndicesArray; 192 shapeList.addElement(shape); 193 194 //long startTime = (new Date()).getTime(); 195 boolean firstTime = true; 196 while (lengthRead < length) { 197 int numVerts = theReader.getShortInt(); 198 lengthRead += 2; 199 int intArray[] = new int[numVerts]; 200 for (int i = 0; i < numVerts; ++i) { 201 intArray[i] = theReader.getShortInt(); 202 lengthRead += 2; 203 } 204 205 int numSurf = theReader.getShortInt(); 206 lengthRead += 2; 207 long startTimeBuff = 0, startTimeList = 0; 208 if (!firstTime && 209 (numSurf != prevNumSurf || 210 ((numVerts != prevNumVerts) && 211 ((prevNumVerts < 3) || 212 (numVerts < 3))))) { 213 // If above true, then start new shape 214 shape = getAppropriateShape(numSurf, numVerts); 215 if (shape == null) { 216 //debugOutputLn(LINE_TRACE, "Starting new shape"); 217 facetSizesList = new Vector(length/6); 218 facetIndicesArray = new int[length/2]; 219 shape = new ShapeHolder(debugPrinter.getValidOutput()); 220 shape.coordsArray = coordsArray; 221 shape.facetSizesList = facetSizesList; 222 //shape.facetIndicesList = facetIndicesList; 223 shape.facetIndicesArray = facetIndicesArray; 224 shape.numSurf = numSurf; 225 shape.numVerts = numVerts; 226 shapeList.addElement(shape); 227 } 228 else { 229 facetSizesList = shape.facetSizesList; 230 facetIndicesArray = shape.facetIndicesArray; 231 } 232 } 233 else { 234 shape.numSurf = numSurf; 235 shape.numVerts = numVerts; 236 } 237 prevNumVerts = numVerts; 238 prevNumSurf = numSurf; 239 facetSizesList.addElement(new Integer(numVerts)); 240 241 int currPtr = 0; 242 System.arraycopy(intArray, 0, 243 facetIndicesArray, shape.currentNumIndices, 244 numVerts); 245 shape.currentNumIndices += numVerts; 246 if (numSurf < 0) { // neg number means detail poly 247 int numPolys = theReader.getShortInt(); 248 lengthRead += skipDetailPolygons(numPolys); 249 shape.numSurf = ~shape.numSurf & 0xffff; 250 if (shape.numSurf == 0) 251 shape.numSurf = 1; // Can't have surface = 0 252 } 253 firstTime = false; 254 } 255 } 256 257 /** 258 * Parses file to get the names of all surfaces. Each polygon will 259 * be associated with a particular surface number, which is the index 260 * number of these names 261 */ getSrfs(int length)262 void getSrfs(int length) { 263 String surfName = new String(); 264 surfNameList = new Vector(length/2); // worst case size (each name 2 chars long) 265 int lengthRead = 0; 266 int stopMarker = theReader.getMarker() + length; 267 268 int surfIndex = 0; 269 while (theReader.getMarker() < stopMarker) { 270 debugOutputLn(VALUES, "marker, stop = " + 271 theReader.getMarker() + ", " + stopMarker); 272 debugOutputLn(LINE_TRACE, "About to call getString"); 273 surfName = theReader.getString(); 274 debugOutputLn(VALUES, "Surfname = " + surfName); 275 surfNameList.addElement(surfName); 276 } 277 } 278 279 /** 280 * Parses file to get all vertices 281 */ getPnts(int length)282 void getPnts(int length) throws ParsingErrorException { 283 int numVerts = length / 12; 284 float x, y, z; 285 286 coordsArray = new float[numVerts*3]; 287 theReader.getVerts(coordsArray, numVerts); 288 } 289 290 /** 291 * Creates new LwoSurface object that parses file and gets all 292 * surface parameters for a particular surface 293 */ getSurf(int length)294 void getSurf(int length) throws FileNotFoundException { 295 debugOutputLn(TRACE, "getSurf()"); 296 297 // Create LwoSurface object to read and hold each surface, then 298 // store that surface in a vector of all surfaces. 299 300 LwoSurface surf = new LwoSurface(theReader, length, 301 debugPrinter.getValidOutput()); 302 surfaceList.addElement(surf); 303 } 304 305 306 /** 307 * parses entire file. 308 * return -1 on error or 0 on completion 309 */ parseFile()310 int parseFile() throws FileNotFoundException, IncorrectFormatException { 311 debugOutputLn(TRACE, "parseFile()"); 312 int length = 0; 313 int lengthRead = 0; 314 int fileLength = 100000; 315 316 long loopStartTime = System.currentTimeMillis(); 317 // Every parsing unit begins with a four character string 318 String tokenString = theReader.getToken(); 319 320 while (!(tokenString == null) && 321 lengthRead < fileLength) { 322 long startTime = System.currentTimeMillis(); 323 // Based on value of tokenString, go to correct parsing method 324 length = theReader.getInt(); 325 326 lengthRead += 4; 327 //debugOutputLn(VALUES, "length, lengthRead, fileLength = " + 328 // length + ", " + lengthRead + ", " + fileLength); 329 //debugOutputLn(VALUES, "LWOB marker is at: " + theReader.getMarker()); 330 331 if (tokenString.equals("FORM")) { 332 //debugOutputLn(LINE_TRACE, "got a form"); 333 fileLength = length + 4; 334 length = 0; 335 tokenString = theReader.getToken(); 336 lengthRead += 4; 337 if (!tokenString.equals("LWOB")) 338 throw new IncorrectFormatException( 339 "File not of FORM-length-LWOB format"); 340 } 341 else if (tokenString.equals("PNTS")) { 342 //debugOutputLn(LINE_TRACE, "PNTS"); 343 getPnts(length); 344 debugOutputLn(TIME, "done with " + tokenString + " in " + 345 (System.currentTimeMillis() - startTime)); 346 } 347 else if (tokenString.equals("POLS")) { 348 //debugOutputLn(LINE_TRACE, "POLS"); 349 getPols(length); 350 debugOutputLn(TIME, "done with " + tokenString + " in " + 351 (System.currentTimeMillis() - startTime)); 352 } 353 else if (tokenString.equals("SRFS")) { 354 //debugOutputLn(LINE_TRACE, "SRFS"); 355 getSrfs(length); 356 debugOutputLn(TIME, "done with " + tokenString + " in " + 357 (System.currentTimeMillis() - startTime)); 358 } 359 else if (tokenString.equals("CRVS")) { 360 //debugOutputLn(LINE_TRACE, "CRVS"); 361 theReader.skipLength(length); 362 //debugOutputLn(TIME, "done with " + tokenString + " in " + 363 // (System.currentTimeMillis() - startTime)); 364 } 365 else if (tokenString.equals("PCHS")) { 366 //debugOutputLn(LINE_TRACE, "PCHS"); 367 theReader.skipLength(length); 368 //debugOutputLn(TIME, "done with " + tokenString + " in " + 369 // (System.currentTimeMillis() - startTime)); 370 } 371 else if (tokenString.equals("SURF")) { 372 //debugOutputLn(LINE_TRACE, "SURF"); 373 getSurf(length); 374 //debugOutputLn(VALUES, "Done with SURF, marker = " + theReader.getMarker()); 375 debugOutputLn(TIME, "done with " + tokenString + " in " + 376 (System.currentTimeMillis() - startTime)); 377 } 378 else if (tokenString.equals("LWOB")) { 379 //debugOutputLn(LINE_TRACE, "LWOB"); 380 } 381 else { 382 //debugOutputLn(LINE_TRACE, "Unknown object = " + tokenString); 383 theReader.skipLength(length); 384 //debugOutputLn(TIME, "done with " + tokenString + " in " + 385 // (System.currentTimeMillis() - startTime)); 386 } 387 lengthRead += length; 388 if (lengthRead < fileLength) { 389 //debugOutputLn(VALUES, "end of parseFile, length, lengthRead = " + 390 // length + ", " + lengthRead); 391 tokenString = theReader.getToken(); 392 lengthRead += 4; 393 //debugOutputLn(VALUES, "just got tokenString = " + tokenString); 394 } 395 } 396 debugOutputLn(TIME, "done with parseFile in " + 397 (System.currentTimeMillis() - loopStartTime)); 398 return 0; 399 } 400 401 /** 402 * This method is used only for testing 403 */ main(String[] args)404 static void main(String[] args) { 405 String fileName; 406 if (args.length == 0) 407 fileName = "cube.obj"; 408 else 409 fileName = args[0]; 410 411 try { 412 LwoParser theParser = new LwoParser(fileName, 0); 413 } 414 catch (FileNotFoundException e) { 415 System.err.println(e.getMessage()); 416 e.printStackTrace(); 417 System.exit(1); 418 } 419 } 420 } 421 422 423 424 425