001: /*
002: * $RCSfile: GeometryRetained.java,v $
003: *
004: * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.10 $
028: * $Date: 2008/02/28 20:17:22 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import javax.vecmath.*;
035: import java.util.ArrayList;
036:
037: abstract class GeometryRetained extends NodeComponentRetained {
038:
039: static final int GEO_TYPE_NONE = -1;
040:
041: static final int GEO_TYPE_QUAD_SET = 1;
042: static final int GEO_TYPE_TRI_SET = 2;
043: static final int GEO_TYPE_POINT_SET = 3;
044: static final int GEO_TYPE_LINE_SET = 4;
045: static final int GEO_TYPE_TRI_STRIP_SET = 5;
046: static final int GEO_TYPE_TRI_FAN_SET = 6;
047: static final int GEO_TYPE_LINE_STRIP_SET = 7;
048:
049: static final int GEO_TYPE_INDEXED_QUAD_SET = 8;
050: static final int GEO_TYPE_INDEXED_TRI_SET = 9;
051: static final int GEO_TYPE_INDEXED_POINT_SET = 10;
052: static final int GEO_TYPE_INDEXED_LINE_SET = 11;
053: static final int GEO_TYPE_INDEXED_TRI_STRIP_SET = 12;
054: static final int GEO_TYPE_INDEXED_TRI_FAN_SET = 13;
055: static final int GEO_TYPE_INDEXED_LINE_STRIP_SET = 14;
056:
057: static final int GEO_TYPE_RASTER = 15;
058: static final int GEO_TYPE_TEXT3D = 16;
059: static final int GEO_TYPE_COMPRESSED = 17;
060:
061: static final int GEO_TYPE_TOTAL = 17;
062: static final int GEO_TYPE_GEOMETRYARRAY = 14;
063:
064: BoundingBox geoBounds = new BoundingBox();
065:
066: // Indicates whether bounds need to be computed.
067: // Checked when a user does addUser/removeUser and count goes from 0 to one
068: // but geometry has not changed and there is no need to recompute
069: boolean boundsDirty = true; // Changed while holding the geoBounds lock
070:
071: int computeGeoBounds = 0; // Changed while holding the geoBounds lock
072:
073: // The "type" of this object
074: int geoType = GEO_TYPE_NONE;
075:
076: // The id used by the native code when building this object
077: int nativeId = -1;
078:
079: // A mask that indicates that something has changed in this object
080: int isDirty = 0xffff;
081:
082: // Geometry Lock (used only by GeometryArrayRetained and RasterRetained)
083: GeometryLock geomLock = new GeometryLock();
084:
085: // Lock used for synchronization of live state
086: Object liveStateLock = new Object();
087:
088: abstract void update();
089:
090: // A reference to the mirror copy of the geometry
091: GeometryRetained mirrorGeometry = null;
092:
093: // indicates whether the geometry in editable
094: boolean isEditable = true;
095:
096: // A list of Universes that this Geometry is referenced from
097: ArrayList universeList = new ArrayList();
098:
099: // A list of ArrayLists which contain all the Shape3DRetained objects
100: // refering to this geometry. Each list corresponds to the universe
101: // above.
102: ArrayList<ArrayList<Shape3DRetained>> userLists = new ArrayList();
103:
104: // true if color not specified with alpha channel
105: boolean noAlpha = false;
106: static final double EPSILON = 1.0e-6;
107:
108: Point3d centroid = new Point3d();
109: boolean recompCentroid = true;
110: // The cached value is evaluated by renderBin and used in determining
111: // whether to put it in display list or not
112: int cachedChangedFrequent = 0;
113:
114: static final int POINT_TYPE = 1;
115: static final int LINE_TYPE = 2;
116: static final int TRIANGLE_TYPE = 3;
117: static final int QUAD_TYPE = 4;
118: static final int RASTER_TYPE = 5;
119: static final int TEXT3D_TYPE = 6;
120: static final int COMPRESS_TYPE = 7;
121:
122: boolean isEquivalenceClass(GeometryRetained geometry) {
123: int t1 = getClassType();
124: int t2 = geometry.getClassType();
125:
126: if (t1 == QUAD_TYPE) {
127: t1 = TRIANGLE_TYPE;
128: }
129: if (t2 == QUAD_TYPE) {
130: t2 = TRIANGLE_TYPE;
131: }
132: return (t1 == t2);
133: }
134:
135: void incrComputeGeoBounds() {
136: synchronized (geoBounds) {
137: computeGeoBounds++;
138: // When it goes from zero to one, compute it ..
139: if (computeGeoBounds == 1 && source.isLive()) {
140: computeBoundingBox();
141: }
142: }
143: }
144:
145: void decrComputeGeoBounds() {
146: synchronized (geoBounds) {
147: computeGeoBounds--;
148: }
149: }
150:
151: // This adds a Shape3DRetained to the list of users of this geometry
152: void addUser(Shape3DRetained s) {
153: int index;
154: ArrayList shapeList;
155:
156: if (s.sourceNode.boundsAutoCompute) {
157: incrComputeGeoBounds();
158: }
159:
160: // If static, no need to maintain a userlist
161: if (this instanceof GeometryArrayRetained) {
162: if (((GeometryArrayRetained) this ).isWriteStatic()) {
163: return;
164: }
165: }
166: synchronized (universeList) {
167: if (universeList.contains(s.universe)) {
168: index = universeList.indexOf(s.universe);
169: shapeList = (ArrayList) userLists.get(index);
170: shapeList.add(s);
171: } else {
172: universeList.add(s.universe);
173: shapeList = new ArrayList();
174: shapeList.add(s);
175: userLists.add(shapeList);
176: }
177: }
178:
179: }
180:
181: // This adds a Shape3DRetained to the list of users of this geometry
182: void removeUser(Shape3DRetained s) {
183: int index;
184: ArrayList shapeList;
185:
186: if (s.sourceNode.boundsAutoCompute) {
187: decrComputeGeoBounds();
188: }
189:
190: if (this instanceof GeometryArrayRetained) {
191: if (((GeometryArrayRetained) this ).isWriteStatic()) {
192: return;
193: }
194: }
195:
196: synchronized (universeList) {
197: index = universeList.indexOf(s.universe);
198: shapeList = (ArrayList) userLists.get(index);
199: shapeList.remove(shapeList.indexOf(s));
200: if (shapeList.size() == 0) {
201: userLists.remove(index);
202: universeList.remove(index);
203: }
204: }
205:
206: }
207:
208: public void updateObject() {
209: this .update();
210: }
211:
212: abstract void computeBoundingBox();
213:
214: void setLive(boolean inBackgroundGroup, int refCount) {
215: doSetLive(inBackgroundGroup, refCount);
216: super .markAsLive();
217: }
218:
219: /**
220: * This setLive routine calls the superclass's method when reference
221: * count is 1
222: */
223: void doSetLive(boolean inBackgroundGroup, int refCount) {
224: super .doSetLive(inBackgroundGroup, refCount);
225: this .update();
226: this .computeBoundingBox();
227: }
228:
229: abstract void execute(Canvas3D cv, RenderAtom ra,
230: boolean isNonUniformScale, boolean updateAlpha,
231: float alpha, int screen, boolean ignoreVertexColors);
232:
233: /**
234: * This method should return an int indicating the format of the vertices,
235: * if any, stored in the geometry. Instances that can return a valid value
236: * should override this method, otherwise it will be assumed that no
237: * valid vertex components exist.
238: * @return format of vertices in the GeometryRetained as specified by
239: * GeometryArray, if appropriate to this instance.
240: */
241: int getVertexFormat() {
242: return 0;
243: }
244:
245: // Issue 199 -- Chien
246: abstract boolean intersect(PickShape pickShape, PickInfo pickInfo,
247: int flags, Point3d iPnt, GeometryRetained geom,
248: int geomIndex);
249:
250: // Old stuff -- Chien
251: //abstract boolean intersect(PickShape pickShape, PickInfo.IntersectionInfo iInfo, int flags, Point3d iPnt);
252:
253: abstract boolean intersect(Bounds targetBound);
254:
255: abstract boolean intersect(Point3d[] pnts);
256:
257: abstract boolean intersect(Transform3D this ToOtherVworld,
258: GeometryRetained geom);
259:
260: void storeInterestData(PickInfo pickInfo, int flags,
261: GeometryRetained geom, int geomIndex, int[] vtxIndexArr,
262: Point3d iPnt, double dist) {
263:
264: PickInfo.IntersectionInfo iInfo = null;
265:
266: if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) {
267: PickInfo.IntersectionInfo iInfoArr[] = pickInfo
268: .getIntersectionInfos();
269: if ((iInfoArr == null) || (iInfoArr.length == 0)) {
270: iInfo = pickInfo.createIntersectionInfo();
271: pickInfo.insertIntersectionInfo(iInfo);
272: } else {
273: assert (iInfoArr.length == 1);
274: iInfo = iInfoArr[0];
275: }
276: } else if ((flags & PickInfo.ALL_GEOM_INFO) != 0) {
277: iInfo = pickInfo.createIntersectionInfo();
278: pickInfo.insertIntersectionInfo(iInfo);
279: } else {
280: assert (false);
281: }
282: // This only set the reference to geometry.source.
283: iInfo.setGeometry((Geometry) geom.source);
284: // The rest are by copy.
285: iInfo.setGeometryIndex(geomIndex);
286: iInfo.setDistance(dist);
287: iInfo.setIntersectionPoint(iPnt);
288: iInfo.setVertexIndices(vtxIndexArr);
289: }
290:
291: boolean intersect(Transform3D this LocalToVworld,
292: Transform3D otherLocalToVworld, GeometryRetained geom) {
293: Transform3D t3d = new Transform3D();
294: t3d.invert(otherLocalToVworld);
295: t3d.mul(this LocalToVworld);
296: return intersect(t3d, geom);
297: }
298:
299: boolean intersect(Transform3D this LocalToVworld, Bounds targetBound) {
300: Bounds transBound = (Bounds) targetBound.clone();
301:
302: Transform3D t3d = new Transform3D();
303: t3d.invert(this LocalToVworld);
304: transBound.transform(t3d);
305: return intersect(transBound);
306: }
307:
308: // Return a flag indicating whether or not this Geometry object can be in
309: // a display list.
310: //
311: // XXXX: Note that for IndexedGeometryArray objects, the original
312: // vertex format is used in making this determination, even when it has
313: // been unindexified. This should be fixed by using the vertex format of
314: // the mirror geometry if there is one.
315: boolean canBeInDisplayList(boolean alphaEditable) {
316: // Check global flag to see whether we can build display lists
317: if (!VirtualUniverse.mc.isDisplayList) {
318: return false;
319: }
320:
321: // Can't build display lists if geometry is frequently writable
322: //
323: // Issue 181 : to fix performance regression from 1.3.2, we will allow
324: // editable geometry if the optimizeForSpace property is set false and
325: // the cachedChangedFrequent flag is set; note this will basically
326: // restore the 1.3.2 behavior, which isn't completely correct.
327: // Eventually, we should fix the bug that is causing the
328: // cachedChangedFrequent bit to be wrong; we can then remove the
329: // erroneous dependency on optimizeForSpace.
330: if (this .isEditable) {
331: if (cachedChangedFrequent != 0) {
332: return false;
333: }
334:
335: // TODO: remove the following when cachedChangedFrequent is fixed
336: // to correctly reflect the state
337: if (!VirtualUniverse.mc.buildDisplayListIfPossible) {
338: return false;
339: }
340: }
341:
342: if (this instanceof GeometryArrayRetained) {
343: int vFormat = ((GeometryArrayRetained) this ).vertexFormat;
344:
345: // If geometry has vertex attributes, check whether
346: // vertex attributes are allowed in display lists
347: if (((vFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0)
348: && !VirtualUniverse.mc.vertexAttrsInDisplayList) {
349: return false;
350: }
351:
352: // Can't build display lists if alpha is editable and
353: // geometry array has colors
354: if (alphaEditable && ((vFormat & GeometryArray.COLOR) != 0)) {
355: return false;
356: }
357:
358: // Only build DL for by-ref geometry when system property is set.
359: // Exclude NIO buffers and use-coord-index-only
360: if ((vFormat & GeometryArray.BY_REFERENCE) != 0) {
361: if (!VirtualUniverse.mc.buildDisplayListIfPossible) {
362: return false;
363: }
364:
365: // XXXX: we could change this to allow display lists for
366: // non-interleaved NIO buffers, but we would first need to
367: // update the now-obsolete buildGAForBuffer method to handle
368: // vertex attrs
369: if ((vFormat & GeometryArray.USE_NIO_BUFFER) != 0) {
370: return false;
371: }
372:
373: if ((vFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) {
374: return false;
375: }
376: }
377:
378: return true;
379: } else {
380: // Can't build display lists for other kind of geometry
381: // NOTE: This method is not called for any type of Geometry
382: // other than GeometryArray, so we shouldn't even get here.
383: return false;
384: }
385: }
386:
387: void computeCentroid() {
388: this .centroid.set(geoBounds.getCenter());
389: }
390:
391: abstract int getClassType();
392:
393: }
|