001: /*
002: * $RCSfile: CompileState.java,v $
003: *
004: * Copyright 1998-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.6 $
028: * $Date: 2008/02/28 20:17:20 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.*;
035: import java.security.*;
036:
037: /**
038: * The CompileState holds information used during a compile. It is
039: * passed to each SceneGraphObject (SGO) during the compile. Each SGO
040: * modifies the CompileState as necessary and passes the CompileState
041: * to its children (if any).
042: *
043: * The CompileState currently has two functions: appearance mapping
044: * and shape merging.
045: *
046: * Appearance mapping maintains a list of the unique appearances seen
047: * during the compile. getAppearance() is used to turn multiple,
048: * equivalent and static appearances into a single shared appearance.
049: *
050: * The shape mergings collects shapes that are potentially mergable
051: * during a compile. The shapes are sorted into a Map of Lists of
052: * shapes, using the shape's appearance as the key. After a subtree
053: * is traversed, the shapes are merged and added to the Group.
054: */
055:
056: class CompileState {
057: // Appearance mapping stuff:
058: HashMap knownAppearances = new HashMap();
059: int numAppearances = 0;
060: int numShared = 0;
061: int numShapes = 0;
062:
063: // Shape merging stuff:
064: HashMap shapeLists = null; // top entry in shapeListStack
065: int numMergeSets = 0;
066: int numMergeShapes = 0;
067: boolean compileVerbose = false;
068:
069: static final int BOUNDS_READ = 0x00001;
070: static final int GEOMETRY_READ = 0x00002;
071:
072: // scene graph flattening
073:
074: boolean keepTG = false; // used to force the immediate transform
075: // group to stay around
076:
077: boolean needNormalsTransform = false; // true if the current transform
078: // needs to push down normals
079: // transform to geometries
080:
081: // the current static transform group
082: TransformGroupRetained staticTransform = null;
083:
084: // parent group
085: GroupRetained parentGroup = null;
086:
087: // list of transform group
088: // for the current transform group
089: ArrayList transformGroupChildrenList = null;
090:
091: // list of objects that have a static
092: // transform that can be deferenced
093: // after compile
094: ArrayList staticTransformObjects = new ArrayList(1);
095:
096: int numTransformGroups = 0;
097: int numStaticTransformGroups = 0;
098: int numMergedTransformGroups = 0;
099: int numGroups = 0;
100: int numMergedGroups = 0;
101: int numShapesWSharedGeom = 0;
102: int numShapesWStaticTG = 0;
103: int numLinks = 0;
104: int numSwitches = 0;
105: int numOrderedGroups = 0;
106: int numMorphs = 0;
107:
108: CompileState() {
109: try {
110: compileVerbose = Boolean
111: .getBoolean("javax.media.j3d.compileVerbose");
112: } catch (AccessControlException e) {
113: compileVerbose = false;
114: }
115: initShapeMerge();
116: }
117:
118: // Appearance mapping:
119: /**
120: * Returns an unique appearance which equals app. If appearance does not
121: * equal any previously found, the appearance will be added to the known
122: * appearances and be returned. If the apperance equals a previously known
123: * appearance, then the prevously known apperance will be returned
124: */
125: AppearanceRetained getAppearance(AppearanceRetained app) {
126: AppearanceRetained retval;
127:
128: // see if the appearance has allready been classified
129: if (app.map == this ) {
130: if (app.mapAppearance != null) {
131: numShared++;
132: return app.mapAppearance;
133: }
134: }
135:
136: // check if this appearance equals one one in the Map
137: if ((retval = (AppearanceRetained) knownAppearances.get(app)) != null) {
138: numShared++;
139: } else {
140: // not found, put this appearance in the map
141: knownAppearances.put(app, app);
142: numAppearances++;
143: numShared++; // sharing with self...
144: retval = app;
145: }
146:
147: // cache this result on the appearance in case it appears again
148: app.map = this ;
149: app.mapAppearance = retval;
150:
151: return retval;
152: }
153:
154: // Shape Merging:
155: private void initShapeMerge() {
156: shapeLists = new HashMap();
157:
158: }
159:
160: void addShape(Shape3DRetained shape) {
161: if (parentGroup != null) {
162: // sort the shapes into lists with equivalent appearances
163: Vector list;
164: if ((list = (Vector) shapeLists.get(shape.appearance)) == null) {
165: list = new Vector();
166: shapeLists.put(shape.appearance, list);
167: }
168: // Add the shape to the list only if at its parent level
169: // no children can be added or removed ..
170: // Look for the first non-null geometry, there should be atleast
171: // one otherwise it wouldn't come here
172: GeometryRetained geometry = null;
173: int i = 0;
174: while (geometry == null && i < shape.geometryList.size()) {
175: geometry = (GeometryRetained) shape.geometryList.get(i);
176: i++;
177: }
178: if (shape.parent instanceof GroupRetained
179: && ((GroupRetained) shape.parent)
180: .isStaticChildren()
181: && geometry.geoType < GeometryArrayRetained.GEO_TYPE_RASTER) {
182: list.add(shape);
183: }
184:
185: }
186: }
187:
188: void printStats() {
189: System.err.println("numTransformGroups= " + numTransformGroups);
190: System.err.println("numStaticTransformGroups= "
191: + numStaticTransformGroups);
192: System.err.println("numMergedTransformGroups= "
193: + numMergedTransformGroups);
194: System.err.println("numGroups= " + numGroups);
195: System.err.println("numMergedGroups= " + numMergedGroups);
196: System.err.println("numShapes= " + numShapes);
197: System.err.println("numShapesWStaticTG= " + numShapesWStaticTG);
198: System.err.println("numMergeShapes= " + numMergeShapes);
199: System.err.println("numMergeSets= " + numMergeSets);
200: System.err.println("numLinks= " + numLinks);
201: System.err.println("numSwitches= " + numSwitches);
202: System.err.println("numOrderedGroups= " + numOrderedGroups);
203: System.err.println("numMorphs= " + numMorphs);
204: }
205:
206: void doShapeMerge() {
207:
208: // System.err.println("doShapeMerge, shapeList = "+shapeLists);
209: if (shapeLists != null) {
210: // loop over the shapes in each list, creating a single shape
211: // for each. Add the shape to the group
212: Collection lists = shapeLists.values();
213: Iterator listIterator = lists.iterator();
214: Shape3DRetained mergeShape;
215: GeometryRetained firstGeo;
216: int num = 0;
217: int compileFlags = 0;
218:
219: while (listIterator.hasNext()) {
220: Vector curList = (Vector) listIterator.next();
221: int numShapes = curList.size();
222: Shape3DRetained[] shapes = new Shape3DRetained[numShapes];
223: curList.copyInto(shapes);
224: Shape3DRetained[] toBeMergedShapes = new Shape3DRetained[numShapes];
225: for (int i = 0; i < numShapes; i++) {
226: if (shapes[i] == null) {
227: continue;
228: }
229: firstGeo = null;
230: num = 0;
231: // Get the first non-null geometry
232: while (firstGeo == null
233: && num < shapes[i].geometryList.size()) {
234: firstGeo = (GeometryRetained) shapes[i].geometryList
235: .get(num);
236: num++;
237: }
238:
239: if (firstGeo != null
240: && firstGeo instanceof GeometryArrayRetained) {
241: int numMerge = 0;
242: mergeShape = shapes[i];
243: GeometryArrayRetained mergeGeo = (GeometryArrayRetained) firstGeo;
244:
245: toBeMergedShapes[numMerge++] = mergeShape;
246: // Determine if all mergeable shapes have the same boundsCompute
247: // and collisionBounds set the same way
248: compileFlags = getCompileFlags(mergeShape);
249: for (int j = i + 1; j < numShapes; j++) {
250: if (shapes[j] == null) {
251: continue;
252: }
253: firstGeo = null;
254: num = 0;
255: // Get the first non-null geometry
256: while (firstGeo == null
257: && num < shapes[j].geometryList
258: .size()) {
259: firstGeo = (GeometryRetained) shapes[j].geometryList
260: .get(num);
261: num++;
262: }
263:
264: // There is a non-null geometry for this shape ..
265: if (firstGeo != null
266: && shapes[j]
267: .isEquivalent(mergeShape)
268: && firstGeo
269: .isEquivalenceClass(mergeGeo)
270: && ((GeometryArrayRetained) firstGeo).vertexFormat == mergeGeo.vertexFormat) {
271: // got one to merge, add shapes to merge,
272: toBeMergedShapes[numMerge++] = shapes[j];
273:
274: compileFlags |= getCompileFlags(shapes[j]);
275:
276: // remove from shapes
277: shapes[j] = null;
278: }
279: }
280: if (numMerge > 1) {
281:
282: // remove the shapes from its parent before merge
283: // They all should
284: GroupRetained group = (GroupRetained) toBeMergedShapes[0].parent;
285: Shape3DRetained s;
286: for (int n = 0; n < numMerge; n++) {
287: s = toBeMergedShapes[n];
288: boolean found = false;
289: int numChilds = group.numChildren();
290: for (int k = 0; (k < numChilds && !found); k++) {
291: if (group.getChild(k).retained == s) {
292: found = true;
293: group.removeChild(k);
294: }
295: }
296: if (!found) {
297: System.err
298: .println("ShapeSet.add(): Can't remove "
299: + "shape from parent, can't find shape!");
300: }
301:
302: }
303:
304: mergeShape = new Shape3DCompileRetained(
305: toBeMergedShapes, numMerge,
306: compileFlags);
307:
308: if (J3dDebug.devPhase && J3dDebug.debug) {
309: if (J3dDebug.doDebug(
310: J3dDebug.compileState,
311: J3dDebug.LEVEL_3)) {
312: System.err.println("Dest is "
313: + parentGroup);
314: System.err.println("Compile Shape "
315: + mergeShape);
316: System.err
317: .println(mergeShape.geometryList
318: .size()
319: + " geoemtryList");
320: for (int j = 0; j < mergeShape.geometryList
321: .size(); j++) {
322: GeometryRetained geo = ((GeometryRetained) mergeShape.geometryList
323: .get(j));
324: if (geo != null)
325: System.err
326: .println("\t Geo_type = "
327: + geo.geoType);
328: }
329:
330: System.err.println(numMerge
331: + " Shapes were merged ");
332: for (int j = 0; j < numMerge; j++) {
333: System.err.println("\t"
334: + toBeMergedShapes[j]);
335: }
336: }
337: }
338:
339: // Set the source to one of the merged shape's source
340: mergeShape
341: .setSource(toBeMergedShapes[0].source);
342: numMergeSets++;
343: numMergeShapes += numMerge;
344: parentGroup
345: .addChild((Node) mergeShape.source);
346: }
347: }
348: // add the shape to the dest
349: }
350: }
351: }
352:
353: // Clear the shapelists for the next merge
354: shapeLists.clear();
355:
356: }
357:
358: int getCompileFlags(Shape3DRetained shape) {
359: int cflag = 0;
360:
361: // If allow intersect is turned on , then geometry is readable
362: if (shape.allowIntersect()
363: || shape.source
364: .getCapability(Shape3D.ALLOW_GEOMETRY_READ)
365: || (shape.boundsAutoCompute && shape.source
366: .getCapability(Shape3D.ALLOW_BOUNDS_READ)))
367: cflag |= GEOMETRY_READ;
368:
369: return cflag;
370:
371: }
372:
373: }
|