001: /*
002: * $RCSfile: Box.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.6 $
041: * $Date: 2007/04/24 18:50:59 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.utils.geometry;
046:
047: import com.sun.j3d.utils.geometry.*;
048: import javax.media.j3d.*;
049: import javax.vecmath.*;
050:
051: /**
052: * Box is a geometry primitive created with a given length, width, and height.
053: * It is centered at the origin. By default, it lies within the bounding
054: * box, [-1,-1,-1] and [1,1,1].
055: *
056: * When a texture is applied to a box, it is map CCW like on a Cylinder.
057: * A texture is mapped CCW from the back of the
058: * body. The top and bottom faces are mapped such that the texture appears
059: * front facing when the faces are rotated 90 toward the viewer.
060: * <p>
061: * By default all primitives with the same parameters share their
062: * geometry (e.g., you can have 50 shperes in your scene, but the
063: * geometry is stored only once). A change to one primitive will
064: * effect all shared nodes. Another implication of this
065: * implementation is that the capabilities of the geometry are shared,
066: * and once one of the shared nodes is live, the capabilities cannot
067: * be set. Use the GEOMETRY_NOT_SHARED flag if you do not wish to
068: * share geometry among primitives with the same parameters.
069: */
070:
071: public class Box extends Primitive {
072:
073: /**
074: * Used to designate the front side of the box when using
075: * getShape().
076: *
077: * @see Box#getShape
078: */
079: public static final int FRONT = 0;
080:
081: /**
082: * Used to designate the back side of the box when using
083: * getShape().
084: *
085: * @see Box#getShape
086: */
087: public static final int BACK = 1;
088:
089: /**
090: * Used to designate the right side of the box when using
091: * getShape().
092: *
093: * @see Box#getShape
094: */
095: public static final int RIGHT = 2;
096:
097: /**
098: * Used to designate the left side of the box when using
099: * getShape().
100: *
101: * @see Box#getShape
102: */
103: public static final int LEFT = 3;
104:
105: /**
106: * Used to designate the top side of the box when using
107: * getShape().
108: *
109: * @see Box#getShape
110: */
111: public static final int TOP = 4;
112:
113: /**
114: * Used to designate the bottom side of the box when using
115: * getShape().
116: *
117: * @see Box#getShape
118: */
119: public static final int BOTTOM = 5;
120:
121: float xDim, yDim, zDim;
122:
123: int numTexUnit = 1;
124:
125: /**
126: * Constructs a default box of 1.0 in all dimensions.
127: * Normals are generated by default, texture coordinates are not.
128: */
129:
130: public Box() {
131: this (1.0f, 1.0f, 1.0f, GENERATE_NORMALS, null);
132: }
133:
134: /**
135: * Constructs a box of a given dimension and appearance.
136: * Normals are generated by default, texture coordinates are not.
137: *
138: * @param xdim X-dimension size.
139: * @param ydim Y-dimension size.
140: * @param zdim Z-dimension size.
141: * @param ap Appearance
142: */
143:
144: public Box(float xdim, float ydim, float zdim, Appearance ap) {
145: this (xdim, ydim, zdim, GENERATE_NORMALS, ap);
146: }
147:
148: /**
149: * Constructs a box of a given dimension, flags, and appearance.
150: *
151: * @param xdim X-dimension size.
152: * @param ydim Y-dimension size.
153: * @param zdim Z-dimension size.
154: * @param primflags primitive flags.
155: * @param ap Appearance
156: */
157:
158: public Box(float xdim, float ydim, float zdim, int primflags,
159: Appearance ap, int numTexUnit) {
160: int i;
161: double sign;
162:
163: xDim = xdim;
164: yDim = ydim;
165: zDim = zdim;
166: flags = primflags;
167: numTexUnit = numTexUnit;
168: boolean texCoordYUp = (flags & GENERATE_TEXTURE_COORDS_Y_UP) != 0;
169:
170: //Depending on whether normal inward bit is set.
171: if ((flags & GENERATE_NORMALS_INWARD) != 0)
172: sign = -1.0;
173: else
174: sign = 1.0;
175:
176: // TransformGroup objTrans = new TransformGroup();
177: // objTrans.setCapability(ALLOW_CHILDREN_READ);
178: // this.addChild(objTrans);
179:
180: Shape3D shape[] = new Shape3D[6];
181:
182: GeomBuffer cache = null;
183:
184: for (i = FRONT; i <= BOTTOM; i++) {
185:
186: cache = getCachedGeometry(Primitive.BOX, xdim, ydim, zdim,
187: i, i, primflags);
188: if (cache != null) {
189: // System.out.println("using cached geometry i = " + i);
190: shape[i] = new Shape3D(cache.getComputedGeometry());
191: numVerts += cache.getNumVerts();
192: numTris += cache.getNumTris();
193: } else {
194:
195: GeomBuffer gbuf = new GeomBuffer(4, numTexUnit);
196:
197: gbuf.begin(GeomBuffer.QUAD_STRIP);
198: for (int j = 0; j < 2; j++) {
199: gbuf.normal3d((double) normals[i].x * sign,
200: (double) normals[i].y * sign,
201: (double) normals[i].z * sign);
202: if (texCoordYUp) {
203: gbuf.texCoord2d(tcoords[i * 8 + j * 2],
204: 1.0 - tcoords[i * 8 + j * 2 + 1]);
205: } else {
206: gbuf.texCoord2d(tcoords[i * 8 + j * 2],
207: tcoords[i * 8 + j * 2 + 1]);
208: }
209:
210: gbuf.vertex3d(
211: (double) verts[i * 12 + j * 3] * xdim,
212: (double) verts[i * 12 + j * 3 + 1] * ydim,
213: (double) verts[i * 12 + j * 3 + 2] * zdim);
214: }
215: for (int j = 3; j > 1; j--) {
216: gbuf.normal3d((double) normals[i].x * sign,
217: (double) normals[i].y * sign,
218: (double) normals[i].z * sign);
219: if (texCoordYUp) {
220: gbuf.texCoord2d(tcoords[i * 8 + j * 2],
221: 1.0 - tcoords[i * 8 + j * 2 + 1]);
222: } else {
223: gbuf.texCoord2d(tcoords[i * 8 + j * 2],
224: tcoords[i * 8 + j * 2 + 1]);
225: }
226: gbuf.vertex3d(
227: (double) verts[i * 12 + j * 3] * xdim,
228: (double) verts[i * 12 + j * 3 + 1] * ydim,
229: (double) verts[i * 12 + j * 3 + 2] * zdim);
230: }
231: gbuf.end();
232: shape[i] = new Shape3D(gbuf.getGeom(flags));
233: numVerts = gbuf.getNumVerts();
234: numTris = gbuf.getNumTris();
235:
236: if ((primflags & Primitive.GEOMETRY_NOT_SHARED) == 0) {
237: cacheGeometry(Primitive.BOX, xdim, ydim, zdim, i,
238: i, primflags, gbuf);
239: }
240: }
241:
242: if ((flags & ENABLE_APPEARANCE_MODIFY) != 0) {
243: (shape[i]).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
244: (shape[i])
245: .setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
246: }
247:
248: if ((flags & ENABLE_GEOMETRY_PICKING) != 0) {
249: (shape[i]).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
250: }
251:
252: // objTrans.addChild(shape[i]);
253: this .addChild(shape[i]);
254: }
255:
256: if (ap == null) {
257: setAppearance();
258: } else
259: setAppearance(ap);
260: }
261:
262: public Box(float xdim, float ydim, float zdim, int primflags,
263: Appearance ap) {
264: this (xdim, ydim, zdim, primflags, ap, 1);
265: }
266:
267: /**
268: * Gets one of the faces (Shape3D) from the box that contains the
269: * geometry and appearance. This allows users to modify the
270: * appearance or geometry of individual parts.
271: * @param partId The part to return.
272: * @return The Shape3D object associated with the partID. If an
273: * invalid partId is passed in, null is returned.
274: */
275:
276: public Shape3D getShape(int partId) {
277: if ((partId >= FRONT) && (partId <= BOTTOM))
278: // return (Shape3D)(((Group)getChild(0)).getChild(partId));
279: return (Shape3D) getChild(partId);
280: return null;
281: }
282:
283: /**
284: * Sets appearance of the box. This will set each face of the
285: * box to the same appearance. To set each face's appearance
286: * separately, use getShape(partId) to get the
287: * individual shape and call shape.setAppearance(ap).
288: */
289:
290: public void setAppearance(Appearance ap) {
291: // ((Shape3D)((Group)getChild(0)).getChild(TOP)).setAppearance(ap);
292: // ((Shape3D)((Group)getChild(0)).getChild(LEFT)).setAppearance(ap);
293: // ((Shape3D)((Group)getChild(0)).getChild(RIGHT)).setAppearance(ap);
294: // ((Shape3D)((Group)getChild(0)).getChild(FRONT)).setAppearance(ap);
295: // ((Shape3D)((Group)getChild(0)).getChild(BACK)).setAppearance(ap);
296: // ((Shape3D)((Group)getChild(0)).getChild(BOTTOM)).setAppearance(ap);
297: ((Shape3D) getChild(TOP)).setAppearance(ap);
298: ((Shape3D) getChild(LEFT)).setAppearance(ap);
299: ((Shape3D) getChild(RIGHT)).setAppearance(ap);
300: ((Shape3D) getChild(FRONT)).setAppearance(ap);
301: ((Shape3D) getChild(BACK)).setAppearance(ap);
302: ((Shape3D) getChild(BOTTOM)).setAppearance(ap);
303: }
304:
305: /**
306: * Gets the appearance of the specified part of the box.
307: *
308: * @param partId identifier for a given subpart of the box
309: *
310: * @return The appearance object associated with the partID. If an
311: * invalid partId is passed in, null is returned.
312: *
313: * @since Java 3D 1.2.1
314: */
315: public Appearance getAppearance(int partId) {
316: if (partId > BOTTOM || partId < FRONT)
317: return null;
318: return getShape(partId).getAppearance();
319: }
320:
321: private static final float[] verts = {
322: // front face
323: 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f,
324: 1.0f,
325: 1.0f,
326: -1.0f,
327: -1.0f,
328: 1.0f,
329: // back face
330: -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
331: -1.0f,
332: 1.0f,
333: -1.0f,
334: -1.0f,
335: // right face
336: 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
337: 1.0f,
338: -1.0f,
339: 1.0f,
340: // left face
341: -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f,
342: -1.0f, -1.0f,
343: -1.0f,
344: // top face
345: 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
346: -1.0f, 1.0f, 1.0f,
347: // bottom face
348: -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
349: -1.0f, 1.0f, -1.0f, 1.0f, };
350:
351: private static final double[] tcoords = {
352: // front
353: 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
354: // back
355: 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
356: //right
357: 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
358: // left
359: 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
360: // top
361: 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
362: // bottom
363: 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 };
364:
365: private static final Vector3f[] normals = {
366: new Vector3f(0.0f, 0.0f, 1.0f), // front face
367: new Vector3f(0.0f, 0.0f, -1.0f), // back face
368: new Vector3f(1.0f, 0.0f, 0.0f), // right face
369: new Vector3f(-1.0f, 0.0f, 0.0f), // left face
370: new Vector3f(0.0f, 1.0f, 0.0f), // top face
371: new Vector3f(0.0f, -1.0f, 0.0f), // bottom face
372: };
373:
374: /**
375: * Used to create a new instance of the node. This routine is called
376: * by <code>cloneTree</code> to duplicate the current node.
377: * <code>cloneNode</code> should be overridden by any user subclassed
378: * objects. All subclasses must have their <code>cloneNode</code>
379: * method consist of the following lines:
380: * <P><blockquote><pre>
381: * public Node cloneNode(boolean forceDuplicate) {
382: * UserSubClass usc = new UserSubClass();
383: * usc.duplicateNode(this, forceDuplicate);
384: * return usc;
385: * }
386: * </pre></blockquote>
387: * @param forceDuplicate when set to <code>true</code>, causes the
388: * <code>duplicateOnCloneTree</code> flag to be ignored. When
389: * <code>false</code>, the value of each node's
390: * <code>duplicateOnCloneTree</code> variable determines whether
391: * NodeComponent data is duplicated or copied.
392: *
393: * @see Node#cloneTree
394: * @see Node#duplicateNode
395: * @see NodeComponent#setDuplicateOnCloneTree
396: */
397: public Node cloneNode(boolean forceDuplicate) {
398: Box b = new Box(xDim, yDim, zDim, flags, getAppearance());
399: b.duplicateNode(this , forceDuplicate);
400: return b;
401: }
402:
403: /**
404: * Copies all node information from <code>originalNode</code> into
405: * the current node. This method is called from the
406: * <code>cloneNode</code> method which is, in turn, called by the
407: * <code>cloneTree</code> method.
408: * <P>
409: * For any <i>NodeComponent</i> objects
410: * contained by the object being duplicated, each <i>NodeComponent</i>
411: * object's <code>duplicateOnCloneTree</code> value is used to determine
412: * whether the <i>NodeComponent</i> should be duplicated in the new node
413: * or if just a reference to the current node should be placed in the
414: * new node. This flag can be overridden by setting the
415: * <code>forceDuplicate</code> parameter in the <code>cloneTree</code>
416: * method to <code>true</code>.
417: *
418: * @param originalNode the original node to duplicate.
419: * @param forceDuplicate when set to <code>true</code>, causes the
420: * <code>duplicateOnCloneTree</code> flag to be ignored. When
421: * <code>false</code>, the value of each node's
422: * <code>duplicateOnCloneTree</code> variable determines whether
423: * NodeComponent data is duplicated or copied.
424: *
425: * @see Node#cloneTree
426: * @see Node#cloneNode
427: * @see NodeComponent#setDuplicateOnCloneTree
428: */
429: public void duplicateNode(Node originalNode, boolean forceDuplicate) {
430: super .duplicateNode(originalNode, forceDuplicate);
431: }
432:
433: /**
434: * Returns the X-dimension size of the Box
435: *
436: * @since Java 3D 1.2.1
437: */
438: public float getXdimension() {
439: return xDim;
440: }
441:
442: /**
443: * Returns the Y-dimension size of the Box
444: *
445: * @since Java 3D 1.2.1
446: */
447: public float getYdimension() {
448: return yDim;
449: }
450:
451: /**
452: * Returns the Z-dimension size of the Box
453: *
454: * @since Java 3D 1.2.1
455: */
456: public float getZdimension() {
457: return zDim;
458: }
459: }
|