Source Code Cross Referenced for NormalGenerator.java in  » 6.0-JDK-Modules » java-3d » com » sun » j3d » utils » geometry » 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.utils.geometry 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $RCSfile: NormalGenerator.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:19 $
042:         * $State: Exp $
043:         */
044:
045:        package com.sun.j3d.utils.geometry;
046:
047:        import com.sun.j3d.utils.geometry.GeometryInfo;
048:        import com.sun.j3d.utils.geometry.EdgeTable;
049:        import java.util.ArrayList;
050:        import javax.vecmath.Vector3f;
051:        import javax.vecmath.Point3f;
052:
053:        /**
054:         * The NormalGenerator utility will calculate and fill in the normals
055:         * of a GeometryInfo object.  The calculated normals are estimated based
056:         * on an analysis of the indexed coordinate information. If your data
057:         * isn't indexed, index lists will be created.<p>
058:         * <p>
059:         * If two (or more) triangles in the model share the same coordinate
060:         * index then the normal generator will attempt to generate one normal
061:         * for the vertex, resulting in a "smooth" looking surface.  If two
062:         * coordinates don't have the same index then they will have two
063:         * separate normals, even if they have the same position.  This will
064:         * result in a "crease" in your object.  If you suspect that your
065:         * data isn't properly indexed, call GeometryInfo.recomputeIndexes(). <p>
066:         * <p>
067:         * Of course, sometimes your model *has* a crease in it.  That's what
068:         * creaseAngle is.  If two triangles' normals differ by more than
069:         * creaseAngle, then the vertex will get two separate normals, creating a 
070:         * discontinuous crease in the model.  This is perfect for the edge
071:         * of a table or the corner of a cube, for instance.
072:         */
073:
074:        public class NormalGenerator {
075:
076:            private double creaseAngle;
077:            private Vector3f facetNorms[];
078:            private ArrayList tally;
079:            private GeometryInfo gi;
080:            private int coordInds[];
081:            private int normalInds[];
082:            private int colorInds[];
083:            private int texInds[][];
084:            private int stripCounts[];
085:            private static long t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0;
086:            private Triangulator tr = null;
087:            private int numTexSets;
088:
089:            // 0 - No debug info
090:            // 1 - Facet Normals
091:            // 2 - Connection info
092:            // 4 - Normals
093:            // 8 - StripCounts
094:            // 16 - Timing
095:            // 32 - Hard edges
096:            // 64 - Coordinate and normal indices
097:            // 128 - Vertex normal calculation info
098:            private static final int DEBUG = 0;
099:
100:            // Calculate the normal of each triangle in the list by finding
101:            // the cross product
102:            private void calculatefacetNorms() {
103:                Point3f coordinates[] = gi.getCoordinates();
104:                facetNorms = new Vector3f[coordInds.length / 3];
105:                Vector3f a = new Vector3f();
106:                Vector3f b = new Vector3f();
107:                if ((DEBUG & 1) != 0)
108:                    System.out.println("Facet normals:");
109:
110:                if (gi.getOldPrim() != gi.QUAD_ARRAY) {
111:                    for (int t = 0; t < coordInds.length; t += 3) {
112:                        a.sub(coordinates[coordInds[t + 2]],
113:                                coordinates[coordInds[t + 1]]);
114:                        b.sub(coordinates[coordInds[t + 0]],
115:                                coordinates[coordInds[t + 1]]);
116:                        facetNorms[t / 3] = new Vector3f();
117:                        facetNorms[t / 3].cross(a, b);
118:                        facetNorms[t / 3].normalize();
119:
120:                        if (Float.isNaN(facetNorms[t / 3].x)) {
121:                            // Normal isn't valid
122:                            facetNorms[t / 3].x = 1.0f;
123:                            facetNorms[t / 3].y = facetNorms[t / 3].z = 0.0f;
124:                        }
125:                        if ((DEBUG & 1) != 0) {
126:                            System.out.println("  " + (t / 3) + " "
127:                                    + facetNorms[t / 3]);
128:                        }
129:                    }
130:                } else {
131:                    // For quads, the facet normal of both triangles is the cross 
132:                    // product of the two vectors that make an 'X' across the quad.
133:                    for (int t = 0; t < coordInds.length; t += 6) {
134:                        a.sub(coordinates[coordInds[t + 2]],
135:                                coordinates[coordInds[t + 0]]);
136:                        b.sub(coordinates[coordInds[t + 5]],
137:                                coordinates[coordInds[t + 1]]);
138:                        facetNorms[t / 3] = new Vector3f();
139:                        facetNorms[t / 3].cross(a, b);
140:                        facetNorms[t / 3].normalize();
141:
142:                        if (Float.isNaN(facetNorms[t / 3].x)) {
143:                            // Normal isn't valid
144:                            facetNorms[t / 3].x = 1.0f;
145:                            facetNorms[t / 3].y = facetNorms[t / 3].z = 0.0f;
146:                        }
147:
148:                        // Second triangle of quad
149:                        facetNorms[t / 3 + 1] = new Vector3f(facetNorms[t / 3]);
150:
151:                        if ((DEBUG & 1) != 0) {
152:                            System.out.println("  " + (t / 3) + "&"
153:                                    + (t / 3 + 1) + " " + facetNorms[t / 3]);
154:                        }
155:                    }
156:                }
157:            } // End of calculatefacetNorms
158:
159:            // The vertex normals will be calculated by averaging the facet normals
160:            // of groups of triangles sharing the vertex.  At the end of this routine
161:            // the groups of coordinate indexes will all be made, and the normal
162:            // indices will point to these groups.
163:            // 
164:            // The routine works by going through each vertex of each triangle.
165:            // Starting at a triangle, we see if the vertex normal can be shared
166:            // with the neighbor triangle (their facet normals differ by less than
167:            // creaseAngle).  If they can be shared, then we move from that triangle
168:            // to the next and the next in a circle around the vertex.
169:            //
170:            // If we hit the edge of the model or a Hard Edge (crease) then we stop
171:            // and then try going around the vertex in the other direction.
172:            //
173:            // Each time we step from one triangle to the next around the center
174:            // vertex, the triangle is added to the group of triangles whose normals
175:            // will be averaged to make the vertex normal.
176:            // 
177:            // Returns the largest number of triangles that share a single normal.
178:            //
179:            private int createHardEdges() {
180:                EdgeTable et = new EdgeTable(coordInds);
181:                tally = new ArrayList();
182:                int normalMap[] = new int[coordInds.length];
183:                int maxShare = 1;
184:                float cosine;
185:                boolean smooth;
186:                float threshold = (float) Math.cos(creaseAngle);
187:                boolean goingRight;
188:
189:                // Set Normal Indices array values to a flag
190:                for (int c = 0; c < coordInds.length; c++)
191:                    normalMap[c] = Integer.MAX_VALUE;
192:
193:                // Cycle through each vertex
194:                for (int c = 0; c < coordInds.length; c++) {
195:                    // See if this vertex's normal has already been done
196:                    if (normalMap[c] == Integer.MAX_VALUE) {
197:                        if ((DEBUG & 32) != 0) {
198:                            System.out.println("Coordinate Index " + c
199:                                    + ": vertex " + coordInds[c]);
200:                        }
201:                        // Create a list of vertices used for calculating this normal
202:                        ArrayList sharers = new ArrayList();
203:                        tally.add(sharers);
204:                        // Put this coordinate in the list
205:                        sharers.add(new Integer(c));
206:                        // Point this coordinate's index at its list
207:                        normalMap[c] = tally.size() - 1;
208:
209:                        // First do right edge
210:                        goingRight = true;
211:                        Edge edge = new Edge(coordInds[c],
212:                                coordInds[(c + 1) % 3 == 0 ? c - 2 : c + 1]);
213:                        if ((DEBUG & 32) != 0)
214:                            System.out.println("  Right edge: " + edge);
215:
216:                        // This is how we'll know we've gone all the way around
217:                        int endVertex = coordInds[c % 3 == 0 ? c + 2 : c - 1];
218:
219:                        // Start at current triangle
220:                        int cur = c;
221:
222:                        // Proceed from one triangle to the next
223:                        do {
224:                            // Look up edge in Edge Table to find neighbor triangle
225:                            Integer tableVal = et.get(edge.v2, edge.v1);
226:                            if ((DEBUG & 32) != 0) {
227:                                System.out.println("  Search Edge: "
228:                                        + (new Edge(edge.v2, edge.v1)));
229:                            }
230:
231:                            // See if there is no triangle on the other side of this edge
232:                            if (tableVal == null) {
233:                                smooth = false;
234:                                if ((DEBUG & 32) != 0)
235:                                    System.out
236:                                            .println("    No neighboring triangle found.");
237:                            } else {
238:
239:                                int n = tableVal.intValue();
240:                                if ((DEBUG & 32) != 0) {
241:                                    System.out
242:                                            .println("    Table lookup result: "
243:                                                    + n
244:                                                    + " (vertex "
245:                                                    + coordInds[n] + ")");
246:                                    System.out.print("      Triangles "
247:                                            + (cur / 3) + " & " + (n / 3)
248:                                            + ": ");
249:                                }
250:
251:                                cosine = facetNorms[cur / 3]
252:                                        .dot(facetNorms[n / 3]);
253:                                smooth = cosine > threshold;
254:                                if (smooth) {
255:                                    // The center coordinate (c) shares the same normal in these
256:                                    // two triangles.  Find that coordinate and set its index
257:                                    // normalMap[n] = normalMap[cur];
258:                                    int centerv = (((n + 1) % 3) == 0 ? n - 2
259:                                            : n + 1);
260:                                    if (coordInds[c] != coordInds[centerv]) {
261:                                        centerv = ((n % 3) == 0 ? n + 2 : n - 1);
262:                                    }
263:
264:                                    if ((DEBUG & 32) != 0)
265:                                        System.out.println("Smooth!  Adding "
266:                                                + centerv);
267:
268:                                    if (normalMap[centerv] != Integer.MAX_VALUE) {
269:                                        smooth = false;
270:                                        if ((DEBUG & 32) != 0)
271:                                            System.out
272:                                                    .println("    Error:  Coordinate aleady has normal (bad data).");
273:                                    } else {
274:
275:                                        normalMap[centerv] = tally.size() - 1;
276:
277:                                        // Consider this triangle's facet normal when calculating the
278:                                        // vertex's normal
279:                                        sharers.add(new Integer(centerv));
280:                                        if (sharers.size() > maxShare)
281:                                            maxShare = sharers.size();
282:
283:                                        // Continue on around the vertex to the next triangle
284:                                        cur = n;
285:                                        if (goingRight)
286:                                            edge.v2 = coordInds[cur];
287:                                        else
288:                                            edge.v1 = coordInds[cur];
289:                                    }
290:                                } else if ((DEBUG & 32) != 0)
291:                                    System.out.println("Hard Edge!");
292:                            }
293:
294:                            if (!smooth && goingRight) {
295:
296:                                // We've hit an impasse going right, so now try going left
297:                                // from the original triangle
298:                                goingRight = false;
299:                                smooth = true; // Trick do loop
300:                                cur = c; // Go back to original triangle
301:
302:                                edge = new Edge(coordInds[(c % 3) == 0 ? c + 2
303:                                        : c - 1], coordInds[c]);
304:                                if ((DEBUG & 32) != 0)
305:                                    System.out.println("  Left edge: " + edge);
306:
307:                            }
308:
309:                        } while (smooth
310:                                && ((goingRight && (edge.v2 != endVertex)) || !goingRight));
311:
312:                        if (((DEBUG & 32) != 0) && goingRight
313:                                && (edge.v2 == endVertex))
314:                            System.out.println("  Went all the way around!");
315:                    }
316:                }
317:
318:                if ((DEBUG & 32) != 0) {
319:                    System.out.println("Tally:");
320:                    for (int i = 0; i < tally.size(); i++) {
321:                        System.out.print("  " + i + ": ");
322:                        ArrayList sharers = (ArrayList) (tally.get(i));
323:                        for (int j = 0; j < sharers.size(); j++) {
324:                            System.out.print(" " + sharers.get(j));
325:                        }
326:                        System.out.println();
327:                    }
328:
329:                    System.out.println("Normal Indexes:");
330:                    for (int i = 0; i < normalMap.length; i++) {
331:                        System.out.println("  " + i + ": " + normalMap[i]);
332:                    }
333:                }
334:
335:                return maxShare;
336:            } // End of createHardEdges
337:
338:            // Now take all of the triangles who share a vertex (who have
339:            // been grouped by the hard edge process) and average their facet
340:            // normals to get the vertex normal
341:            //
342:            // This routine has something of a hack in it.  We found that our
343:            // method of breaking up data into individual triangles before
344:            // calculating normals was causing a bug.  If a polygon was broken
345:            // into two triangles at a particular vertex, then that facet's 
346:            // normal would get averaged into the vertex normal *twice*,
347:            // skewing the normal toward the decomposed facet.  So what we did
348:            // was to check for duplicate facet normals as we're averaging,
349:            // not allowing the same facet normal to be counted twice.  
350:            // 
351:            // What should be done is to put the facets' normals into a separate,
352:            // indexed, table.  That way, to tell if two triangles have the
353:            // same normal, we just need to compare indexes.  This would speed up
354:            // the process of checking for duplicates.
355:            private void calculateVertexNormals(int maxShare) {
356:                Vector3f normals[];
357:                ArrayList sharers;
358:                int triangle;
359:                Vector3f fn[]; // Normals of facets joined by this vertex
360:                int fnsize; // Number of elements currently ised in fn
361:
362:                if (creaseAngle != 0.0) {
363:                    fn = new Vector3f[maxShare];
364:                    normals = new Vector3f[tally.size()];
365:                    normalInds = new int[coordInds.length];
366:                    for (int n = 0; n < tally.size(); n++) {
367:                        sharers = (ArrayList) (tally.get(n));
368:                        if ((DEBUG & 128) != 0) {
369:                            System.out.println(n + ": " + sharers.size()
370:                                    + " triangles:");
371:                        }
372:                        fnsize = 0;
373:                        normals[n] = new Vector3f();
374:                        for (int t = 0; t < sharers.size(); t++) {
375:                            int v = ((Integer) sharers.get(t)).intValue();
376:                            // See if index removed by hard edge process
377:                            if (v != -1) {
378:                                triangle = v / 3;
379:                                if (!Float.isNaN(facetNorms[triangle].x)) {
380:
381:                                    int f;
382:                                    // Don't add the same facet normal twice
383:                                    for (f = 0; f < fnsize; f++) {
384:                                        if (fn[f].equals(facetNorms[triangle]))
385:                                            break;
386:                                    }
387:
388:                                    normalInds[v] = n;
389:                                    if (f == fnsize) {
390:                                        // Didn't find this triangle's normal already in the list
391:                                        normals[n].add(facetNorms[triangle]);
392:                                        fn[fnsize++] = facetNorms[triangle];
393:                                    } else if ((DEBUG & 128) != 0) {
394:                                        System.out.println("  triangle " + t
395:                                                + " ignored.");
396:                                    }
397:                                }
398:                            }
399:                        }
400:                        normals[n].normalize();
401:                        if (Float.isNaN(normals[n].x)) {
402:                            // Normal isn't valid
403:                            normals[n].x = 1.0f;
404:                            normals[n].y = normals[n].z = 0.0f;
405:                        }
406:                        if ((DEBUG & 128) != 0) {
407:                            for (int t = 0; t < sharers.size(); t++) {
408:                                int v = ((Integer) sharers.get(t)).intValue();
409:                                if (v != -1) {
410:                                    triangle = v / 3;
411:                                    System.out.println("  "
412:                                            + facetNorms[triangle]);
413:                                }
414:                            }
415:                            System.out.println("  Result: " + normals[n]);
416:                            System.out.println();
417:                        }
418:                    }
419:                } else {
420:                    // This code renders the facet normals
421:                    normals = facetNorms;
422:
423:                    normalInds = new int[facetNorms.length * 3];
424:                    for (int i = 0; i < facetNorms.length; i++) {
425:                        normalInds[i * 3 + 0] = i;
426:                        normalInds[i * 3 + 1] = i;
427:                        normalInds[i * 3 + 2] = i;
428:                    }
429:                }
430:                gi.setNormals(normals);
431:
432:                if ((DEBUG & 4) != 0) {
433:                    System.out.println("Normals:");
434:                    for (int i = 0; i < normals.length; i++) {
435:                        System.out.println("  " + i + " " + normals[i]);
436:                    }
437:                    System.out.println("Indices:");
438:                    for (int i = 0; i < normalInds.length; i++) {
439:                        System.out.println("  " + i + " " + normalInds[i]);
440:                    }
441:                }
442:            } // End of calculateVertexNormals
443:
444:            // The original data was in quads and we converted it to triangles to
445:            // calculate the normals.  Now we are converting it back to quads.
446:            // It's a very simple algorithm.
447:            // Since both sub-triangles of a quad have the same facet normal,
448:            // there should never be a hard edge down the middle of the quad.
449:            // Therefore, the vertices of the shared edge of the two subtriangles
450:            // should have the same normal index in both triangles.
451:            private int[] triToQuadIndices(int oldList[]) {
452:                if (oldList == null)
453:                    return null;
454:
455:                int newList[] = new int[oldList.length / 6 * 4];
456:                // index list to pass back
457:                // Cycle through each pair of triangles and put them together
458:                for (int q = 0; q < oldList.length / 6; q++) {
459:                    newList[q * 4 + 0] = oldList[q * 6 + 0];
460:                    newList[q * 4 + 1] = oldList[q * 6 + 1];
461:                    newList[q * 4 + 2] = oldList[q * 6 + 2];
462:                    newList[q * 4 + 3] = oldList[q * 6 + 5];
463:                }
464:
465:                return newList;
466:            } // End of triToQuadIndices
467:
468:            // The original data was in quads.  We converted it to triangles to
469:            // calculate normals.  Now we need to convert it back to quads. 
470:            private void convertTriToQuad(GeometryInfo geom) {
471:                // Create the new arrays
472:                geom.setCoordinateIndices(triToQuadIndices(geom
473:                        .getCoordinateIndices()));
474:                geom.setColorIndices(triToQuadIndices(geom.getColorIndices()));
475:                geom
476:                        .setNormalIndices(triToQuadIndices(geom
477:                                .getNormalIndices()));
478:                int num = geom.getTexCoordSetCount();
479:                for (int i = 0; i < num; i++) {
480:                    geom.setTextureCoordinateIndices(i, triToQuadIndices(geom
481:                            .getTextureCoordinateIndices(i)));
482:                }
483:                geom.setPrimitive(gi.QUAD_ARRAY);
484:            } // End of convertTriToQuad()
485:
486:            // The original data was in fans and we converted it to triangles to
487:            // calculate the normals.  Now we are converting it back to fans.
488:            // We have already calculated the new stripCounts, so now we need
489:            // to change the index lists so they match up with the stripCounts.
490:            // It's a very simple algorithm.  The paramater oldList is the 
491:            // index list being compressed back into fans (could be coordinate,
492:            // color, normal, or texCoord indices) and numVerts is the pre-
493:            // calculated total of all entries of the stripCounts array.
494:            private int[] triToFanIndices(int sc[], int oldList[], int numVerts) {
495:                if (oldList == null)
496:                    return null;
497:
498:                int newList[] = new int[numVerts]; // index list to pass back
499:                int vert1 = 0; // 1st vertex of triangle
500:                int n = 0; // index into newList
501:                // Cycle through each fan in the new list
502:                for (int f = 0; f < sc.length; f++) {
503:                    // Copy entire first triangle into new array
504:                    newList[n++] = oldList[vert1++];
505:                    newList[n++] = oldList[vert1++];
506:                    newList[n++] = oldList[vert1++];
507:                    // Each additional triangle in the fan only needs one vertex
508:                    for (int t = 3; t < sc[f]; t++) {
509:                        newList[n++] = oldList[vert1 + 2];
510:                        vert1 += 3;
511:                    }
512:                }
513:                return newList;
514:            } // End of triToFanIndices
515:
516:            //
517:            // The original data was in fans.  We converted it to triangles to
518:            // calculate normals.  Now we need to convert it back to fans. 
519:            // The hard part is that, if we found a hard edge in the middle of
520:            // a fan, we need to split the fan into two.  To tell if there's
521:            // a hard edge there, we compare the normal indices of both
522:            // vertices comprising the edge.
523:            private void convertTriToFan(GeometryInfo geom,
524:                    int oldStripCounts[]) {
525:                int ni[] = geom.getNormalIndices();
526:
527:                //
528:                // Calculate new stripCounts array
529:                //
530:                int tri = 0; // Which triangle currently being converted
531:                ArrayList newStripCounts;
532:                newStripCounts = new ArrayList(oldStripCounts.length + 100);
533:
534:                // Use the original stripCounts array
535:                for (int f = 0; f < oldStripCounts.length; f++) {
536:                    int stripCount = 3;
537:
538:                    // Cycle through each triangle in the fan, comparing to the
539:                    // next triangle in the fan.  Compare the normal indices of
540:                    // both vertices of the edge to see if the two triangles
541:                    // can be mated
542:                    for (int t = 0; t < oldStripCounts[f] - 3; t++) {
543:                        // The first vertex of this triangle must match the first
544:                        // vertex of the next, AND the third vertex of this
545:                        // triangle must match the second vertex of the next.
546:                        if ((ni[tri * 3] == ni[(tri + 1) * 3])
547:                                && (ni[tri * 3 + 2] == ni[(tri + 1) * 3 + 1])) {
548:                            // OK to extend fan
549:                            stripCount++;
550:                        } else {
551:                            // hard edge within fan
552:                            newStripCounts.add(new Integer(stripCount));
553:                            stripCount = 3;
554:                        }
555:                        tri++;
556:                    }
557:                    tri++;
558:                    newStripCounts.add(new Integer(stripCount));
559:                }
560:
561:                // Convert from ArrayList to int[]
562:                int sc[] = new int[newStripCounts.size()];
563:                for (int i = 0; i < sc.length; i++)
564:                    sc[i] = ((Integer) newStripCounts.get(i)).intValue();
565:                newStripCounts = null;
566:
567:                //
568:                // Change the index lists so they match up with the new stripCounts
569:                //
570:
571:                // See how many vertices we'll need
572:                int c = 0;
573:                for (int i = 0; i < sc.length; i++)
574:                    c += sc[i];
575:
576:                // Create the new arrays
577:                geom.setCoordinateIndices(triToFanIndices(sc, geom
578:                        .getCoordinateIndices(), c));
579:                geom.setColorIndices(triToFanIndices(sc,
580:                        geom.getColorIndices(), c));
581:                geom.setNormalIndices(triToFanIndices(sc, geom
582:                        .getNormalIndices(), c));
583:                int num = geom.getTexCoordSetCount();
584:                for (int i = 0; i < num; i++) {
585:                    geom.setTextureCoordinateIndices(i, triToFanIndices(sc,
586:                            geom.getTextureCoordinateIndices(i), c));
587:                }
588:
589:                if ((DEBUG & 8) != 0) {
590:                    System.out.print("Old stripCounts:");
591:                    for (int i = 0; i < oldStripCounts.length; i++) {
592:                        System.out.print(" " + oldStripCounts[i]);
593:                    }
594:                    System.out.println();
595:                    System.out.print("New stripCounts:");
596:                    for (int i = 0; i < sc.length; i++) {
597:                        System.out.print(" " + sc[i]);
598:                    }
599:                    System.out.println();
600:                }
601:
602:                geom.setStripCounts(sc);
603:                geom.setPrimitive(gi.TRIANGLE_FAN_ARRAY);
604:            } // End of convertTriToFan()
605:
606:            // The original data was in strips and we converted it to triangles to
607:            // calculate the normals.  Now we are converting it back to strips.
608:            // We have already calculated the new stripCounts, so now we need
609:            // to change the index lists so they match up with the stripCounts.
610:            // It's a very simple algorithm.  The paramater oldList is the 
611:            // index list being compressed back into strips (could be coordinate,
612:            // color, normal, or texCoord indices) and numVerts is the pre-
613:            // calculated total of all entries of the stripCounts array.
614:            private int[] triToStripIndices(int sc[], int oldList[],
615:                    int numVerts) {
616:                if (oldList == null)
617:                    return null;
618:
619:                int newList[] = new int[numVerts]; // index list to pass back
620:                int vert1 = 0; // 1st vertex of triangle
621:                int n = 0; // index into newList
622:                // Cycle through each strip in the new list
623:                for (int f = 0; f < sc.length; f++) {
624:                    // Copy entire first triangle into new array
625:                    newList[n++] = oldList[vert1++];
626:                    newList[n++] = oldList[vert1++];
627:                    newList[n++] = oldList[vert1++];
628:                    // Each additional triangle in the fan only needs one vertex
629:                    for (int t = 3; t < sc[f]; t++) {
630:                        // Every other triangle has been reversed to preserve winding
631:                        newList[n++] = oldList[vert1 + 2 - (t % 2)];
632:                        vert1 += 3;
633:                    }
634:                }
635:                return newList;
636:            } // End of triToStripIndices
637:
638:            private void convertTriToStrip(GeometryInfo geom,
639:                    int oldStripCounts[]) {
640:                int ni[] = geom.getNormalIndices();
641:
642:                //
643:                // Calculate new stripCounts array
644:                //
645:                int tri = 0; // Which triangle currently being converted
646:                ArrayList newStripCounts;
647:                newStripCounts = new ArrayList(oldStripCounts.length + 100);
648:
649:                // Use the original stripCounts array
650:                for (int f = 0; f < oldStripCounts.length; f++) {
651:                    int stripCount = 3;
652:
653:                    // Cycle through each triangle in the strip, comparing to the
654:                    // next triangle in the strip.  Compare the normal indices of
655:                    // both vertices of the edge to see if the two triangles
656:                    // can be mated.
657:                    for (int t = 0; t < oldStripCounts[f] - 3; t++) {
658:                        // Every other triangle has been reversed to preserve winding
659:                        if (t % 2 == 0) {
660:                            // The middle vertex of this triangle needs to match the
661:                            // first vertex of the next, AND the third vertices of
662:                            // the two triangles must match
663:                            if ((ni[tri * 3 + 1] == ni[(tri + 1) * 3])
664:                                    && (ni[tri * 3 + 2] == ni[(tri + 1) * 3 + 2])) {
665:                                // OK to extend strip
666:                                stripCount++;
667:                            } else {
668:                                // hard edge within strip
669:                                newStripCounts.add(new Integer(stripCount));
670:                                stripCount = 3;
671:
672:                                // Can't start a new strip on an odd edge so output
673:                                // isolated triangle
674:                                if (t < oldStripCounts[f] - 4) {
675:                                    newStripCounts.add(new Integer(3));
676:                                    t++;
677:                                }
678:                            }
679:                        } else {
680:                            // The middle vertex of this triangle must match the middle 
681:                            // vertex of the next, AND the third vertex of this triangle
682:                            // must match the first vertex of the next
683:                            if ((ni[tri * 3 + 1] == ni[(tri + 1) * 3 + 1])
684:                                    && (ni[tri * 3 + 2] == ni[(tri + 1) * 3])) {
685:                                // OK to extend strip
686:                                stripCount++;
687:                            } else {
688:                                // hard edge within strip
689:                                newStripCounts.add(new Integer(stripCount));
690:                                stripCount = 3;
691:                            }
692:                        }
693:                        tri++;
694:                    }
695:                    tri++;
696:                    newStripCounts.add(new Integer(stripCount));
697:                }
698:
699:                // Convert from ArrayList to int[]
700:                int sc[] = new int[newStripCounts.size()];
701:                for (int i = 0; i < sc.length; i++)
702:                    sc[i] = ((Integer) newStripCounts.get(i)).intValue();
703:                newStripCounts = null;
704:
705:                //
706:                // Change the index lists so they match up with the new stripCounts
707:                //
708:
709:                // See how many vertices we'll need
710:                int c = 0;
711:                for (int i = 0; i < sc.length; i++)
712:                    c += sc[i];
713:
714:                // Create the new arrays
715:                geom.setCoordinateIndices(triToStripIndices(sc, geom
716:                        .getCoordinateIndices(), c));
717:                geom.setColorIndices(triToStripIndices(sc, geom
718:                        .getColorIndices(), c));
719:                geom.setNormalIndices(triToStripIndices(sc, geom
720:                        .getNormalIndices(), c));
721:                int num = geom.getTexCoordSetCount();
722:                for (int i = 0; i < num; i++) {
723:                    geom.setTextureCoordinateIndices(i, triToStripIndices(sc,
724:                            geom.getTextureCoordinateIndices(i), c));
725:                }
726:
727:                if ((DEBUG & 8) != 0) {
728:                    System.out.print("Old stripCounts:");
729:                    for (int i = 0; i < oldStripCounts.length; i++) {
730:                        System.out.print(" " + oldStripCounts[i]);
731:                    }
732:                    System.out.println();
733:                    System.out.print("New stripCounts:");
734:                    for (int i = 0; i < sc.length; i++) {
735:                        System.out.print(" " + sc[i]);
736:                    }
737:                    System.out.println();
738:                }
739:
740:                geom.setStripCounts(sc);
741:                geom.setPrimitive(gi.TRIANGLE_STRIP_ARRAY);
742:            }// End of convertTriToStrip()
743:
744:            /**
745:             * Used when the user calls the NormalGenerator and not
746:             * the Stripifier or Triangulator.   We had to convert
747:             * the user's data to indexed triangles before we could
748:             * generate normals, so now we need to switch back to
749:             * the original format.
750:             */
751:            void convertBackToOldPrim(GeometryInfo geom, int oldPrim,
752:                    int oldStripCounts[]) {
753:                if (oldPrim == geom.TRIANGLE_ARRAY)
754:                    return;
755:
756:                switch (oldPrim) {
757:                case GeometryInfo.QUAD_ARRAY:
758:                    convertTriToQuad(geom);
759:                    break;
760:                case GeometryInfo.TRIANGLE_FAN_ARRAY:
761:                    convertTriToFan(geom, oldStripCounts);
762:                    break;
763:                case GeometryInfo.TRIANGLE_STRIP_ARRAY:
764:                    convertTriToStrip(geom, oldStripCounts);
765:                    break;
766:                }
767:
768:                if ((DEBUG & 64) != 0) {
769:                    System.out
770:                            .println("Coordinate and normal indices (original):");
771:                    for (int i = 0; i < coordInds.length; i++) {
772:                        System.out.println(i + "  " + coordInds[i] + "  "
773:                                + normalInds[i]);
774:                    }
775:                }
776:            } // End of convertBackToOldPrim
777:
778:            /**
779:             * Generate normals for the GeometryInfo object.  If the GeometryInfo
780:             * object didn't previously contain indexed data, indexes are made
781:             * by collapsing identical positions into a single index.  Any
782:             * normal information previously contained in the GeometryInfo 
783:             * object is lost.  Strips and Fans are converted into individual
784:             * triangles for Normal generation, but are stitched back together
785:             * if GeometryInfo.getGeometryArray() (or getIndexedGeometryArray())
786:             * is called without stripifying first.
787:             */
788:            public void generateNormals(GeometryInfo geom) {
789:                gi = geom;
790:                gi.setNormals((Vector3f[]) null);
791:                gi.setNormalIndices(null);
792:
793:                long time = 0L;
794:                if ((DEBUG & 16) != 0) {
795:                    time = System.currentTimeMillis();
796:                }
797:
798:                if (gi.getPrimitive() == gi.POLYGON_ARRAY) {
799:                    if (tr == null)
800:                        tr = new Triangulator();
801:                    tr.triangulate(gi);
802:                } else {
803:                    // NOTE:  We should calculate facet normals before converting to
804:                    // triangles.
805:                    gi.rememberOldPrim();
806:                    gi.convertToIndexedTriangles();
807:                }
808:
809:                // Cache some of the GeometryInfo fields
810:                coordInds = gi.getCoordinateIndices();
811:                colorInds = gi.getColorIndices();
812:                normalInds = gi.getNormalIndices();
813:                numTexSets = gi.getTexCoordSetCount();
814:                texInds = new int[numTexSets][];
815:                for (int i = 0; i < numTexSets; i++) {
816:                    texInds[i] = gi.getTextureCoordinateIndices(i);
817:                }
818:                stripCounts = gi.getStripCounts();
819:
820:                if ((DEBUG & 16) != 0) {
821:                    t1 += System.currentTimeMillis() - time;
822:                    System.out.println("Convert to triangles: " + t1 + " ms");
823:                    time = System.currentTimeMillis();
824:                }
825:
826:                calculatefacetNorms();
827:                if ((DEBUG & 16) != 0) {
828:                    t2 += System.currentTimeMillis() - time;
829:                    System.out
830:                            .println("Calculate Facet Normals: " + t2 + " ms");
831:                    time = System.currentTimeMillis();
832:                }
833:
834:                int maxShare = createHardEdges();
835:                if ((DEBUG & 16) != 0) {
836:                    t3 += System.currentTimeMillis() - time;
837:                    System.out.println("Hard Edges: " + t3 + " ms");
838:                    time = System.currentTimeMillis();
839:                }
840:
841:                calculateVertexNormals(maxShare);
842:                if ((DEBUG & 16) != 0) {
843:                    t5 += System.currentTimeMillis() - time;
844:                    System.out.println("Vertex Normals: " + t5 + " ms");
845:                    time = System.currentTimeMillis();
846:                }
847:
848:                if ((DEBUG & 64) != 0) {
849:                    System.out
850:                            .println("Coordinate and normal indices (triangles):");
851:                    for (int i = 0; i < coordInds.length; i++) {
852:                        System.out.println(i + "  " + coordInds[i] + "  "
853:                                + normalInds[i]);
854:                    }
855:                }
856:
857:                // We have been caching some info from the GeometryInfo, so we need
858:                // to update it.
859:                gi.setCoordinateIndices(coordInds);
860:                gi.setColorIndices(colorInds);
861:                gi.setNormalIndices(normalInds);
862:                for (int i = 0; i < numTexSets; i++) {
863:                    gi.setTextureCoordinateIndices(i, texInds[i]);
864:                }
865:                gi.setStripCounts(stripCounts);
866:            } // End of generateNormals
867:
868:            /**
869:             * Set the crease angle.  
870:             * If two triangles' normals differ by more than
871:             * creaseAngle, then the vertex will get two separate normals, creating a 
872:             * discontinuous crease in the model.  This is perfect for the edge
873:             * of a table or the corner of a cube, for instance.  Clamped to
874:             * 0 <= creaseAngle <= PI.  Optimizations are made for creaseAngle == 0
875:             * (facet normals) and creaseAngle == PI (smooth shading).
876:             */
877:            public void setCreaseAngle(double radians) {
878:                if (radians > Math.PI)
879:                    radians = Math.PI;
880:                if (radians < 0.0)
881:                    radians = 0.0;
882:                creaseAngle = radians;
883:            } // End of setCreaseAngle
884:
885:            /**
886:             * Returns the current value of the crease angle, in radians.
887:             */
888:            public double getCreaseAngle() {
889:                return creaseAngle;
890:            } // End of getCreaseAngle
891:
892:            /**
893:             * Constructor.  Construct a NormalGenerator object with creaseAngle
894:             * set to the given value.
895:             */
896:            public NormalGenerator(double radians) {
897:                creaseAngle = radians;
898:            } // End of NormalGenerator(double)
899:
900:            /**
901:             * Constructor.  Construct a NormalGenerator object with creaseAngle
902:             * set to 44 degrees (0.767944871 radians).
903:             */
904:            public NormalGenerator() {
905:                this (44.0 * Math.PI / 180.0);
906:            } // End of NormalGenerator()
907:        } // End of class NormalGenerator
908:
909:        // End of file NormalGenerator.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.