001: /*
002: * $RCSfile: Background.java,v $
003: *
004: * @(#)Background.java 1.33 99/02/20 16:05:38
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:51 $
034: * $State: Exp $
035: */
036: /*
037: *
038: * @Author: Rick Goldberg
039: * @Author: Doug Gehringer
040: */
041: package org.jdesktop.j3d.loaders.vrml97.impl;
042:
043: import java.awt.*;
044: import java.awt.image.*;
045: import javax.media.j3d.BoundingSphere;
046: import javax.media.j3d.Bounds;
047: import javax.media.j3d.BranchGroup;
048: import javax.media.j3d.ImageComponent;
049: import javax.media.j3d.ImageComponent2D;
050: import javax.media.j3d.PolygonAttributes;
051: import javax.media.j3d.Texture;
052: import javax.media.j3d.Texture2D;
053:
054: import javax.vecmath.Point3d;
055:
056: /** Description of the Class */
057: public class Background extends BindableNode {
058:
059: // from BindableNode
060: // eventIn SFBool bind
061: // eventOut SFTime bindTime;
062: // eventOut SFBool isBound;
063:
064: // exposedField
065: MFFloat groundAngle;
066: MFColor groundColor;
067: MFString backUrl;
068: MFString bottomUrl;
069: MFString frontUrl;
070: MFString leftUrl;
071: MFString rightUrl;
072: MFString topUrl;
073: MFFloat skyAngle;
074: MFColor skyColor;
075:
076: // spherical mapping divisions per linear space pixel [0..63] -> [0..Pi]
077: // generated by
078: // for (p = 0; p<64; p ++) {
079: // theta[p] = Math.acos( 1.0 - ((double)p)/31.5) ) ;
080: // }
081:
082: double thetas[] = { 0.0, 0.2526477262845635, 0.3582612185126168,
083: 0.4399759547909189, 0.509443848811893, 0.5711684985655375,
084: 0.6274557729231908, 0.6796738189082439, 0.7287134507434055,
085: 0.7751933733103613, 0.8195643276682608, 0.8621670552325126,
086: 0.9032668821590636, 0.9430755091369839, 0.9817653565786227,
087: 1.019479357663014, 1.0563378512337098, 1.092443562145639,
088: 1.1278852827212575, 1.162740649493618, 1.1970782758519827,
089: 1.2309594173407747, 1.2644392922379775, 1.2975681442542588,
090: 1.3303921100256373, 1.3629539374415498, 1.3952935892191738,
091: 1.4274487578895312, 1.4594553124539327, 1.4913476927097593,
092: 1.5231592641704934, 1.5549226443049409, 1.5866700092848522,
093: 1.6184333894192997, 1.6502449608800338, 1.6821373411358607,
094: 1.714143895700262, 1.7462990643706193, 1.7786387161482433,
095: 1.811200543564156, 1.8440245093355343, 1.8771533613518159,
096: 1.9106332362490184, 1.9445143777378107, 1.978852004096175,
097: 2.0137073708685356, 2.0491490914441544, 2.0852548023560833,
098: 2.122113295926779, 2.1598272970111703, 2.198517144452809,
099: 2.2383257714307296, 2.2794255983572804, 2.3220283259215324,
100: 2.366399280279432, 2.412879202846388, 2.461918834681549,
101: 2.5141368806666025, 2.5704241550242557, 2.6321488047779003,
102: 2.7016166987988743, 2.7833314350771765, 2.8889449273052294,
103: 3.141592653589793 };
104:
105: private final static boolean GROUND = true;
106: private final static boolean SKY = false;
107:
108: // This node is not added to the J3D graph directly, so implNode=null
109: // When the background is bound, it's backgroundImpl is attached to
110: // the browserRoot
111: javax.media.j3d.BranchGroup backgroundImpl;
112: javax.media.j3d.Background background;
113: javax.media.j3d.Bounds bound;
114:
115: /**
116: *Constructor for the Background object
117: *
118: *@param loader Description of the Parameter
119: */
120: public Background(Loader loader) {
121: super (loader, loader.getBackgroundStack());
122: groundAngle = new MFFloat();
123: groundColor = new MFColor();
124: backUrl = new MFString();
125: bottomUrl = new MFString();
126: frontUrl = new MFString();
127: leftUrl = new MFString();
128: rightUrl = new MFString();
129: topUrl = new MFString();
130: skyAngle = new MFFloat();
131: float[] color = new float[3];
132: color[0] = 0.3f;
133: color[1] = 0.3f;
134: color[2] = 0.3f;
135: skyColor = new MFColor(color);
136: loader.addBackground(this );
137: initFields();
138: }
139:
140: /**
141: *Constructor for the Background object
142: *
143: *@param loader Description of the Parameter
144: *@param bind Description of the Parameter
145: *@param bindTime Description of the Parameter
146: *@param isBound Description of the Parameter
147: *@param groundAngle Description of the Parameter
148: *@param groundColor Description of the Parameter
149: *@param backUrl Description of the Parameter
150: *@param bottomUrl Description of the Parameter
151: *@param frontUrl Description of the Parameter
152: *@param leftUrl Description of the Parameter
153: *@param rightUrl Description of the Parameter
154: *@param topUrl Description of the Parameter
155: *@param skyAngle Description of the Parameter
156: *@param skyColor Description of the Parameter
157: */
158: public Background(Loader loader, SFBool bind, SFTime bindTime,
159: SFBool isBound, MFFloat groundAngle, MFColor groundColor,
160: MFString backUrl, MFString bottomUrl, MFString frontUrl,
161: MFString leftUrl, MFString rightUrl, MFString topUrl,
162: MFFloat skyAngle, MFColor skyColor) {
163: super (loader, loader.getBackgroundStack(), bind, bindTime,
164: isBound);
165: this .groundAngle = groundAngle;
166: this .groundColor = groundColor;
167: this .backUrl = backUrl;
168: this .bottomUrl = bottomUrl;
169: this .frontUrl = frontUrl;
170: this .leftUrl = leftUrl;
171: this .rightUrl = rightUrl;
172: this .topUrl = topUrl;
173: this .skyAngle = skyAngle;
174: this .skyColor = skyColor;
175: loader.addBackground(this );
176: initFields();
177: }
178:
179: /** Description of the Method */
180: void initImpl() {
181: BranchGroup bkgGeom = new BranchGroup();
182:
183: if (skyAngle.mfloat.length > 0) {
184: int[] bkg = createBkgGrad(skyColor, skyAngle,
185: Background.SKY);
186: if (groundAngle.mfloat.length > 0) {
187: int[] grndBkg = createBkgGrad(groundColor, groundAngle,
188: Background.GROUND);
189: for (int i = 0; i < 32; i++) {
190: bkg[i + 31] = grndBkg[31 - i];
191: }
192: }
193: Texture2D img = getImageBkg(bkg);
194: background = new javax.media.j3d.Background();
195:
196: javax.media.j3d.Appearance app = new javax.media.j3d.Appearance();
197: app.setTexture(img);
198: PolygonAttributes pa = new PolygonAttributes();
199: pa.setCullFace(javax.media.j3d.PolygonAttributes.CULL_NONE);
200: pa.setBackFaceNormalFlip(true);
201: app.setPolygonAttributes(pa);
202: bkgGeom = new BranchGroup();
203: javax.media.j3d.Group sphere = new com.sun.j3d.utils.geometry.Sphere(
204: 1.0f,
205: com.sun.j3d.utils.geometry.Sphere.GENERATE_TEXTURE_COORDS,
206: 20, app);
207: bkgGeom.addChild(sphere);
208: background.setGeometry(bkgGeom);
209: } else {
210: background = new javax.media.j3d.Background(
211: skyColor.vals[0], skyColor.vals[1],
212: skyColor.vals[2]);
213: }
214:
215: background.setApplicationBounds(loader.infiniteBounds);
216: backgroundImpl = new RGroup();
217: backgroundImpl.addChild(background);
218:
219: implReady = true;
220: }
221:
222: // create full "external sky" sphere gradient map to a 64x1 "grid" of pixels
223: // knowing theta and color samples. these will be used to create a texture to
224: // apply to the infinite background sphere.
225:
226: /**
227: * Description of the Method
228: *
229: *@param colors Description of the Parameter
230: *@param angles Description of the Parameter
231: *@param dome Description of the Parameter
232: *@return Description of the Return Value
233: *@exception vrml.InvalidVRMLSyntaxException Description of the Exception
234: */
235: int[] createBkgGrad(MFColor colors, MFFloat angles, boolean dome)
236: throws vrml.InvalidVRMLSyntaxException {
237: float[] clrs0 = new float[3];
238: float[] clrs1 = new float[3];
239: int c0dex = 0;
240: int c1dex = 1;
241: int maxdex = angles.mfloat.length;
242: int mindex = 0;
243: int span = dome ? 32 : 64;
244: int[] gradients = new int[span];
245: //System.out.println(maxdex);
246:
247: if (maxdex != (colors.vals.length / 3) - 1) {
248: throw new vrml.InvalidVRMLSyntaxException(
249: "Background: there shall be one less angle than colors");
250: }
251:
252: colors.get1Value(0, clrs0);
253: gradients[0] = ((int) (clrs0[0] * 255.0f)) << 24
254: | ((int) (clrs0[1] * 255.0f)) << 16
255: | ((int) (clrs0[2] * 255.0f)) << 8 | (int) 0xff;
256: for (int i = 1; i < span; i++) {
257: if (c1dex <= maxdex) {
258: int r;
259: int g;
260: int b;
261: float i0;
262: float i1;
263: //System.out.println("c0dex "+c0dex+ " c1dex "+c1dex);
264: if (c1dex != maxdex) {
265: //System.out.println( i+ " " +thetas[i] + " >= " + angles.get1Value(c1dex));
266: if (thetas[i] >= angles.get1Value(c1dex)) {
267: c0dex = c1dex;
268: c1dex++;
269: }
270: }
271: colors.get1Value(c0dex, clrs0);
272: colors.get1Value(c1dex, clrs1);
273: i0 = (1.0f - (float) Math.cos(thetas[i])) * 0.5f;
274: i1 = 1.0f - i0;
275: r = (int) ((clrs0[0] * i0 + clrs1[0] * i1) * 255.0f);
276: g = (int) ((clrs0[1] * i0 + clrs1[1] * i1) * 255.0f);
277: b = (int) ((clrs0[2] * i0 + clrs1[2] * i1) * 255.0f);
278: //System.out.println("r "+r+" g "+g+" b "+b);
279: gradients[i] = (r << 24) | (g << 16) | (b << 8)
280: | (int) 0xff;
281: } else {
282: gradients[i] = gradients[i - 1];
283: }
284: //System.out.println(gradients[i]);
285:
286: }
287:
288: return gradients;
289: }
290:
291: /**
292: * Gets the imageBkg attribute of the Background object
293: *
294: *@param gradients Description of the Parameter
295: *@return The imageBkg value
296: */
297: Texture2D getImageBkg(int[] gradients) {
298: ImageComponent2D component2D;
299: BufferedImage bufIm;
300: ColorModel cm = new DirectColorModel(32, 0xff000000, 0xff0000,
301: 0xff00, 0xff);
302: WritableRaster raster = cm
303: .createCompatibleWritableRaster(1, 64);
304: int[] data = ((DataBufferInt) raster.getDataBuffer()).getData();
305: System.arraycopy(gradients, 0, data, 0, gradients.length);
306: bufIm = new BufferedImage(cm, raster, false, null);
307: component2D = new ImageComponent2D(ImageComponent.FORMAT_RGBA,
308: bufIm);
309:
310: Texture2D tex = new Texture2D(Texture.BASE_LEVEL, Texture.RGB,
311: 1, 64);
312: // do these need to be for at infinity?
313: tex.setMinFilter(Texture.BASE_LEVEL_LINEAR);
314: tex.setMagFilter(Texture.BASE_LEVEL_LINEAR);
315: tex.setImage(0, component2D);
316: tex.setEnable(true);
317: return tex;
318: }
319:
320: /**
321: * Gets the backgroundImpl attribute of the Background object
322: *
323: *@return The backgroundImpl value
324: */
325: public javax.media.j3d.BranchGroup getBackgroundImpl() {
326: return backgroundImpl;
327: }
328:
329: /**
330: * Description of the Method
331: *
332: *@param eventInName Description of the Parameter
333: *@param time Description of the Parameter
334: */
335: public void notifyMethod(String eventInName, double time) {
336: if (eventInName.equals("bind")) {
337: super .notifyMethod("bind", time);
338: } else if (eventInName.equals("skyColor")) {
339: if (skyColor.vals.length == 3) {
340: background.setColor(skyColor.vals[0], skyColor.vals[1],
341: skyColor.vals[2]);
342: } else {
343: System.err
344: .println("Background: unexpected number of colors");
345: }
346: } else if (eventInName.equals("route_skyColor")) {
347: background
348: .setCapability(javax.media.j3d.Background.ALLOW_COLOR_WRITE);
349: } else if (eventInName.equals("route_bind")) {
350: // no-op
351: } else {
352: System.err.println("Background: unexpected notify "
353: + eventInName);
354: }
355: }
356:
357: /**
358: * Gets the type attribute of the Background object
359: *
360: *@return The type value
361: */
362: public String getType() {
363: return "Background";
364: }
365:
366: /**
367: * Description of the Method
368: *
369: *@return Description of the Return Value
370: */
371: public Object clone() {
372: return new Background(loader, (SFBool) bind.clone(),
373: (SFTime) bindTime.clone(), (SFBool) isBound.clone(),
374: (MFFloat) groundAngle.clone(), (MFColor) groundColor
375: .clone(), (MFString) backUrl.clone(),
376: (MFString) bottomUrl.clone(), (MFString) frontUrl
377: .clone(), (MFString) leftUrl.clone(),
378: (MFString) rightUrl.clone(), (MFString) topUrl.clone(),
379: (MFFloat) skyAngle.clone(), (MFColor) skyColor.clone());
380: }
381:
382: /** Description of the Method */
383: void initFields() {
384: initBindableFields();
385: groundAngle.init(this , FieldSpec, Field.EXPOSED_FIELD,
386: "groundAngle");
387: groundColor.init(this , FieldSpec, Field.EXPOSED_FIELD,
388: "groundColor");
389: backUrl.init(this , FieldSpec, Field.EXPOSED_FIELD, "backUrl");
390: bottomUrl.init(this , FieldSpec, Field.EXPOSED_FIELD,
391: "bottomUrl");
392: frontUrl.init(this , FieldSpec, Field.EXPOSED_FIELD, "frontUrl");
393: leftUrl.init(this , FieldSpec, Field.EXPOSED_FIELD, "leftUrl");
394: rightUrl.init(this , FieldSpec, Field.EXPOSED_FIELD, "rightUrl");
395: topUrl.init(this , FieldSpec, Field.EXPOSED_FIELD, "topUrl");
396: skyAngle.init(this , FieldSpec, Field.EXPOSED_FIELD, "skyAngle");
397: skyColor.init(this , FieldSpec, Field.EXPOSED_FIELD, "skyColor");
398:
399: }
400:
401: /**
402: * Description of the Method
403: *
404: *@return Description of the Return Value
405: */
406: public vrml.BaseNode wrap() {
407: return new org.jdesktop.j3d.loaders.vrml97.node.Background(this);
408: }
409: }
|