Source Code Cross Referenced for ObjectFile.java in  » 6.0-JDK-Modules » java-3d » com » sun » j3d » loaders » objectfile » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » java 3d » com.sun.j3d.loaders.objectfile 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: ObjectFile.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.5 $
0041:         * $Date: 2007/02/09 17:20:10 $
0042:         * $State: Exp $
0043:         */
0044:
0045:        package com.sun.j3d.loaders.objectfile;
0046:
0047:        import com.sun.j3d.loaders.Scene;
0048:        import com.sun.j3d.loaders.SceneBase;
0049:        import com.sun.j3d.loaders.Loader;
0050:        import com.sun.j3d.loaders.IncorrectFormatException;
0051:        import com.sun.j3d.loaders.ParsingErrorException;
0052:        import com.sun.j3d.loaders.objectfile.ObjectFileParser;
0053:        import com.sun.j3d.loaders.objectfile.ObjectFileMaterials;
0054:        import com.sun.j3d.utils.geometry.GeometryInfo;
0055:        import com.sun.j3d.utils.geometry.NormalGenerator;
0056:        import com.sun.j3d.utils.geometry.Stripifier;
0057:        import java.io.FileNotFoundException;
0058:        import java.io.StreamTokenizer;
0059:        import java.io.Reader;
0060:        import java.io.BufferedReader;
0061:        import java.io.BufferedInputStream;
0062:        import java.io.FileReader;
0063:        import java.io.InputStreamReader;
0064:        import java.io.IOException;
0065:        import java.net.URL;
0066:        import java.util.ArrayList;
0067:        import java.util.Iterator;
0068:        import java.util.HashMap;
0069:        import java.util.StringTokenizer;
0070:        import javax.media.j3d.*;
0071:        import javax.vecmath.Color3f;
0072:        import javax.vecmath.Point3f;
0073:        import javax.vecmath.Vector3f;
0074:        import javax.vecmath.TexCoord2f;
0075:        import java.net.MalformedURLException;
0076:
0077:        /**
0078:         * The ObjectFile class implements the Loader interface for the Wavefront
0079:         * .obj file format, a standard 3D object file format created for use with
0080:         * Wavefront's Advanced Visualizer (tm) and available for purchase from
0081:         * Viewpoint DataLabs, as well as other 3D model companies.  Object Files
0082:         * are text based
0083:         * files supporting both polygonal and free-form geometry (curves 
0084:         * and surfaces).  The Java 3D .obj file loader supports a subset of the
0085:         * file format, but it is enough to load almost all commonly available 
0086:         * Object Files.  Free-form geometry is not supported.</p>
0087:         *
0088:         * The Object File tokens currently supported by this loader are:</p>
0089:         * <code>v <i>float</i> <i>float</i> <i>float</i></code></p>
0090:         *   <dl><dd>A single vertex's geometric position in space.  The first vertex
0091:         *   listed in the file has index 1,
0092:         *   and subsequent vertices are numbered sequentially.</dl></p>
0093:         * <code>vn <i>float</i> <i>float</i> <i>float</i></code></p>
0094:         *   <dl><dd>A normal.  The first normal in the file is index 1, and 
0095:         *   subsequent normals are numbered sequentially.</dl></p>
0096:         * <code>vt <i>float</i> <i>float</i></code></p>
0097:         *   <dl><dd>A texture coordinate.  The first texture coordinate in the file is
0098:         *   index 1, and subsequent normals are numbered sequentially.</dl></p>
0099:         * <code>f <i>int</i> <i>int</i> <i>int</i> . . .</code></p>
0100:         *   <dl><dd><i><b>or</b></i></dl></p>
0101:         * <code>f <i>int</i>/<i>int</i> <i>int</i>/<i>int</i> <i>int</i>/<i>int</i> . . .</code></p>
0102:         *   <dl><dd><i><b>or</i></b></dl></p>
0103:         * <code>f <i>int</i>/<i>int</i>/<i>int</i> <i>int</i>/<i>int</i>/<i>int</i> <i>int</i>/<i>int</i>/<i>int</i> . . .</code></p>
0104:         *   <dl><dd>A polygonal face.  The numbers are indexes into the arrays of
0105:         *   vertex positions, texture coordinates, and normals respectively.
0106:         *   There is no maximum number of vertices that a single polygon may
0107:         *   contain.  The .obj file specification says that each face must
0108:         *   be flat and convex, but if the TRIANGULATE flag is sent to the
0109:         *   ObjectFile constructor, each face will be triangulated by the
0110:         *   Java 3D Triangulator, and therefore may be concave.
0111:         *   A number may be omitted if, for example, texture coordinates are
0112:         *   not being defined in the model.  Numbers are normally positive
0113:         *   indexes, but may also be negative.  An index of -1 means the last
0114:         *   member added to the respective array, -2 is the one before that,
0115:         *   and so on.</dl></p>
0116:         * <code>g <i>name</i></code></p>
0117:         *   <dl><dd>Faces defined after this token will be added to the named group.
0118:         *   These geometry groups are returned as separated Shape3D objects
0119:         *   attached to the parent SceneGroup.  Each named Shape3D will also
0120:         *   be in the Hashtable returned by Scene.getNamedObjects().  It is
0121:         *   legal to add faces to a group, switch to another group, and then 
0122:         *   add more faces to the original group by reissuing the same name
0123:         *   with the g token.  If faces are added to the model before the g
0124:         *   token is seen, the faces are put into the default group called
0125:         *   "default."</dl></p>
0126:         * <code>s <i>int</i></code></p>
0127:         *   <dl><dd><i><b>or</i></b></dl></p>
0128:         * <code>s off</code></p>
0129:         *   <dl><dd>If the vn token is not used in the file to specify vertex normals
0130:         *   for the model, this token may be used to put faces into groups
0131:         *   for normal calculation ("smoothing groups") in the same manner as
0132:         *   the 'g' token
0133:         *   is used to group faces geometrically.  Faces in the same smoothing
0134:         *   group will have their normals calculated as if they are part of
0135:         *   the same smooth surface.  To do this, we use the Java 3D NormalGenerator
0136:         *   utility with the creaseAngle parameter set to PI (180 degrees - 
0137:         *   smooth shading, no creases) or to whatever the user has set the 
0138:         *   creaseAngle.  Faces in group 0 or 'off' use a 
0139:         *   creaseAngle of zero, meaning there is no smoothing (the normal
0140:         *   of the face is used at all vertices giving the surface a faceted
0141:         *   look; there will be a
0142:         *   crease, or "Hard Edge," between each face in group zero).  There is
0143:         *   also an implied hard edge <i>between</i> each smoothing group, where they
0144:         *   meet each other.</p>
0145:         *   </p>
0146:         *   If neither the vn nor the s token is used in the file, then normals
0147:         *   are calculated using the creaseAngle set in the contructor.
0148:         *   Normals are calculated on each geometry
0149:         *   group separately, meaning there will be a hard edge between each
0150:         *   geometry group.</dl></p>
0151:         *   </p>
0152:         * <code>usemtl <i>name</i></code></p>
0153:         *   <dl><dd>The current (and subsequent) geometry groups (specified with
0154:         *   the 'g' token) have applied
0155:         *   to them the named material property.  The following set of material
0156:         *   properties are available by default:</dl></p>
0157:         *   <pre>
0158:         *     amber           amber_trans       aqua            aqua_filter
0159:         *     archwhite       archwhite2        bflesh          black
0160:         *     blondhair       blue_pure         bluegrey        bluetint
0161:         *     blugrn          blutan            bluteal         bone
0162:         *     bone1           bone2             brass           brnhair
0163:         *     bronze          brown             brownlips       brownskn
0164:         *     brzskin         chappie           charcoal        deepgreen
0165:         *     default         dkblue            dkblue_pure     dkbrown
0166:         *     dkdkgrey        dkgreen           dkgrey          dkorange
0167:         *     dkpurple        dkred             dkteal          emerald
0168:         *     fgreen          flaqua            flblack         flblonde
0169:         *     flblue_pure     flbrown           fldkblue_pure   fldkdkgrey
0170:         *     fldkgreen       fldkgreen2        fldkgrey        fldkolivegreen
0171:         *     fldkpurple      fldkred           flesh           fleshtransparent
0172:         *     flgrey          fllime            flltbrown       flltgrey
0173:         *     flltolivegreen  flmintgreen       flmustard       florange
0174:         *     flpinegreen     flpurple          flred           fltan
0175:         *     flwhite         flwhite1          flyellow        glass
0176:         *     glassblutint    glasstransparent  gold            green
0177:         *     greenskn        grey              hair            iris
0178:         *     jetflame        lavendar          lcdgreen        lighttan
0179:         *     lighttan2       lighttan3         lighttannew     lightyellow
0180:         *     lime            lips              ltbrown         ltgrey
0181:         *     meh             metal             mintgrn         muscle
0182:         *     navy_blue       offwhite.cool     offwhite.warm   olivegreen
0183:         *     orange          pale_green        pale_pink       pale_yellow
0184:         *     peach           periwinkle        pink            pinktan
0185:         *     plasma          purple            red             redbrick
0186:         *     redbrown        redorange         redwood         rubber
0187:         *     ruby            sand_stone        sapphire        shadow
0188:         *     ship2           silver            skin            sky_blue
0189:         *     smoked_glass    tan               taupe           teeth
0190:         *     violet          white             yellow          yellow_green
0191:         *     yellowbrt       yelloworng
0192:         *   </pre>
0193:         * <code>mtllib <i>filename</i></code></p>
0194:         *   <dl><dd>Load material properties from the named file.  Materials
0195:         *   with the same name as the predefined materials above will override
0196:         *   the default value.  Any directory path information in (filename)
0197:         *   is ignored.  The .mtl files are assumed to be in the same directory 
0198:         *   as the .obj file.  If they are in a different directory, use
0199:         *   Loader.setBasePath() (or Loader.setBaseUrl() ).  The format of the
0200:         *   material properties files
0201:         *   are as follows:</p>
0202:         *   <code>newmtl <i>name</i></code></p>
0203:         *     <dl><dd>Start the definition of a new named material property.</dl></p>
0204:         *   <code>Ka <i>float</i> <i>float</i> <i>float</i></code></p>
0205:         *     <dl><dd>Ambient color.</dl></p>
0206:         *   <code>Kd <i>float</i> <i>float</i> <i>float</i></code></p>
0207:         *     <dl><dd>Diffuse color.</dl></p>
0208:         *   <code>Ks <i>float</i> <i>float</i> <i>float</i></code></p>
0209:         *     <dl><dd>Specular color.</dl></p>
0210:         *   <code>illum <i>(0, 1, or 2)</i></code></p>
0211:         *     <dl><dd>0 to disable lighting, 1 for ambient & diffuse only (specular
0212:         *     color set to black), 2 for full lighting.</dl></p>
0213:         *   <code>Ns <i>float</i></code></p>
0214:         *     <dl><dd>Shininess (clamped to 1.0 - 128.0).</dl></p>
0215:         *   <code>map_Kd <i>filename</i></code></p>
0216:         *     <dl><dd>Texture map.  Supports .rgb, .rgba, .int, .inta, .sgi, and
0217:         *     .bw files in addition to those supported by
0218:         *     <a href="../../utils/image/TextureLoader.html">TextureLoader</a>.
0219:         *     </dl></dl></p>
0220:         */
0221:
0222:        public class ObjectFile implements  Loader {
0223:            // 0=Input file assumed good
0224:            // 1=Input file checked for inconsistencies
0225:            // 2=path names
0226:            // 4=flags
0227:            // 8=Timing Info
0228:            // 16=Tokens
0229:            // 32=Token details (use with 16)
0230:            // 64=limits of model coordinates
0231:            private static final int DEBUG = 0;
0232:
0233:            /**
0234:             * Flag sent to constructor.  The object's vertices will be changed
0235:             * so that the object is centered at (0,0,0) and the coordinate
0236:             * positions are all in the range of (-1,-1,-1) to (1,1,1).
0237:             */
0238:            public static final int RESIZE = LOAD_SOUND_NODES << 1;
0239:
0240:            /**
0241:             * Flag sent to constructor.  The Shape3D object will be created
0242:             * by using the GeometryInfo POLYGON_ARRAY primitive, causing
0243:             * them to be Triangulated by GeometryInfo.  Use
0244:             * this if you suspect concave or other non-behaving polygons
0245:             * in your model.
0246:             */
0247:            public static final int TRIANGULATE = RESIZE << 1;
0248:
0249:            /**
0250:             * Flag sent to constructor.  Use if the vertices in your .obj
0251:             * file were specified with clockwise winding (Java 3D wants
0252:             * counter-clockwise) so you see the back of the polygons and
0253:             * not the front.  Calls GeometryInfo.reverse().
0254:             */
0255:            public static final int REVERSE = TRIANGULATE << 1;
0256:
0257:            /**
0258:             * Flag sent to contructor.  After normals are generated the data
0259:             * will be analyzed to find triangle strips.  Use this if your
0260:             * hardware supports accelerated rendering of strips.
0261:             */
0262:            public static final int STRIPIFY = REVERSE << 1;
0263:
0264:            private static final char BACKSLASH = '\\';
0265:
0266:            private int flags;
0267:            private String basePath = null;
0268:            private URL baseUrl = null;
0269:            private boolean fromUrl = false;
0270:            private float radians;
0271:
0272:            // First, lists of points are read from the .obj file into these arrays. . .
0273:            private ArrayList coordList; // Holds Point3f
0274:            private ArrayList texList; // Holds TexCoord2f
0275:            private ArrayList normList; // Holds Vector3f
0276:
0277:            // . . . and index lists are read into these arrays.
0278:            private ArrayList coordIdxList; // Holds Integer index into coordList
0279:            private ArrayList texIdxList; // Holds Integer index into texList
0280:            private ArrayList normIdxList; // Holds Integer index into normList
0281:
0282:            // The length of each face is stored in this array.
0283:            private ArrayList stripCounts; // Holds Integer
0284:
0285:            // Each face's Geometry Group membership is kept here. . .
0286:            private HashMap groups; // key=Integer index into stripCounts
0287:            // value=String name of group
0288:            private String curGroup;
0289:
0290:            // . . . and Smoothing Group membership is kept here
0291:            private HashMap sGroups; // key=Integer index into stripCounts
0292:            // value=String name of group
0293:            private String curSgroup;
0294:
0295:            // The name of each group's "usemtl" material property is kept here
0296:            private HashMap groupMaterials; // key=String name of Group
0297:            // value=String name of material
0298:
0299:            // After reading the entire file, the faces are converted into triangles.
0300:            // The Geometry Group information is converted into these structures. . .
0301:            private HashMap triGroups; // key=String name of group
0302:            // value=ArrayList of Integer
0303:            //       indices into coordIdxList
0304:            private ArrayList curTriGroup;
0305:
0306:            // . . . and Smoothing Group info is converted into these.
0307:            private HashMap triSgroups; // key=String name of group
0308:            // value=ArrayList of Integer
0309:            // indices into coordIdxList
0310:            private ArrayList curTriSgroup;
0311:
0312:            // Finally, coordList, texList, and normList are converted to arrays for
0313:            // use with GeometryInfo
0314:            private Point3f coordArray[] = null;
0315:            private Vector3f normArray[] = null;
0316:            private TexCoord2f texArray[] = null;
0317:
0318:            // Used for debugging
0319:            private long time;
0320:
0321:            private ObjectFileMaterials materials = null;
0322:
0323:            void readVertex(ObjectFileParser st) throws ParsingErrorException {
0324:                Point3f p = new Point3f();
0325:
0326:                st.getNumber();
0327:                p.x = (float) st.nval;
0328:                st.getNumber();
0329:                p.y = (float) st.nval;
0330:                st.getNumber();
0331:                p.z = (float) st.nval;
0332:
0333:                if ((DEBUG & 32) != 0)
0334:                    System.out.println("  (" + p.x + "," + p.y + "," + p.z
0335:                            + ")");
0336:
0337:                st.skipToNextLine();
0338:
0339:                // Add this vertex to the array
0340:                coordList.add(p);
0341:            } // End of readVertex
0342:
0343:            /**
0344:             * readNormal
0345:             */
0346:            void readNormal(ObjectFileParser st) throws ParsingErrorException {
0347:                Vector3f p = new Vector3f();
0348:
0349:                st.getNumber();
0350:                p.x = (float) st.nval;
0351:                st.getNumber();
0352:                p.y = (float) st.nval;
0353:                st.getNumber();
0354:                p.z = (float) st.nval;
0355:
0356:                if ((DEBUG & 32) != 0)
0357:                    System.out.println("  (" + p.x + "," + p.y + "," + p.z
0358:                            + ")");
0359:
0360:                st.skipToNextLine();
0361:
0362:                // Add this vertex to the array
0363:                normList.add(p);
0364:            } // End of readNormal
0365:
0366:            /**
0367:             * readTexture
0368:             */
0369:            void readTexture(ObjectFileParser st) throws ParsingErrorException {
0370:                TexCoord2f p = new TexCoord2f();
0371:
0372:                st.getNumber();
0373:                p.x = (float) st.nval;
0374:                st.getNumber();
0375:                p.y = (float) st.nval;
0376:
0377:                if ((DEBUG & 32) != 0)
0378:                    System.out.println("  (" + p.x + "," + p.y + ")");
0379:
0380:                st.skipToNextLine();
0381:
0382:                // Add this vertex to the array
0383:                texList.add(p);
0384:            } // End of readTexture
0385:
0386:            /**
0387:             * readFace
0388:             *
0389:             *    Adds the indices of the current face to the arrays.
0390:             *
0391:             *    ViewPoint files can have up to three arrays:  Vertex Positions,
0392:             *    Texture Coordinates, and Vertex Normals.  Each vertex can
0393:             *    contain indices into all three arrays.
0394:             */
0395:            void readFace(ObjectFileParser st) throws ParsingErrorException {
0396:                int vertIndex, texIndex = 0, normIndex = 0;
0397:                int count = 0;
0398:
0399:                //   There are n vertices on each line.  Each vertex is comprised
0400:                //   of 1-3 numbers separated by slashes ('/').  The slashes may
0401:                //   be omitted if there's only one number.
0402:
0403:                st.getToken();
0404:
0405:                while (st.ttype != st.TT_EOL) {
0406:                    // First token is always a number (or EOL)
0407:                    st.pushBack();
0408:                    st.getNumber();
0409:                    vertIndex = (int) st.nval - 1;
0410:                    if (vertIndex < 0)
0411:                        vertIndex += coordList.size() + 1;
0412:                    coordIdxList.add(new Integer(vertIndex));
0413:
0414:                    // Next token is a slash, a number, or EOL.  Continue on slash
0415:                    st.getToken();
0416:                    if (st.ttype == '/') {
0417:
0418:                        // If there's a number after the first slash, read it
0419:                        st.getToken();
0420:                        if (st.ttype == st.TT_WORD) {
0421:                            // It's a number
0422:                            st.pushBack();
0423:                            st.getNumber();
0424:                            texIndex = (int) st.nval - 1;
0425:                            if (texIndex < 0)
0426:                                texIndex += texList.size() + 1;
0427:                            texIdxList.add(new Integer(texIndex));
0428:                            st.getToken();
0429:                        }
0430:
0431:                        // Next token is a slash, a number, or EOL.  Continue on slash
0432:                        if (st.ttype == '/') {
0433:
0434:                            // There has to be a number after the 2nd slash
0435:                            st.getNumber();
0436:                            normIndex = (int) st.nval - 1;
0437:                            if (normIndex < 0)
0438:                                normIndex += normList.size() + 1;
0439:                            normIdxList.add(new Integer(normIndex));
0440:                            st.getToken();
0441:                        }
0442:                    }
0443:                    if ((DEBUG & 32) != 0) {
0444:                        System.out.println("  " + vertIndex + '/' + texIndex
0445:                                + '/' + normIndex);
0446:                    }
0447:                    count++;
0448:                }
0449:
0450:                Integer faceNum = new Integer(stripCounts.size());
0451:                stripCounts.add(new Integer(count));
0452:
0453:                // Add face to current groups
0454:                groups.put(faceNum, curGroup);
0455:                if (curSgroup != null)
0456:                    sGroups.put(faceNum, curSgroup);
0457:
0458:                // In case we exited early
0459:                st.skipToNextLine();
0460:            } // End of readFace
0461:
0462:            /**
0463:             * readPartName
0464:             */
0465:            void readPartName(ObjectFileParser st) {
0466:                st.getToken();
0467:
0468:                // Find the Material Property of the current group
0469:                String curMat = (String) groupMaterials.get(curGroup);
0470:
0471:                // New faces will be added to the curGroup
0472:                if (st.ttype != ObjectFileParser.TT_WORD)
0473:                    curGroup = "default";
0474:                else
0475:                    curGroup = st.sval;
0476:                if ((DEBUG & 32) != 0)
0477:                    System.out.println("  Changed to group " + curGroup);
0478:
0479:                // See if this group has Material Properties yet
0480:                if (groupMaterials.get(curGroup) == null) {
0481:                    // It doesn't - carry over from last group
0482:                    groupMaterials.put(curGroup, curMat);
0483:                }
0484:
0485:                st.skipToNextLine();
0486:            } // End of readPartName
0487:
0488:            /**
0489:             * readMaterialName
0490:             */
0491:            void readMaterialName(ObjectFileParser st)
0492:                    throws ParsingErrorException {
0493:                st.getToken();
0494:                if (st.ttype == ObjectFileParser.TT_WORD) {
0495:                    groupMaterials.put(curGroup, new String(st.sval));
0496:                    if ((DEBUG & 32) != 0) {
0497:                        System.out.println("  Material Property " + st.sval
0498:                                + " assigned to group " + curGroup);
0499:                    }
0500:                }
0501:                st.skipToNextLine();
0502:            } // End of readMaterialName
0503:
0504:            /**
0505:             * loadMaterialFile
0506:             *
0507:             *	Both types of slashes are returned as tokens from our parser,
0508:             *	so we go through the line token by token and keep just the
0509:             *	last token on the line.  This should be the filename without
0510:             *	any directory info.
0511:             */
0512:            void loadMaterialFile(ObjectFileParser st)
0513:                    throws ParsingErrorException {
0514:                String s = null;
0515:
0516:                // Filenames are case sensitive
0517:                st.lowerCaseMode(false);
0518:
0519:                // Get name of material file (skip path)
0520:                do {
0521:                    st.getToken();
0522:                    if (st.ttype == ObjectFileParser.TT_WORD)
0523:                        s = st.sval;
0524:                } while (st.ttype != ObjectFileParser.TT_EOL);
0525:
0526:                materials.readMaterialFile(fromUrl, fromUrl ? baseUrl
0527:                        .toString() : basePath, s);
0528:
0529:                st.lowerCaseMode(true);
0530:                st.skipToNextLine();
0531:            } // End of loadMaterialFile
0532:
0533:            /**
0534:             * readSmoothingGroup
0535:             */
0536:            void readSmoothingGroup(ObjectFileParser st)
0537:                    throws ParsingErrorException {
0538:                st.getToken();
0539:                if (st.ttype != ObjectFileParser.TT_WORD) {
0540:                    st.skipToNextLine();
0541:                    return;
0542:                }
0543:                if (st.sval.equals("off"))
0544:                    curSgroup = "0";
0545:                else
0546:                    curSgroup = st.sval;
0547:                if ((DEBUG & 32) != 0)
0548:                    System.out.println("  Smoothing group " + curSgroup);
0549:                st.skipToNextLine();
0550:            } // End of readSmoothingGroup
0551:
0552:            /**
0553:             * readFile
0554:             *
0555:             *    Read the model data from the file.
0556:             */
0557:            void readFile(ObjectFileParser st) throws ParsingErrorException {
0558:                int t;
0559:
0560:                st.getToken();
0561:                while (st.ttype != ObjectFileParser.TT_EOF) {
0562:
0563:                    // Print out one token for each line
0564:                    if ((DEBUG & 16) != 0) {
0565:                        System.out.print("Token ");
0566:                        if (st.ttype == ObjectFileParser.TT_EOL)
0567:                            System.out.println("EOL");
0568:                        else if (st.ttype == ObjectFileParser.TT_WORD)
0569:                            System.out.println(st.sval);
0570:                        else
0571:                            System.out.println((char) st.ttype);
0572:                    }
0573:
0574:                    if (st.ttype == ObjectFileParser.TT_WORD) {
0575:                        if (st.sval.equals("v")) {
0576:                            readVertex(st);
0577:                        } else if (st.sval.equals("vn")) {
0578:                            readNormal(st);
0579:                        } else if (st.sval.equals("vt")) {
0580:                            readTexture(st);
0581:                        } else if (st.sval.equals("f")) {
0582:                            readFace(st);
0583:                        } else if (st.sval.equals("fo")) { // Not sure what the dif is
0584:                            readFace(st);
0585:                        } else if (st.sval.equals("g")) {
0586:                            readPartName(st);
0587:                        } else if (st.sval.equals("s")) {
0588:                            readSmoothingGroup(st);
0589:                        } else if (st.sval.equals("p")) {
0590:                            st.skipToNextLine();
0591:                        } else if (st.sval.equals("l")) {
0592:                            st.skipToNextLine();
0593:                        } else if (st.sval.equals("mtllib")) {
0594:                            loadMaterialFile(st);
0595:                        } else if (st.sval.equals("usemtl")) {
0596:                            readMaterialName(st);
0597:                        } else if (st.sval.equals("maplib")) {
0598:                            st.skipToNextLine();
0599:                        } else if (st.sval.equals("usemap")) {
0600:                            st.skipToNextLine();
0601:                        } else {
0602:                            throw new ParsingErrorException(
0603:                                    "Unrecognized token, line " + st.lineno());
0604:                        }
0605:                    }
0606:
0607:                    st.skipToNextLine();
0608:
0609:                    // Get next token
0610:                    st.getToken();
0611:                }
0612:            } // End of readFile
0613:
0614:            /**
0615:             * Constructor.
0616:             *
0617:             * @param flags The constants from above or from
0618:             * com.sun.j3d.loaders.Loader, possibly "or'ed" (|) together.
0619:             * @param radians Ignored if the vn token is present in the model (user
0620:             * normals supplied).  Otherwise, crease angle to use within smoothing
0621:             * groups, or within geometry groups if the s token isn't present either.
0622:             */
0623:            public ObjectFile(int flags, float radians) {
0624:                setFlags(flags);
0625:                this .radians = radians;
0626:            } // End of ObjectFile(int, float)
0627:
0628:            /**
0629:             * Constructor.  Crease Angle set to default of
0630:             * 44 degrees (see NormalGenerator utility for details).
0631:             * @param flags The constants from above or from
0632:             * com.sun.j3d.loaders.Loader, possibly "or'ed" (|) together.
0633:             */
0634:            public ObjectFile(int flags) {
0635:                this (flags, -1.0f);
0636:            } // End of ObjectFile(int)
0637:
0638:            /**
0639:             * Default constructor.  Crease Angle set to default of
0640:             * 44 degrees (see NormalGenerator utility for details).  Flags
0641:             * set to zero (0).
0642:             */
0643:            public ObjectFile() {
0644:                this (0, -1.0f);
0645:            } // End of ObjectFile()
0646:
0647:            /**
0648:             * Takes a file name and sets the base path to the directory
0649:             * containing that file.
0650:             */
0651:            private void setBasePathFromFilename(String fileName) {
0652:                if (fileName.lastIndexOf(java.io.File.separator) == -1) {
0653:                    // No path given - current directory
0654:                    setBasePath("." + java.io.File.separator);
0655:                } else {
0656:                    setBasePath(fileName.substring(0, fileName
0657:                            .lastIndexOf(java.io.File.separator)));
0658:                }
0659:            } // End of setBasePathFromFilename
0660:
0661:            /**
0662:             * The Object File is loaded from the .obj file specified by
0663:             * the filename.
0664:             * To attach the model to your scene, call getSceneGroup() on
0665:             * the Scene object passed back, and attach the returned
0666:             * BranchGroup to your scene graph.  For an example, see 
0667:             * j3d-examples/ObjLoad/ObjLoad.java.
0668:             */
0669:            public Scene load(String filename) throws FileNotFoundException,
0670:                    IncorrectFormatException, ParsingErrorException {
0671:
0672:                setBasePathFromFilename(filename);
0673:
0674:                Reader reader = new BufferedReader(new FileReader(filename));
0675:                return load(reader);
0676:            } // End of load(String)
0677:
0678:            private void setBaseUrlFromUrl(URL url)
0679:                    throws FileNotFoundException {
0680:                String u = url.toString();
0681:                String s;
0682:                if (u.lastIndexOf('/') == -1) {
0683:                    s = url.getProtocol() + ":";
0684:                } else {
0685:                    s = u.substring(0, u.lastIndexOf('/') + 1);
0686:                }
0687:                try {
0688:                    baseUrl = new URL(s);
0689:                } catch (MalformedURLException e) {
0690:                    throw new FileNotFoundException(e.getMessage());
0691:                }
0692:            } // End of setBaseUrlFromUrl
0693:
0694:            /**
0695:             * The object file is loaded off of the web.
0696:             * To attach the model to your scene, call getSceneGroup() on
0697:             * the Scene object passed back, and attach the returned
0698:             * BranchGroup to your scene graph.  For an example, see 
0699:             * j3d-examples/ObjLoad/ObjLoad.java.
0700:             */
0701:            public Scene load(URL url) throws FileNotFoundException,
0702:                    IncorrectFormatException, ParsingErrorException {
0703:                BufferedReader reader;
0704:
0705:                if (baseUrl == null)
0706:                    setBaseUrlFromUrl(url);
0707:
0708:                try {
0709:                    reader = new BufferedReader(new InputStreamReader(url
0710:                            .openStream()));
0711:                } catch (IOException e) {
0712:                    throw new FileNotFoundException(e.getMessage());
0713:                }
0714:                fromUrl = true;
0715:                return load(reader);
0716:            } // End of load(URL)
0717:
0718:            /**
0719:             * getLimits
0720:             *
0721:             * Returns an array of Point3f which form a bounding box around the
0722:             * object.  Element 0 is the low value, element 1 is the high value.
0723:             * See normalize() below for an example of how to use this method.
0724:             */
0725:            private Point3f[] getLimits() {
0726:                Point3f cur_vtx = new Point3f();
0727:
0728:                // Find the limits of the model
0729:                Point3f[] limit = new Point3f[2];
0730:                limit[0] = new Point3f(Float.MAX_VALUE, Float.MAX_VALUE,
0731:                        Float.MAX_VALUE);
0732:                limit[1] = new Point3f(Float.MIN_VALUE, Float.MIN_VALUE,
0733:                        Float.MIN_VALUE);
0734:                for (int i = 0; i < coordList.size(); i++) {
0735:
0736:                    cur_vtx = (Point3f) coordList.get(i);
0737:
0738:                    // Keep track of limits for normalization
0739:                    if (cur_vtx.x < limit[0].x)
0740:                        limit[0].x = cur_vtx.x;
0741:                    if (cur_vtx.x > limit[1].x)
0742:                        limit[1].x = cur_vtx.x;
0743:                    if (cur_vtx.y < limit[0].y)
0744:                        limit[0].y = cur_vtx.y;
0745:                    if (cur_vtx.y > limit[1].y)
0746:                        limit[1].y = cur_vtx.y;
0747:                    if (cur_vtx.z < limit[0].z)
0748:                        limit[0].z = cur_vtx.z;
0749:                    if (cur_vtx.z > limit[1].z)
0750:                        limit[1].z = cur_vtx.z;
0751:                }
0752:
0753:                if ((DEBUG & 64) != 0) {
0754:                    System.out.println("Model range: (" + limit[0].x + ","
0755:                            + limit[0].y + "," + limit[0].z + ") to ("
0756:                            + limit[1].x + "," + limit[1].y + "," + limit[1].z
0757:                            + ")");
0758:                }
0759:
0760:                return limit;
0761:            } // End of getLimits
0762:
0763:            /**
0764:             * Center the object and make it (-1,-1,-1) to (1,1,1).
0765:             */
0766:            private void resize() {
0767:                int i, j;
0768:                Point3f cur_vtx = new Point3f();
0769:                float biggest_dif;
0770:
0771:                Point3f[] limit = getLimits();
0772:
0773:                // Move object so it's centered on (0,0,0)
0774:                Vector3f offset = new Vector3f(-0.5f
0775:                        * (limit[0].x + limit[1].x), -0.5f
0776:                        * (limit[0].y + limit[1].y), -0.5f
0777:                        * (limit[0].z + limit[1].z));
0778:
0779:                if ((DEBUG & 64) != 0) {
0780:                    System.out.println("Offset amount: (" + offset.x + ","
0781:                            + offset.y + "," + offset.z + ")");
0782:                }
0783:
0784:                // Find the divide-by value for the normalization
0785:                biggest_dif = limit[1].x - limit[0].x;
0786:                if (biggest_dif < limit[1].y - limit[0].y)
0787:                    biggest_dif = limit[1].y - limit[0].y;
0788:                if (biggest_dif < limit[1].z - limit[0].z)
0789:                    biggest_dif = limit[1].z - limit[0].z;
0790:                biggest_dif /= 2.0f;
0791:
0792:                for (i = 0; i < coordList.size(); i++) {
0793:
0794:                    cur_vtx = (Point3f) coordList.get(i);
0795:
0796:                    cur_vtx.add(cur_vtx, offset);
0797:
0798:                    cur_vtx.x /= biggest_dif;
0799:                    cur_vtx.y /= biggest_dif;
0800:                    cur_vtx.z /= biggest_dif;
0801:
0802:                    // coordList.setElementAt(cur_vtx, i);
0803:                }
0804:            } // End of resize
0805:
0806:            private int[] objectToIntArray(ArrayList inList) {
0807:                int outList[] = new int[inList.size()];
0808:                for (int i = 0; i < inList.size(); i++) {
0809:                    outList[i] = ((Integer) inList.get(i)).intValue();
0810:                }
0811:                return outList;
0812:            } // End of objectToIntArray
0813:
0814:            private Point3f[] objectToPoint3Array(ArrayList inList) {
0815:                Point3f outList[] = new Point3f[inList.size()];
0816:                for (int i = 0; i < inList.size(); i++) {
0817:                    outList[i] = (Point3f) inList.get(i);
0818:                }
0819:                return outList;
0820:            } // End of objectToPoint3Array
0821:
0822:            private TexCoord2f[] objectToTexCoord2Array(ArrayList inList) {
0823:                TexCoord2f outList[] = new TexCoord2f[inList.size()];
0824:                for (int i = 0; i < inList.size(); i++) {
0825:                    outList[i] = (TexCoord2f) inList.get(i);
0826:                }
0827:                return outList;
0828:            } // End of objectToTexCoord2Array
0829:
0830:            private Vector3f[] objectToVectorArray(ArrayList inList) {
0831:                Vector3f outList[] = new Vector3f[inList.size()];
0832:                for (int i = 0; i < inList.size(); i++) {
0833:                    outList[i] = (Vector3f) inList.get(i);
0834:                }
0835:                return outList;
0836:            } // End of objectToVectorArray
0837:
0838:            /**
0839:             * Each group is a list of indices into the model's index lists,
0840:             * indicating the starting index of each triangle in the group.
0841:             * This method converts those data structures
0842:             * into an integer array to use with GeometryInfo.
0843:             */
0844:            private int[] groupIndices(ArrayList sourceList, ArrayList group) {
0845:                int indices[] = new int[group.size() * 3];
0846:                for (int i = 0; i < group.size(); i++) {
0847:                    int j = ((Integer) group.get(i)).intValue();
0848:                    indices[i * 3 + 0] = ((Integer) sourceList.get(j + 0))
0849:                            .intValue();
0850:                    indices[i * 3 + 1] = ((Integer) sourceList.get(j + 1))
0851:                            .intValue();
0852:                    indices[i * 3 + 2] = ((Integer) sourceList.get(j + 2))
0853:                            .intValue();
0854:                }
0855:                return indices;
0856:            } // end of groupIndices
0857:
0858:            /**
0859:             * smoothingGroupNormals
0860:             *
0861:             * Smoothing groups are groups of faces who should be grouped
0862:             * together for normal calculation purposes.  The faces are
0863:             * put into a GeometryInfo object and normals are calculated
0864:             * with a 180 degree creaseAngle (no creases) or whatever the
0865:             * user has specified.  The normals
0866:             * are then copied out of the GeometryInfo and back into
0867:             * ObjectFile data structures.
0868:             */
0869:            private void smoothingGroupNormals() {
0870:                NormalGenerator ng = new NormalGenerator(
0871:                        radians == -1.0f ? Math.PI : radians);
0872:                NormalGenerator ng0 = new NormalGenerator(0.0);
0873:                normList.clear();
0874:                normIdxList = null;
0875:                int newNormIdxArray[] = new int[coordIdxList.size()];
0876:
0877:                Iterator e = triSgroups.keySet().iterator();
0878:                while (e.hasNext()) {
0879:                    String curname = (String) e.next();
0880:                    ArrayList triList = (ArrayList) triSgroups.get(curname);
0881:
0882:                    // Check for group with no faces
0883:                    if (triList.size() > 0) {
0884:
0885:                        GeometryInfo gi = new GeometryInfo(
0886:                                GeometryInfo.TRIANGLE_ARRAY);
0887:
0888:                        gi.setCoordinateIndices(groupIndices(coordIdxList,
0889:                                triList));
0890:                        gi.setCoordinates(coordArray);
0891:
0892:                        if (curname.equals("0"))
0893:                            ng0.generateNormals(gi);
0894:                        else
0895:                            ng.generateNormals(gi);
0896:
0897:                        // Get the generated normals and indices
0898:                        Vector3f genNorms[] = gi.getNormals();
0899:                        int genNormIndices[] = gi.getNormalIndices();
0900:
0901:                        // Now we need to copy the generated normals into ObjectFile
0902:                        // data structures (normList and normIdxList).  The variable
0903:                        // normIdx is the index of the index of the normal currently
0904:                        // being put into the list.  It takes some calculation to
0905:                        // figure out the new index and where to put it.
0906:                        int normIdx = 0;
0907:                        // Repeat for each triangle in the smoothing group
0908:                        for (int i = 0; i < triList.size(); i++) {
0909:
0910:                            // Get the coordIdxList index of the first index in this face
0911:                            int idx = ((Integer) triList.get(i)).intValue();
0912:
0913:                            // Repeat for each vertex in the triangle
0914:                            for (int j = 0; j < 3; j++) {
0915:
0916:                                // Put the new normal's index into the index list
0917:                                newNormIdxArray[idx + j] = normList.size();
0918:
0919:                                // Add the vertex's normal to the normal list
0920:                                normList
0921:                                        .add(genNorms[genNormIndices[normIdx++]]);
0922:                            }
0923:                        }
0924:                    }
0925:                }
0926:                normIdxList = new ArrayList(coordIdxList.size());
0927:                for (int i = 0; i < coordIdxList.size(); i++) {
0928:                    normIdxList.add(new Integer(newNormIdxArray[i]));
0929:                }
0930:                normArray = objectToVectorArray(normList);
0931:            } // end of smoothingGroupNormals
0932:
0933:            /**
0934:             * Each face is converted to triangles.  As each face is converted,
0935:             * we look up which geometry group and smoothing group the face
0936:             * belongs to.  The generated triangles are added to each of these
0937:             * groups, which are also being converted to a new triangle based format.
0938:             *
0939:             * We need to convert to triangles before normals are generated
0940:             * because of smoothing groups.  The faces in a smoothing group 
0941:             * are copied into a GeometryInfo to have their normals calculated,
0942:             * and then the normals are copied out of the GeometryInfo using
0943:             * GeometryInfo.getNormalIndices.  As part of Normal generation,
0944:             * the geometry gets converted to Triangles.  So we need to convert
0945:             * to triangles *before* Normal generation so that the normals we
0946:             * read out of the GeometryInfo match up with the vertex data
0947:             * that we sent in.  If we sent in TRIANGLE_FAN data, the normal
0948:             * generator would convert it to triangles and we'd read out 
0949:             * normals formatted for Triangle data.  This would not match up
0950:             * with our original Fan data, so we couldn't tell which normals
0951:             * go with which vertices.
0952:             */
0953:            private void convertToTriangles() {
0954:                boolean triangulate = (flags & TRIANGULATE) != 0;
0955:                boolean textures = !texList.isEmpty() && !texIdxList.isEmpty()
0956:                        && (texIdxList.size() == coordIdxList.size());
0957:                boolean normals = !normList.isEmpty() && !normIdxList.isEmpty()
0958:                        && (normIdxList.size() == coordIdxList.size());
0959:                int numFaces = stripCounts.size();
0960:                boolean haveSgroups = curSgroup != null;
0961:
0962:                triGroups = new HashMap(50);
0963:                if (haveSgroups)
0964:                    triSgroups = new HashMap(50);
0965:
0966:                ArrayList newCoordIdxList = null;
0967:                ArrayList newTexIdxList = null;
0968:                ArrayList newNormIdxList = null;
0969:
0970:                if (triangulate) {
0971:                    GeometryInfo gi = new GeometryInfo(
0972:                            GeometryInfo.POLYGON_ARRAY);
0973:                    gi.setStripCounts(objectToIntArray(stripCounts));
0974:                    gi.setCoordinates(coordArray);
0975:                    gi.setCoordinateIndices(objectToIntArray(coordIdxList));
0976:                    if (textures) {
0977:                        gi.setTextureCoordinateParams(1, 2);
0978:                        gi.setTextureCoordinates(0, texArray);
0979:                        gi.setTextureCoordinateIndices(0,
0980:                                objectToIntArray(texIdxList));
0981:                    }
0982:                    if (normals) {
0983:                        gi.setNormals(normArray);
0984:                        gi.setNormalIndices(objectToIntArray(normIdxList));
0985:                    }
0986:                    gi.convertToIndexedTriangles();
0987:
0988:                    // Data is now indexed triangles.  Next step is to take the data
0989:                    // out of the GeometryInfo and put into internal data structures
0990:
0991:                    int coordIndicesArray[] = gi.getCoordinateIndices();
0992:
0993:                    // Fix for #4366060
0994:                    // Make sure triangulated geometry has the correct number of triangles
0995:                    int tris = 0;
0996:                    for (int i = 0; i < numFaces; i++)
0997:                        tris += ((Integer) stripCounts.get(i)).intValue() - 2;
0998:
0999:                    if (coordIndicesArray.length != (tris * 3)) {
1000:                        // Model contains bad polygons that didn't triangulate into the
1001:                        // correct number of triangles.  Fall back to "simple" triangulation
1002:                        triangulate = false;
1003:                    } else {
1004:
1005:                        int texIndicesArray[] = gi
1006:                                .getTextureCoordinateIndices();
1007:                        int normIndicesArray[] = gi.getNormalIndices();
1008:
1009:                        // Convert index arrays to internal ArrayList format
1010:                        coordIdxList.clear();
1011:                        texIdxList.clear();
1012:                        normIdxList.clear();
1013:                        for (int i = 0; i < coordIndicesArray.length; i++) {
1014:                            coordIdxList.add(new Integer(coordIndicesArray[i]));
1015:                            if (textures)
1016:                                texIdxList.add(new Integer(texIndicesArray[i]));
1017:                            if (normals)
1018:                                normIdxList
1019:                                        .add(new Integer(normIndicesArray[i]));
1020:                        }
1021:                    }
1022:                }
1023:
1024:                if (!triangulate) {
1025:                    newCoordIdxList = new ArrayList();
1026:                    if (textures)
1027:                        newTexIdxList = new ArrayList();
1028:                    if (normals)
1029:                        newNormIdxList = new ArrayList();
1030:                }
1031:
1032:                // Repeat for each face in the model - add the triangles from each 
1033:                // face to the Geometry and Smoothing Groups
1034:                int baseVertex = 0;
1035:                for (int f = 0; f < numFaces; f++) {
1036:                    int faceSize = ((Integer) stripCounts.get(f)).intValue();
1037:
1038:                    // Find out the name of the group to which this face belongs
1039:                    Integer curFace = new Integer(f);
1040:                    curGroup = (String) groups.get(curFace);
1041:
1042:                    // Change to a new geometry group, create if it doesn't exist
1043:                    curTriGroup = (ArrayList) triGroups.get(curGroup);
1044:                    if (curTriGroup == null) {
1045:                        curTriGroup = new ArrayList();
1046:                        triGroups.put(curGroup, curTriGroup);
1047:                    }
1048:
1049:                    // Change to a new smoothing group, create if it doesn't exist
1050:                    if (haveSgroups) {
1051:                        curSgroup = (String) sGroups.get(curFace);
1052:                        if (curSgroup == null) {
1053:                            // Weird case - this face has no smoothing group.  Happens if the
1054:                            // first 's' token comes after some faces have already been defined.
1055:                            // Assume they wanted no smoothing for these faces
1056:                            curSgroup = "0";
1057:                        }
1058:                        curTriSgroup = (ArrayList) triSgroups.get(curSgroup);
1059:                        if (curTriSgroup == null) {
1060:                            curTriSgroup = new ArrayList();
1061:                            triSgroups.put(curSgroup, curTriSgroup);
1062:                        }
1063:                    }
1064:
1065:                    if (triangulate) {
1066:
1067:                        // Each polygon of n vertices is now n-2 triangles
1068:                        for (int t = 0; t < faceSize - 2; t++) {
1069:
1070:                            // The groups just remember the first vertex of each triangle
1071:                            Integer triBaseVertex = new Integer(baseVertex);
1072:                            curTriGroup.add(triBaseVertex);
1073:                            if (haveSgroups)
1074:                                curTriSgroup.add(triBaseVertex);
1075:
1076:                            baseVertex += 3;
1077:                        }
1078:                    } else {
1079:                        // Triangulate simply
1080:                        for (int v = 0; v < faceSize - 2; v++) {
1081:                            // Add this triangle to the geometry group and the smoothing group
1082:                            Integer triBaseVertex = new Integer(newCoordIdxList
1083:                                    .size());
1084:                            curTriGroup.add(triBaseVertex);
1085:                            if (haveSgroups)
1086:                                curTriSgroup.add(triBaseVertex);
1087:
1088:                            newCoordIdxList.add(coordIdxList.get(baseVertex));
1089:                            newCoordIdxList.add(coordIdxList.get(baseVertex + v
1090:                                    + 1));
1091:                            newCoordIdxList.add(coordIdxList.get(baseVertex + v
1092:                                    + 2));
1093:
1094:                            if (textures) {
1095:                                newTexIdxList.add(texIdxList.get(baseVertex));
1096:                                newTexIdxList.add(texIdxList.get(baseVertex + v
1097:                                        + 1));
1098:                                newTexIdxList.add(texIdxList.get(baseVertex + v
1099:                                        + 2));
1100:                            }
1101:
1102:                            if (normals) {
1103:                                newNormIdxList.add(normIdxList.get(baseVertex));
1104:                                newNormIdxList.add(normIdxList.get(baseVertex
1105:                                        + v + 1));
1106:                                newNormIdxList.add(normIdxList.get(baseVertex
1107:                                        + v + 2));
1108:                            }
1109:                        }
1110:                        baseVertex += faceSize;
1111:                    }
1112:                }
1113:
1114:                // No need to keep these around
1115:                stripCounts = null;
1116:                groups = null;
1117:                sGroups = null;
1118:
1119:                if (!triangulate) {
1120:                    coordIdxList = newCoordIdxList;
1121:                    texIdxList = newTexIdxList;
1122:                    normIdxList = newNormIdxList;
1123:                }
1124:            } // End of convertToTriangles
1125:
1126:            private SceneBase makeScene() {
1127:                // Create Scene to pass back
1128:                SceneBase scene = new SceneBase();
1129:                BranchGroup group = new BranchGroup();
1130:                scene.setSceneGroup(group);
1131:
1132:                boolean gen_norms = normList.isEmpty() || normIdxList.isEmpty()
1133:                        || (normIdxList.size() != coordIdxList.size());
1134:                boolean do_tex = !texList.isEmpty() && !texIdxList.isEmpty()
1135:                        && (texIdxList.size() == coordIdxList.size());
1136:
1137:                // Convert ArrayLists to arrays
1138:                coordArray = objectToPoint3Array(coordList);
1139:                if (!gen_norms)
1140:                    normArray = objectToVectorArray(normList);
1141:                if (do_tex)
1142:                    texArray = objectToTexCoord2Array(texList);
1143:
1144:                convertToTriangles();
1145:
1146:                if ((DEBUG & 8) != 0) {
1147:                    time = System.currentTimeMillis() - time;
1148:                    System.out.println("Convert to triangles: " + time + " ms");
1149:                    time = System.currentTimeMillis();
1150:                }
1151:
1152:                if ((gen_norms) && (curSgroup != null)) {
1153:                    smoothingGroupNormals();
1154:                    gen_norms = false;
1155:                    if ((DEBUG & 8) != 0) {
1156:                        time = System.currentTimeMillis() - time;
1157:                        System.out.println("Smoothing group normals: " + time
1158:                                + " ms");
1159:                        time = System.currentTimeMillis();
1160:                    }
1161:                }
1162:
1163:                NormalGenerator ng = null;
1164:                if (gen_norms)
1165:                    ng = new NormalGenerator(radians);
1166:
1167:                Stripifier strippy = null;
1168:                if ((flags & STRIPIFY) != 0)
1169:                    strippy = new Stripifier();
1170:
1171:                long t1 = 0, t2 = 0, t3 = 0, t4 = 0;
1172:
1173:                // Each "Group" of faces in the model will be one Shape3D
1174:                Iterator e = triGroups.keySet().iterator();
1175:                while (e.hasNext()) {
1176:
1177:                    String curname = (String) e.next();
1178:                    ArrayList triList = (ArrayList) triGroups.get(curname);
1179:
1180:                    // Check for group with no faces
1181:                    if (triList.size() > 0) {
1182:
1183:                        GeometryInfo gi = new GeometryInfo(
1184:                                GeometryInfo.TRIANGLE_ARRAY);
1185:
1186:                        gi.setCoordinateIndices(groupIndices(coordIdxList,
1187:                                triList));
1188:                        gi.setCoordinates(coordArray);
1189:
1190:                        if (do_tex) {
1191:                            gi.setTextureCoordinateParams(1, 2);
1192:                            gi.setTextureCoordinates(0, texArray);
1193:                            gi.setTextureCoordinateIndices(0, groupIndices(
1194:                                    texIdxList, triList));
1195:                        }
1196:
1197:                        if ((DEBUG & 8) != 0)
1198:                            time = System.currentTimeMillis();
1199:                        if (gen_norms) {
1200:                            if ((flags & REVERSE) != 0)
1201:                                gi.reverse();
1202:                            ng.generateNormals(gi);
1203:                            if ((DEBUG & 8) != 0) {
1204:                                t2 += System.currentTimeMillis() - time;
1205:                                System.out.println("Generate normals: " + t2
1206:                                        + " ms");
1207:                                time = System.currentTimeMillis();
1208:                            }
1209:                        } else {
1210:                            gi.setNormalIndices(groupIndices(normIdxList,
1211:                                    triList));
1212:                            gi.setNormals(normArray);
1213:                            if ((flags & REVERSE) != 0)
1214:                                gi.reverse();
1215:                        }
1216:
1217:                        if ((flags & STRIPIFY) != 0) {
1218:                            strippy.stripify(gi);
1219:                            if ((DEBUG & 8) != 0) {
1220:                                t3 += System.currentTimeMillis() - time;
1221:                                System.out.println("Stripify: " + t3 + " ms");
1222:                                time = System.currentTimeMillis();
1223:                            }
1224:                        }
1225:
1226:                        // Put geometry into Shape3d
1227:                        Shape3D shape = new Shape3D();
1228:
1229:                        shape.setGeometry(gi
1230:                                .getGeometryArray(true, true, false));
1231:
1232:                        String matName = (String) groupMaterials.get(curname);
1233:                        materials.assignMaterial(matName, shape);
1234:
1235:                        group.addChild(shape);
1236:                        scene.addNamedObject(curname, shape);
1237:
1238:                        if ((DEBUG & 8) != 0) {
1239:                            t4 += System.currentTimeMillis() - time;
1240:                            System.out.println("Shape 3D: " + t4 + " ms");
1241:                            time = System.currentTimeMillis();
1242:                        }
1243:                    }
1244:                }
1245:
1246:                return scene;
1247:            } // end of makeScene
1248:
1249:            /**
1250:             * The Object File is loaded from the already opened file.
1251:             * To attach the model to your scene, call getSceneGroup() on
1252:             * the Scene object passed back, and attach the returned
1253:             * BranchGroup to your scene graph.  For an example, see 
1254:             * j3d-examples/ObjLoad/ObjLoad.java.
1255:             */
1256:            public Scene load(Reader reader) throws FileNotFoundException,
1257:                    IncorrectFormatException, ParsingErrorException {
1258:                // ObjectFileParser does lexical analysis
1259:                ObjectFileParser st = new ObjectFileParser(reader);
1260:
1261:                coordList = new ArrayList();
1262:                texList = new ArrayList();
1263:                normList = new ArrayList();
1264:                coordIdxList = new ArrayList();
1265:                texIdxList = new ArrayList();
1266:                normIdxList = new ArrayList();
1267:                groups = new HashMap(50);
1268:                curGroup = "default";
1269:                sGroups = new HashMap(50);
1270:                curSgroup = null;
1271:                stripCounts = new ArrayList();
1272:                groupMaterials = new HashMap(50);
1273:                groupMaterials.put(curGroup, "default");
1274:                materials = new ObjectFileMaterials();
1275:
1276:                time = 0L;
1277:                if ((DEBUG & 8) != 0) {
1278:                    time = System.currentTimeMillis();
1279:                }
1280:
1281:                readFile(st);
1282:
1283:                if ((DEBUG & 8) != 0) {
1284:                    time = System.currentTimeMillis() - time;
1285:                    System.out.println("Read file: " + time + " ms");
1286:                    time = System.currentTimeMillis();
1287:                }
1288:
1289:                if ((flags & RESIZE) != 0)
1290:                    resize();
1291:
1292:                return makeScene();
1293:            } // End of load(Reader)
1294:
1295:            /**
1296:             * For an .obj file loaded from a URL, set the URL where associated files
1297:             * (like material properties files) will be found.
1298:             * Only needs to be called to set it to a different URL
1299:             * from that containing the .obj file.
1300:             */
1301:            public void setBaseUrl(URL url) {
1302:                baseUrl = url;
1303:            } // End of setBaseUrl
1304:
1305:            /**
1306:             * Return the URL where files associated with this .obj file (like
1307:             * material properties files) will be found.
1308:             */
1309:            public URL getBaseUrl() {
1310:                return baseUrl;
1311:            } // End of getBaseUrl
1312:
1313:            /**
1314:             * Set the path where files associated with this .obj file are
1315:             * located.
1316:             * Only needs to be called to set it to a different directory
1317:             * from that containing the .obj file.
1318:             */
1319:            public void setBasePath(String pathName) {
1320:                basePath = pathName;
1321:                if (basePath == null || basePath == "")
1322:                    basePath = "." + java.io.File.separator;
1323:                basePath = basePath.replace('/', java.io.File.separatorChar);
1324:                basePath = basePath.replace('\\', java.io.File.separatorChar);
1325:                if (!basePath.endsWith(java.io.File.separator))
1326:                    basePath = basePath + java.io.File.separator;
1327:            } // End of setBasePath
1328:
1329:            /**
1330:             * Return the path where files associated with this .obj file (like material
1331:             * files) are located.
1332:             */
1333:            public String getBasePath() {
1334:                return basePath;
1335:            } // End of getBasePath
1336:
1337:            /**
1338:             * Set parameters for loading the model.
1339:             * Flags defined in Loader.java are ignored by the ObjectFile Loader
1340:             * because the .obj file format doesn't include lights, fog, background,
1341:             * behaviors, views, or sounds.  However, several flags are defined
1342:             * specifically for use with the ObjectFile Loader (see above).
1343:             */
1344:            public void setFlags(int flags) {
1345:                this .flags = flags;
1346:                if ((DEBUG & 4) != 0)
1347:                    System.out.println("Flags = " + flags);
1348:            } // End of setFlags
1349:
1350:            /**
1351:             * Get the parameters currently defined for loading the model.
1352:             * Flags defined in Loader.java are ignored by the ObjectFile Loader
1353:             * because the .obj file format doesn't include lights, fog, background,
1354:             * behaviors, views, or sounds.  However, several flags are defined
1355:             * specifically for use with the ObjectFile Loader (see above).
1356:             */
1357:            public int getFlags() {
1358:                return flags;
1359:            } // End of getFlags
1360:
1361:        } // End of class ObjectFile
1362:
1363:        // End of file ObjectFile.java
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.