001: /*
002: * $RCSfile: J3dLwoParser.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.4 $
041: * $Date: 2007/02/09 17:20:07 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.loaders.lw3d;
046:
047: import java.awt.Component;
048: import java.awt.Image;
049: import java.util.Enumeration;
050: import java.util.Vector;
051: import com.sun.j3d.utils.geometry.GeometryInfo;
052: import com.sun.j3d.utils.geometry.NormalGenerator;
053: import com.sun.j3d.utils.geometry.Stripifier;
054: import com.sun.j3d.utils.image.TextureLoader;
055: import com.sun.j3d.loaders.IncorrectFormatException;
056: import java.io.FileNotFoundException;
057:
058: import javax.media.j3d.*;
059: import javax.vecmath.*;
060:
061: import java.net.*;
062:
063: /**
064: * This class is responsible for turning Lightwave geometry data into
065: * Java3D geometry. It is a subclass of LwoObject and calls that
066: * superclass when first instantiated to parse the binary file and turn it
067: * into intermediate data structures. J3dLwoParser then goes through
068: * those data structures and turns them into Java3D objects. For each
069: * ShapeHolder object created by the parent class, this class retrieves
070: * the geometry data and associated surface data, creates the
071: * appropriate Geometry object (usually IndexedTriangleFanArray,
072: * unless the object is points or lines), including calculating normals for
073: * the polygons and sets up the Appearance according to the surface
074: * parameters (including calculating texture coordinates if necessary).
075: */
076:
077: class J3dLwoParser extends LwoParser {
078:
079: float normalCoordsArray[];
080: int normalIndicesArray[];
081: Shape3D objectShape;
082: Color3f color, diffuseColor, specularColor, emissiveColor;
083: float shininess;
084: Vector objectShapeList = new Vector();
085:
086: /**
087: * Constructor: Calls LwoObject to parse file and create data structures
088: */
089: J3dLwoParser(String fileName, int debugVals)
090: throws FileNotFoundException {
091: super (fileName, debugVals);
092: }
093:
094: J3dLwoParser(URL url, int debugVals) throws FileNotFoundException {
095: super (url, debugVals);
096: }
097:
098: void getSurf(int length) throws FileNotFoundException {
099: super .getSurf(length);
100: }
101:
102: /**
103: * Turns LwoObject's data structures (created from the binary geometry
104: * file) into Java3d objects
105: */
106: void createJava3dGeometry() throws IncorrectFormatException {
107:
108: GeometryArray object;
109: LwoTexture texture;
110:
111: for (Enumeration e = shapeList.elements(); e.hasMoreElements();) {
112: int vertexFormat = javax.media.j3d.GeometryArray.COORDINATES;
113: ShapeHolder shape = (ShapeHolder) e.nextElement();
114: debugOutputLn(LINE_TRACE,
115: "about to create Arrays for Shape");
116: debugOutputLn(VALUES, "shape = " + shape);
117: shape.createArrays(true);
118: int vertexCount = shape.coordsArray.length / 3;
119: int indexCount = 0;
120: if (shape.facetIndices != null)
121: indexCount = shape.facetIndices.length;
122: debugOutputLn(VALUES, "numSurf = " + shape.numSurf);
123: // Find the right surface. Note: surfaces are indexed by
124: // name. So take this surf number, look up the name of that
125: // surface in surfaceNameList, then take that name and
126: // find the matching LwoSurface
127: String surfName = (String) surfNameList
128: .elementAt(shape.numSurf - 1);
129: LwoSurface surf = null;
130: for (int surfNum = 0; surfNum < surfaceList.size(); ++surfNum) {
131: LwoSurface tempSurf = (LwoSurface) surfaceList
132: .elementAt(surfNum);
133: String tempSurfName = tempSurf.surfName;
134: if (surfName.equals(tempSurfName)) {
135: surf = tempSurf;
136: break;
137: }
138: }
139: if (surf == null) {
140: throw new IncorrectFormatException(
141: "bad surf for surfnum/name = " + shape.numSurf
142: + ", " + surfName);
143: }
144: debugOutputLn(VALUES, "surf = " + surf);
145:
146: // Get the LwoTexture object (if any) for the surface
147: texture = surf.getTexture();
148:
149: Appearance appearance = new Appearance();
150: if (shape.facetSizes[0] == 1) {
151: // This case happens if the objects are points
152: // Note that points are colored, not lit
153: object = new javax.media.j3d.PointArray(vertexCount,
154: vertexFormat);
155: object.setCoordinates(0, shape.coordsArray);
156: ColoringAttributes colorAtt = new ColoringAttributes(
157: surf.getColor(), ColoringAttributes.FASTEST);
158: PointAttributes pointStyle = new PointAttributes();
159: pointStyle.setPointSize(1);
160:
161: appearance.setColoringAttributes(colorAtt);
162: appearance.setPointAttributes(pointStyle);
163: } else if (shape.facetSizes[0] == 2) {
164: // This case happens if the objects are lines
165: // Note that lines are colored, not lit
166: debugOutputLn(LINE_TRACE, "Creating IndexedLineArray");
167: object = new javax.media.j3d.LineArray(vertexCount,
168: vertexFormat);
169: object.setCoordinates(0, shape.coordsArray);
170: ColoringAttributes colorAtt = new ColoringAttributes(
171: surf.getColor(), ColoringAttributes.FASTEST);
172: appearance.setColoringAttributes(colorAtt);
173: } else {
174: // This is the case for any polygonal objects
175: debugOutputLn(LINE_TRACE, "Creating IndexedTriFanArray");
176: // create triFanArray
177: vertexFormat |= javax.media.j3d.GeometryArray.NORMALS;
178:
179: debugOutputLn(LINE_TRACE,
180: "about to process vertices/indices, facetIndices = "
181: + shape.facetIndices);
182: if (shape.facetIndices != null) {
183: float[] textureCoords = null;
184: int[] textureIndices = null;
185:
186: debugOutputLn(LINE_TRACE,
187: "setting vertexCount, normind = "
188: + shape.normalIndices);
189: // If these are null we're going direct (non-indexed)
190: debugOutputLn(LINE_TRACE,
191: "vtxcount, format, indcount = "
192: + vertexCount + ", " + vertexFormat
193: + ", " + indexCount);
194: if (texture != null) {
195: // There's a texture here - need to create the appropriate arrays
196: // and calculate texture coordinates for the object
197: vertexFormat |= GeometryArray.TEXTURE_COORDINATE_2;
198: textureCoords = new float[vertexCount * 2];
199: textureIndices = new int[shape.facetIndices.length];
200: calculateTextureCoords(texture,
201: shape.coordsArray, shape.facetIndices,
202: textureCoords, textureIndices);
203: debugOutputLn(LINE_TRACE, "textureCoords:");
204: debugOutputLn(LINE_TRACE,
205: "texture Coords, Indices.length = "
206: + textureCoords.length + ", "
207: + textureIndices.length);
208: }
209: debugOutputLn(LINE_TRACE,
210: "about to create GeometryInfo");
211:
212: // Use the GeometryInfo utility to calculate smooth normals
213: GeometryInfo gi = new GeometryInfo(
214: GeometryInfo.TRIANGLE_FAN_ARRAY);
215: gi.setCoordinates(shape.coordsArray);
216: gi.setCoordinateIndices(shape.facetIndices);
217: gi.setStripCounts(shape.facetSizes);
218: if (texture != null) {
219: gi.setTextureCoordinateParams(1, 2);
220: gi.setTextureCoordinates(0, textureCoords);
221: gi.setTextureCoordinateIndices(0,
222: textureIndices);
223: }
224: gi.recomputeIndices();
225: NormalGenerator ng = new NormalGenerator(surf
226: .getCreaseAngle());
227: ng.generateNormals(gi);
228: Stripifier st = new Stripifier();
229: st.stripify(gi);
230: object = gi.getGeometryArray(true, true, false);
231: debugOutputLn(LINE_TRACE, "done.");
232: } else {
233: // This case is called if LwoObject did not create facet
234: // indices. This code is not currently used because facet
235: // indices are always created for polygonal objects
236: debugOutputLn(LINE_TRACE,
237: "about to create trifanarray with "
238: + "vertexCount, facetSizes.len = "
239: + vertexCount + ", "
240: + shape.facetSizes.length);
241: object = new javax.media.j3d.TriangleFanArray(
242: vertexCount, vertexFormat, shape.facetSizes);
243: object.setCoordinates(0, shape.coordsArray);
244: object.setNormals(0, shape.normalCoords);
245: debugOutputLn(VALUES,
246: "passed in normalCoords, length = "
247: + shape.normalCoords.length);
248: }
249: debugOutputLn(LINE_TRACE, "created fan array");
250:
251: // Setup Appearance given the surface parameters
252: Material material = new Material(surf.getColor(), surf
253: .getEmissiveColor(), surf.getDiffuseColor(),
254: surf.getSpecularColor(), surf.getShininess());
255: material.setLightingEnable(true);
256: appearance.setMaterial(material);
257: if (surf.getTransparency() != 0f) {
258: TransparencyAttributes ta = new TransparencyAttributes();
259: ta.setTransparency(surf.getTransparency());
260: ta.setTransparencyMode(ta.BLENDED);
261: appearance.setTransparencyAttributes(ta);
262: }
263: if (texture != null) {
264: debugOutputLn(LINE_TRACE,
265: "texture != null, enable texturing");
266: Texture tex = texture.getTexture();
267: tex.setEnable(true);
268: appearance.setTexture(tex);
269: TextureAttributes ta = new TextureAttributes();
270: if (texture.getType().equals("DTEX"))
271: ta.setTextureMode(TextureAttributes.MODULATE);
272: else if (texture.getType().equals("CTEX"))
273: ta.setTextureMode(TextureAttributes.DECAL);
274: appearance.setTextureAttributes(ta);
275: } else {
276: debugOutputLn(LINE_TRACE,
277: "texture == null, no texture to use");
278: }
279: }
280: debugOutputLn(LINE_TRACE, "done creating object");
281:
282: // This does gc
283: shape.nullify();
284:
285: objectShape = new Shape3D(object);
286:
287: // Combine the appearance and geometry
288: objectShape.setAppearance(appearance);
289: objectShapeList.addElement(objectShape);
290: }
291: }
292:
293: /**
294: * Calculate texture coordinates for the geometry given the texture
295: * map properties specified in the LwoTexture object
296: */
297: void calculateTextureCoords(LwoTexture texture, float verts[],
298: int indices[], float[] textureCoords, int[] textureIndices) {
299:
300: /*
301: the actual math in these coord calculations comes directly from
302: Newtek - they posted sample code to help compute tex coords based
303: on the type of mapping:
304:
305: Here are some simplified code fragments showing how LightWave
306: computes UV coordinates from X, Y, and Z. If the resulting
307: UV coordinates are not in the range from 0 to 1, the
308: appropriate integer should be added to them to bring them into
309: that range (the fract function should have accomplished
310: this by subtracting the floor of each number from itself).
311: Then they can be multiplied by the width and height (in pixels)
312: of an image map to determine which pixel to look up. The
313: texture size, center, and tiling parameters are taken right
314: off the texture control panel.
315:
316:
317: x -= xTextureCenter;
318: y -= yTextureCenter;
319: z -= zTextureCenter;
320: if (textureType == TT_PLANAR) {
321: s = (textureAxis == TA_X) ? z / zTextureSize + .5 :
322: x / xTextureSize + .5;
323: t = (textureAxis == TA_Y) ? -z / zTextureSize + .5 :
324: -y / yTextureSize + .5;
325: u = fract(s);
326: v = fract(t);
327: }
328: else if (type == TT_CYLINDRICAL) {
329: if (textureAxis == TA_X) {
330: xyztoh(z,x,-y,&lon);
331: t = -x / xTextureSize + .5;
332: }
333: else if (textureAxis == TA_Y) {
334: xyztoh(-x,y,z,&lon);
335: t = -y / yTextureSize + .5;
336: }
337: else {
338: xyztoh(-x,z,-y,&lon);
339: t = -z / zTextureSize + .5;
340: }
341: lon = 1.0 - lon / TWOPI;
342: if (widthTiling != 1.0)
343: lon = fract(lon) * widthTiling;
344: u = fract(lon);
345: v = fract(t);
346: }
347: else if (type == TT_SPHERICAL) {
348: if (textureAxis == TA_X)
349: xyztohp(z,x,-y,&lon,&lat);
350: else if (textureAxis == TA_Y)
351: xyztohp(-x,y,z,&lon,&lat);
352: else
353: xyztohp(-x,z,-y,&lon,&lat);
354: lon = 1.0 - lon / TWOPI;
355: lat = .5 - lat / PI;
356: if (widthTiling != 1.0)
357: lon = fract(lon) * widthTiling;
358: if (heightTiling != 1.0)
359: lat = fract(lat) * heightTiling;
360: u = fract(lon);
361: v = fract(lat);
362: }
363:
364: support functions:
365:
366: void xyztoh(float x,float y,float z,float *h)
367: {
368: if (x == 0.0 && z == 0.0)
369: *h = 0.0;
370: else {
371: if (z == 0.0)
372: *h = (x < 0.0) ? HALFPI : -HALFPI;
373: else if (z < 0.0)
374: *h = -atan(x / z) + PI;
375: else
376: *h = -atan(x / z);
377: }
378: }
379:
380: void xyztohp(float x,float y,float z,float *h,float *p)
381: {
382: if (x == 0.0 && z == 0.0) {
383: *h = 0.0;
384: if (y != 0.0)
385: *p = (y < 0.0) ? -HALFPI : HALFPI;
386: else
387: *p = 0.0;
388: }
389: else {
390: if (z == 0.0)
391: *h = (x < 0.0) ? HALFPI : -HALFPI;
392: else if (z < 0.0)
393: *h = -atan(x / z) + PI;
394: else
395: *h = -atan(x / z);
396: x = sqrt(x * x + z * z);
397: if (x == 0.0)
398: *p = (y < 0.0) ? -HALFPI : HALFPI;
399: else
400: *p = atan(y / x);
401: }
402: }
403: */
404:
405: debugOutputLn(TRACE, "calculateTextureCoords()");
406: // Compute texture coord stuff
407: float sx = 0, sz = 0, ty = 0, tz = 0;
408: double s, t;
409: int textureAxis = texture.getTextureAxis();
410: Vector3f textureSize = texture.getTextureSize();
411: Vector3f textureCenter = texture.getTextureCenter();
412:
413: String mappingType = texture.getMappingType();
414: if (mappingType.startsWith("Cylindrical"))
415: calculateCylindricalTextureCoords(textureAxis, textureSize,
416: textureCenter, textureCoords, textureIndices,
417: verts, indices);
418: else if (mappingType.startsWith("Spherical"))
419: calculateSphericalTextureCoords(textureAxis, textureCenter,
420: textureCoords, textureIndices, verts, indices);
421: else if (mappingType.startsWith("Planar"))
422: calculatePlanarTextureCoords(textureAxis, textureSize,
423: textureCenter, textureCoords, textureIndices,
424: verts, indices);
425:
426: }
427:
428: /** See the comments in calculateTextureCoordinates*/
429: double xyztoh(float x, float y, float z) {
430: if (x == 0.0 && z == 0.0)
431: return 0.0;
432: else {
433: if (z == 0.0)
434: return (x < 0.0) ? Math.PI / 2.0 : -Math.PI / 2.0;
435: else if (z < 0.0)
436: return -Math.atan(x / z) + Math.PI;
437: else
438: return -Math.atan(x / z);
439: }
440: }
441:
442: /** See the comments in calculateTextureCoordinates*/
443: double xyztop(float x, float y, float z) {
444: double p;
445:
446: if (x == 0.0 && z == 0.0) {
447: if (y != 0.0)
448: p = (y < 0.0) ? -Math.PI / 2 : Math.PI / 2;
449: else
450: p = 0.0;
451: } else {
452: x = (float) Math.sqrt(x * x + z * z);
453: if (x == 0.0)
454: p = (y < 0.0) ? -Math.PI / 2 : Math.PI / 2;
455: else
456: p = Math.atan(y / x);
457: }
458: return p;
459: }
460:
461: /** See the comments in calculateTextureCoordinates*/
462: void calculateSphericalTextureCoords(int textureAxis,
463: Vector3f textureCenter, float textureCoords[],
464: int textureIndices[], float verts[], int indices[]) {
465: debugOutputLn(TRACE, "calculateSphericalTextureCoords");
466: double s, t;
467:
468: for (int i = 0; i < indices.length; ++i) {
469: float x = verts[3 * indices[i]] - textureCenter.x;
470: float y = verts[3 * indices[i] + 1] - textureCenter.y;
471: float z = -(verts[3 * indices[i] + 2] + textureCenter.z);
472: if (textureAxis == 1) { // X Axis
473: s = xyztoh(z, x, -y);
474: t = xyztop(z, x, -y);
475: } else if (textureAxis == 2) { // Y Axis
476: s = xyztoh(-x, y, z);
477: t = xyztop(-x, y, z);
478: } else { // Z Axis
479: s = xyztoh(-x, z, -y);
480: t = xyztop(-x, z, -y);
481: }
482: s = 1.0 - s / (2 * Math.PI);
483: t = -(.5 - t / Math.PI);
484: textureCoords[indices[i] * 2] = (float) s;
485: textureCoords[indices[i] * 2 + 1] = (float) t;
486: textureIndices[i] = indices[i];
487: }
488: }
489:
490: /** See the comments in calculateTextureCoordinates*/
491: void calculateCylindricalTextureCoords(int textureAxis,
492: Vector3f textureSize, Vector3f textureCenter,
493: float textureCoords[], int textureIndices[], float verts[],
494: int indices[]) {
495: debugOutputLn(TRACE, "calculateCylindricalTextureCoords");
496: debugOutputLn(VALUES, "axis, size, center, tc, ti, v, i = "
497: + textureAxis + ", " + textureSize + ", "
498: + textureCenter + ", " + textureCoords + ", "
499: + textureIndices + ", " + verts + ", " + indices);
500: double s, t;
501:
502: debugOutputLn(VALUES, "Cyl Texture Coords:");
503: for (int i = 0; i < indices.length; ++i) {
504: float x = verts[3 * indices[i]] - textureCenter.x;
505: float y = verts[3 * indices[i] + 1] - textureCenter.y;
506: float z = -(verts[3 * indices[i] + 2] + textureCenter.z);
507: // Negate z value because we invert geom z's to swap handedness
508: if (textureAxis == 1) { // X axis
509: s = xyztoh(z, x, -y);
510: t = x / textureSize.x + .5;
511: } else if (textureAxis == 2) { // Y Axis
512: s = xyztoh(-x, y, z);
513: t = y / textureSize.y + .5;
514: } else {
515: s = xyztoh(-x, z, -y);
516: t = z / textureSize.z + .5;
517: }
518: s = 1.0 - s / (2 * Math.PI);
519: textureCoords[indices[i] * 2] = (float) s;
520: textureCoords[indices[i] * 2 + 1] = (float) t;
521: textureIndices[i] = indices[i];
522: debugOutputLn(VALUES, "x, y, z = " + x + ", " + y + ", "
523: + z + " " + "s, t = " + s + ", " + t);
524: }
525: }
526:
527: /** See the comments in calculateTextureCoordinates*/
528: void calculatePlanarTextureCoords(int textureAxis,
529: Vector3f textureSize, Vector3f textureCenter,
530: float textureCoords[], int textureIndices[], float verts[],
531: int indices[]) {
532: debugOutputLn(TRACE, "calculatePlanarTextureCoords");
533: debugOutputLn(VALUES, "size, center, axis = " + textureSize
534: + textureCenter + ", " + textureAxis);
535: float sx = 0, sz = 0, ty = 0, tz = 0;
536: double s, t;
537:
538: if (textureAxis == 1) { // X Axis
539: sz = -1.0f / textureSize.z; // Negate because we negate z in geom
540: ty = 1.0f / textureSize.y;
541: } else if (textureAxis == 2) { // Y Axis
542: sx = 1.0f / textureSize.x;
543: tz = -1.0f / textureSize.z; // Negate because we negate z in geom
544: } else { // Z Axis
545: sx = 1.0f / textureSize.x;
546: ty = 1.0f / textureSize.y;
547: }
548:
549: debugOutputLn(VALUES, "Planar Texture Coords:");
550: for (int i = 0; i < indices.length; ++i) {
551: float x = verts[3 * indices[i]] - textureCenter.x;
552: float y = verts[3 * indices[i] + 1] - textureCenter.y;
553: float z = verts[3 * indices[i] + 2] + textureCenter.z;
554: s = x * sx + z * sz + .5;
555: t = y * ty + z * tz + .5;
556: textureCoords[indices[i] * 2] = (float) s;
557: textureCoords[indices[i] * 2 + 1] = (float) t;
558: textureIndices[i] = indices[i];
559: debugOutputLn(VALUES, "x, y, z = " + x + ", " + y + ", "
560: + z + " " + "s, t = " + s + ", " + t);
561: }
562: }
563:
564: Shape3D getJava3dShape() {
565: return objectShape;
566: }
567:
568: Vector getJava3dShapeList() {
569: return objectShapeList;
570: }
571:
572: }
|