001: /*
002: * $RCSfile: ElevationGrid.java,v $
003: *
004: * @(#)ElevationGrid.java 1.17 99/03/05 17:13:20
005: *
006: * Copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
007: *
008: * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
009: * modify and redistribute this software in source and binary code form,
010: * provided that i) this copyright notice and license appear on all copies of
011: * the software; and ii) Licensee does not utilize the software in a manner
012: * which is disparaging to Sun.
013: *
014: * This software is provided "AS IS," without a warranty of any kind. ALL
015: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
016: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
017: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
018: * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
019: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
020: * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
021: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
022: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
023: * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
024: * POSSIBILITY OF SUCH DAMAGES.
025: *
026: * This software is not designed or intended for use in on-line control of
027: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
028: * the design, construction, operation or maintenance of any nuclear
029: * facility. Licensee represents and warrants that it will not use or
030: * redistribute the Software for such purposes.
031: *
032: * $Revision: 1.2 $
033: * $Date: 2005/02/03 23:06:55 $
034: * $State: Exp $
035: */
036: /*
037: * @Author: Rick Goldberg
038: *
039: */
040: package org.jdesktop.j3d.loaders.vrml97.impl;
041:
042: import com.sun.j3d.utils.geometry.*;
043: import javax.media.j3d.*;
044: import javax.vecmath.*;
045: import vrml.InvalidVRMLSyntaxException;
046:
047: /** Description of the Class */
048: public class ElevationGrid extends Geometry implements Ownable {
049:
050: //eventIn redundant
051: //MFFloat height;
052:
053: //exposedField
054: SFNode color;
055: SFNode normal;
056: SFNode texCoord;
057: MFFloat height;
058:
059: //field
060: SFBool ccw;
061: SFBool colorPerVertex;
062: SFBool normalPerVertex;
063: SFFloat creaseAngle;
064: SFBool solid;
065: SFInt32 xDimension;
066: SFFloat xSpacing;
067: SFInt32 zDimension;
068: SFFloat zSpacing;
069:
070: // j3d info
071: GeometryArray impl;
072: GeometryInfo gi;
073: Point3f[] coordArray;
074: Color3f[] colorArray;
075: Point2f[] texCoordArray;
076: Vector3f[] normalArray;
077:
078: // vrml
079: Shape owner;
080:
081: // other
082: boolean nullable = true;
083: boolean haveTexture = false;
084:
085: /**
086: *Constructor for the ElevationGrid object
087: *
088: *@param loader Description of the Parameter
089: */
090: public ElevationGrid(Loader loader) {
091: super (loader);
092: height = new MFFloat();
093: color = new SFNode(null);
094: normal = new SFNode(null);
095: texCoord = new SFNode(null);
096: ccw = new SFBool(true);
097: colorPerVertex = new SFBool(true);
098: creaseAngle = new SFFloat(0.0f);
099: normalPerVertex = new SFBool(true);
100: solid = new SFBool(true);
101: xDimension = new SFInt32(0);
102: xSpacing = new SFFloat(1.0f);
103: zDimension = new SFInt32(0);
104: zSpacing = new SFFloat(1.0f);
105:
106: initFields();
107: }
108:
109: /**
110: *Constructor for the ElevationGrid object
111: *
112: *@param loader Description of the Parameter
113: *@param height Description of the Parameter
114: *@param color Description of the Parameter
115: *@param normal Description of the Parameter
116: *@param texCoord Description of the Parameter
117: *@param ccw Description of the Parameter
118: *@param colorPerVertex Description of the Parameter
119: *@param creaseAngle Description of the Parameter
120: *@param normalPerVertex Description of the Parameter
121: *@param solid Description of the Parameter
122: *@param xDimension Description of the Parameter
123: *@param xSpacing Description of the Parameter
124: *@param zDimension Description of the Parameter
125: *@param zSpacing Description of the Parameter
126: */
127: ElevationGrid(Loader loader, MFFloat height, SFNode color,
128: SFNode normal, SFNode texCoord, SFBool ccw,
129: SFBool colorPerVertex, SFFloat creaseAngle,
130: SFBool normalPerVertex, SFBool solid, SFInt32 xDimension,
131: SFFloat xSpacing, SFInt32 zDimension, SFFloat zSpacing) {
132: super (loader);
133: this .height = height;
134: this .color = color;
135: this .normal = normal;
136: this .texCoord = texCoord;
137: this .ccw = ccw;
138: this .colorPerVertex = colorPerVertex;
139: this .creaseAngle = creaseAngle;
140: this .normalPerVertex = normalPerVertex;
141: this .solid = solid;
142: this .xDimension = xDimension;
143: this .xSpacing = xSpacing;
144: this .zDimension = zDimension;
145: this .zSpacing = zSpacing;
146:
147: initFields();
148:
149: }
150:
151: /** Description of the Method */
152: void initImpl() {
153: // do the vrml data to j3d conversion ( initSetup() )
154: // or leave them null.
155:
156: initSetup();
157: gi = new GeometryInfo(GeometryInfo.QUAD_ARRAY);
158:
159: if (coordArray != null) {
160: gi.setCoordinates(coordArray);
161:
162: if (loader.debug) {
163: for (int i = 0; i < coordArray.length; i++) {
164: System.out.println(coordArray[i]);
165: }
166: }
167:
168: } else {
169: throw new vrml.InvalidVRMLSyntaxException(
170: "No coordinates supplied for ElevationGrid");
171: }
172:
173: if (colorArray != null) {
174: gi.setColors(colorArray);
175: // enable event mapping
176: ((Color) (color.node)).owner = this ;
177: }
178:
179: if (texCoordArray != null) {
180: gi.setTextureCoordinates(texCoordArray);
181: haveTexture = true;
182: // enable event mapping
183: ((TextureCoordinate) (texCoord.node)).owner = this ;
184: }
185:
186: if (normalArray != null) {
187: gi.setNormals(normalArray);
188: ((Normal) (normal.node)).owner = this ;
189: } else {
190: // this one has to be dealt with here since
191: // coordinates are now known to gi
192: float ca = creaseAngle.getValue();
193: if (ca < 0.0f) {
194: ca = 0.0f;
195: }
196: if (ca > (float) Math.PI) {
197: ca -= (float) Math.PI;
198: }
199: NormalGenerator ng = new NormalGenerator(ca);
200: ng.generateNormals(gi);
201: }
202:
203: impl = gi.getGeometryArray();
204:
205: // if no routes were specified at parsetime
206: // allow these to get GC'd
207: if (nullable) {
208: height = null;
209: color = null;
210: normal = null;
211: texCoord = null;
212: }
213:
214: // cleanUp null references
215: loader.cleanUp();
216: implReady = true;
217:
218: }
219:
220: // convert vrml data to j3d data
221:
222: /** Description of the Method */
223: void initSetup() {
224:
225: int xD = xDimension.getValue();
226: int zD = zDimension.getValue();
227: int quadNum = 0;
228: int quadCount = (xD - 1) * (zD - 1);
229: float[] heights = height.mfloat;
230:
231: if (loader.debug) {
232: System.out.println("X dimension" + xD);
233: System.out.println("Z dimension" + zD);
234: System.out.println("quad count" + quadCount);
235: System.out.println("height" + height);
236: for (int h = 0; h < heights.length; h++) {
237: System.out.print(heights[h] + ",");
238: }
239: }
240: if ((xD < 1) || (zD < 1)) {
241: throw new vrml.InvalidVRMLSyntaxException(
242: "ElevationGrid dimensionless");
243: }
244: if (height.mfloat.length != xD * zD) {
245: throw new vrml.InvalidVRMLSyntaxException(
246: "ElevationGrid dimension mismatch");
247: }
248:
249: // TBD, check the size of the heights. If it is really large
250: // may want to indexify the data.
251:
252: // coordArray will be passed to gi in terms of independent quads
253: coordArray = new Point3f[quadCount * 4];
254: // only used if color field exists else nullout
255: colorArray = new Color3f[quadCount * 4];
256: // only used if normal field exists else nullout
257: normalArray = new Vector3f[quadCount * 4];
258: // only used if texCoord field exists else nullout
259: texCoordArray = new Point2f[quadCount * 4];
260:
261: // reader beware: i and j are NOT the same i and j in the vrml spec
262: // rather k is j and j is i
263: for (int k = 0; k < zD - 1; k++) {
264: for (int j = 0; j < xD - 1; j++) {
265: // this steps through the dimensions, one
266: // quad at a time
267: int i = j + (k * xD);
268: Point3f p0 = new Point3f();
269: Point3f p1 = new Point3f();
270: Point3f p2 = new Point3f();
271: Point3f p3 = new Point3f();
272: float zSp = zSpacing.value;
273: float xSp = xSpacing.value;
274:
275: p0.x = (float) j * xSp;
276: p0.y = heights[i];
277: p0.z = ((float) k) * zSp;
278:
279: p1.x = (float) j * xSp;
280: p1.y = heights[i + xD];
281: p1.z = ((float) (k + 1)) * zSp;
282:
283: p2.x = ((float) (j + 1)) * xSp;
284: p2.y = heights[i + xD + 1];
285: p2.z = ((float) (k + 1)) * zSp;
286:
287: p3.x = ((float) (j + 1)) * xSp;
288: p3.y = heights[i + 1];
289: p3.z = ((float) k) * zSp;
290:
291: // fill in the coordArray
292:
293: if (ccw.value) {
294: coordArray[(quadNum * 4) + 0] = p0;
295: coordArray[(quadNum * 4) + 1] = p1;
296: coordArray[(quadNum * 4) + 2] = p2;
297: coordArray[(quadNum * 4) + 3] = p3;
298: } else {
299: coordArray[(quadNum * 4) + 0] = p0;
300: coordArray[(quadNum * 4) + 1] = p3;
301: coordArray[(quadNum * 4) + 2] = p2;
302: coordArray[(quadNum * 4) + 3] = p1;
303: }
304:
305: if (loader.debug) {
306: System.out.println("quadNum" + quadNum);
307: System.out.println("v0 "
308: + coordArray[quadNum * 4 + 0]);
309: System.out.println("v1 "
310: + coordArray[quadNum * 4 + 1]);
311: System.out.println("v2 "
312: + coordArray[quadNum * 4 + 2]);
313: System.out.println("v3 "
314: + coordArray[quadNum * 4 + 3]);
315:
316: }
317: // do the
318: // colorArray, texCoordArray, but not normalArray
319:
320: if (color.node != null) {
321: Color3f c0 = new Color3f();
322: Color3f c1 = new Color3f();
323: Color3f c2 = new Color3f();
324: Color3f c3 = new Color3f();
325: MFColor mfclr = (MFColor) (((Color) (color.node)).color);
326: float[] clrs = (float[]) (mfclr.vals);
327: if (colorPerVertex.value) {
328: // colors supplied are for each vtx
329: int ind0 = i * 3;
330: int ind1 = (i + xD) * 3;
331: int ind2 = (i + xD + 1) * 3;
332: int ind3 = (i + 1) * 3;
333:
334: // shouldn't Color3f be .r, .g, .b?
335: c0.x = clrs[ind0];
336: c0.y = clrs[ind0 + 1];
337: c0.z = clrs[ind0 + 2];
338:
339: c1.x = clrs[ind1];
340: c1.y = clrs[ind1 + 1];
341: c1.z = clrs[ind1 + 2];
342:
343: c2.x = clrs[ind2];
344: c2.y = clrs[ind2 + 1];
345: c2.z = clrs[ind2 + 2];
346:
347: c3.x = clrs[ind3];
348: c3.y = clrs[ind3 + 1];
349: c3.z = clrs[ind3 + 2];
350:
351: if (ccw.value) {
352: colorArray[(quadNum * 4) + 0] = c0;
353: colorArray[(quadNum * 4) + 1] = c1;
354: colorArray[(quadNum * 4) + 2] = c2;
355: colorArray[(quadNum * 4) + 3] = c3;
356: } else {
357: colorArray[(quadNum * 4) + 0] = c0;
358: colorArray[(quadNum * 4) + 1] = c3;
359: colorArray[(quadNum * 4) + 2] = c2;
360: colorArray[(quadNum * 4) + 3] = c1;
361: }
362:
363: } else {
364: // there are only xD-1 * zD-1 colors
365: c0.x = clrs[(quadNum * 3) + 0];
366: c0.y = clrs[(quadNum * 3) + 1];
367: c0.z = clrs[(quadNum * 3) + 2];
368:
369: colorArray[(quadNum * 4) + 0] = c0;
370: colorArray[(quadNum * 4) + 1] = c0;
371: colorArray[(quadNum * 4) + 2] = c0;
372: colorArray[(quadNum * 4) + 3] = c0;
373: }
374: } else {
375: colorArray = null;
376: }
377:
378: if (texCoord.node != null) {
379: Point2f v0 = new Point2f();
380: Point2f v1 = new Point2f();
381: Point2f v2 = new Point2f();
382: Point2f v3 = new Point2f();
383: float[] tx = (float[]) ((MFVec2f) (((TextureCoordinate) (texCoord.node)).point)).vals;
384: // texCoords are supplied per vertex
385: int ind0 = i * 2;
386: int ind1 = (i + xD) * 2;
387: int ind2 = (i + xD + 1) * 2;
388: int ind3 = (i + 1) * 2;
389: v0.x = tx[ind0];
390: v0.y = tx[ind0 + 1];
391:
392: v1.x = tx[ind1];
393: v1.y = tx[ind1 + 1];
394:
395: v2.x = tx[ind2];
396: v2.y = tx[ind2 + 1];
397:
398: v3.x = tx[ind3];
399: v3.y = tx[ind3 + 1];
400:
401: if (ccw.value) {
402: texCoordArray[(quadNum * 4) + 0] = v0;
403: texCoordArray[(quadNum * 4) + 1] = v1;
404: texCoordArray[(quadNum * 4) + 2] = v2;
405: texCoordArray[(quadNum * 4) + 3] = v3;
406: } else {
407: texCoordArray[(quadNum * 4) + 0] = v0;
408: texCoordArray[(quadNum * 4) + 1] = v3;
409: texCoordArray[(quadNum * 4) + 2] = v2;
410: texCoordArray[(quadNum * 4) + 3] = v1;
411: }
412:
413: } else {
414: texCoordArray = null;
415: }
416:
417: if (normal.node != null) {
418:
419: Vector3f v0 = new Vector3f();
420: Vector3f v1 = new Vector3f();
421: Vector3f v2 = new Vector3f();
422: Vector3f v3 = new Vector3f();
423:
424: float[] no = (float[]) ((MFVec3f) (((Normal) (normal.node)).vector)).value;
425:
426: // handle just like color
427: if (normalPerVertex.value) {
428:
429: int ind0 = i * 3;
430: int ind1 = (i + xD) * 3;
431: int ind2 = (i + xD + 1) * 3;
432: int ind3 = (i + 1) * 3;
433:
434: v0.x = no[ind0];
435: v0.y = no[ind0 + 1];
436: v0.z = no[ind0 + 2];
437:
438: v1.x = no[ind1];
439: v1.y = no[ind1 + 1];
440: v1.z = no[ind1 + 2];
441:
442: v2.x = no[ind2];
443: v2.y = no[ind2 + 1];
444: v2.z = no[ind2 + 2];
445:
446: v3.x = no[ind3];
447: v3.y = no[ind3 + 1];
448: v3.z = no[ind3 + 2];
449:
450: if (ccw.value) {
451: normalArray[(quadNum * 4) + 0] = v0;
452: normalArray[(quadNum * 4) + 1] = v1;
453: normalArray[(quadNum * 4) + 2] = v2;
454: normalArray[(quadNum * 4) + 3] = v3;
455: } else {
456: normalArray[(quadNum * 4) + 0] = v0;
457: normalArray[(quadNum * 4) + 1] = v3;
458: normalArray[(quadNum * 4) + 2] = v2;
459: normalArray[(quadNum * 4) + 3] = v1;
460: }
461:
462: } else {
463: // there are only xD-1 * zD-1 nomals, ie one per quad
464: v0.x = no[(quadNum * 3) + 0];
465: v0.y = no[(quadNum * 3) + 1];
466: v0.z = no[(quadNum * 3) + 2];
467:
468: normalArray[(quadNum * 4) + 0] = v0;
469: normalArray[(quadNum * 4) + 1] = v0;
470: normalArray[(quadNum * 4) + 2] = v0;
471: normalArray[(quadNum * 4) + 3] = v0;
472: }
473: } else {
474: normalArray = null;
475: }
476:
477: // next quadNum
478:
479: quadNum++;
480:
481: }
482: }
483: }
484:
485: /**
486: * Description of the Method
487: *
488: *@param eventInName Description of the Parameter
489: *@param time Description of the Parameter
490: */
491: public void notifyMethod(String eventInName, double time) {
492:
493: if ((eventInName.equals("route_color"))
494: || (eventInName.equals("route_normal"))
495: || (eventInName.equals("route_texCoord"))
496: || (eventInName.equals("route_height"))) {
497: impl.setCapability(GeometryArray.ALLOW_COORDINATE_WRITE);
498: impl.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
499: impl.setCapability(GeometryArray.ALLOW_NORMAL_WRITE);
500: impl.setCapability(GeometryArray.ALLOW_NORMAL_READ);
501: impl.setCapability(GeometryArray.ALLOW_TEXCOORD_WRITE);
502: impl.setCapability(GeometryArray.ALLOW_TEXCOORD_READ);
503: impl.setCapability(GeometryArray.ALLOW_COLOR_WRITE);
504: impl.setCapability(GeometryArray.ALLOW_COLOR_READ);
505:
506: ((Shape3D) (owner.implNode))
507: .setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
508: nullable = false;
509: } else if (eventInName.equals("height")
510: || eventInName.equals("color")
511: || eventInName.equals("normal")
512: || eventInName.equals("texCoord")) {
513: initImpl();
514: ((Shape3D) (owner.implNode)).setGeometry(impl);
515: }
516:
517: }
518:
519: /** Description of the Method */
520: void initFields() {
521: height.init(this , FieldSpec, Field.EXPOSED_FIELD, "height");
522: color.init(this , FieldSpec, Field.EXPOSED_FIELD, "color");
523: normal.init(this , FieldSpec, Field.EXPOSED_FIELD, "normal");
524: texCoord.init(this , FieldSpec, Field.EXPOSED_FIELD, "texCoord");
525: ccw.init(this , FieldSpec, Field.FIELD, "ccw");
526: colorPerVertex.init(this , FieldSpec, Field.FIELD,
527: "colorPerVertex");
528: creaseAngle.init(this , FieldSpec, Field.FIELD, "creaseAngle");
529: normalPerVertex.init(this , FieldSpec, Field.FIELD,
530: "normalPerVertex");
531: solid.init(this , FieldSpec, Field.FIELD, "solid");
532: xDimension.init(this , FieldSpec, Field.FIELD, "xDimension");
533: xSpacing.init(this , FieldSpec, Field.FIELD, "xSpacing");
534: zDimension.init(this , FieldSpec, Field.FIELD, "zDimension");
535: zSpacing.init(this , FieldSpec, Field.FIELD, "zSpacing");
536: }
537:
538: /**
539: * Description of the Method
540: *
541: *@return Description of the Return Value
542: */
543: public Object clone() {
544: return new ElevationGrid(loader, (MFFloat) (height.clone()),
545: (SFNode) (color.clone()), (SFNode) (normal.clone()),
546: (SFNode) (texCoord.clone()), (SFBool) (ccw.clone()),
547: (SFBool) (colorPerVertex.clone()),
548: (SFFloat) (creaseAngle.clone()),
549: (SFBool) (normalPerVertex.clone()), (SFBool) (solid
550: .clone()), (SFInt32) (xDimension.clone()),
551: (SFFloat) (xSpacing.clone()), (SFInt32) (zDimension
552: .clone()), (SFFloat) (zSpacing.clone()));
553: }
554:
555: /**
556: * Gets the type attribute of the ElevationGrid object
557: *
558: *@return The type value
559: */
560: public String getType() {
561: return "ElevationGrid";
562: }
563:
564: // must extend Geometry and implement abstracts
565:
566: /**
567: * Description of the Method
568: *
569: *@return Description of the Return Value
570: */
571: public boolean haveTexture() {
572: return haveTexture;
573: }
574:
575: /**
576: * Gets the implGeom attribute of the ElevationGrid object
577: *
578: *@return The implGeom value
579: */
580: public javax.media.j3d.Geometry getImplGeom() {
581: return impl;
582: }
583:
584: /**
585: * Gets the boundingBox attribute of the ElevationGrid object
586: *
587: *@return The boundingBox value
588: */
589: javax.media.j3d.BoundingBox getBoundingBox() {
590: javax.media.j3d.BoundingBox b;
591:
592: // create a tiny bounding box about a coordinate
593: // to seed the placement
594: Point3d epsilon = new Point3d(.000001, .000001, .000001);
595: Point3d lower = new Point3d(coordArray[0]);
596: Point3d upper = new Point3d(coordArray[0]);
597: lower.sub(epsilon);
598: upper.add(epsilon);
599:
600: b = new javax.media.j3d.BoundingBox(lower, upper);
601:
602: for (int c = 1; c < coordArray.length; c++) {
603: b.combine(new Point3d(coordArray[c]));
604: }
605: if (loader.debug) {
606: System.out.println(b);
607: }
608: return b;
609: }
610:
611: // fulfill the Ownable interface
612: /**
613: * Gets the solid attribute of the ElevationGrid object
614: *
615: *@return The solid value
616: */
617: public boolean getSolid() {
618: return solid.value;
619: }
620:
621: /**
622: * Sets the owner attribute of the ElevationGrid object
623: *
624: *@param s The new owner value
625: */
626: public void setOwner(Shape s) {
627: this.owner = s;
628: }
629:
630: }
|