001: /*
002: * $RCSfile: OrderedGroupRetained.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.8 $
028: * $Date: 2008/02/28 20:17:27 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.ArrayList;
035:
036: /**
037: * The OrderedGroup is a group node that ensures its children rendered
038: * in index increasing order.
039: */
040:
041: class OrderedGroupRetained extends GroupRetained {
042: // mapping of ordered child id to child index
043: int orderedChildIdTable[];
044:
045: // This is a counter for ordered child id
046: private int orderedChildIdCount = 0;
047:
048: // This is a vector of free orderedChildId
049: private ArrayList orderedChildIdFreeList = new ArrayList();
050:
051: // One OrderedBin per view
052: OrderedBin[] orderedBin = new OrderedBin[0];
053:
054: // child id of the newly added child
055: Integer newChildId;
056:
057: // ChildCount used by renderBin to initialize the
058: // orderedCollection in each orderedBin (per view)
059: int childCount = 0;
060:
061: // per children ordered path data
062: ArrayList childrenOrderedPaths = new ArrayList(1);
063:
064: // child index order - set by the user.
065: int[] userChildIndexOrder = null;
066:
067: // child index order - use by j3d internal.
068: int[] childIndexOrder = null;
069:
070: OrderedGroupRetained() {
071: this .nodeType = NodeRetained.ORDEREDGROUP;
072: }
073:
074: void setChildIndexOrder(int[] cIOArr) {
075: if (cIOArr != null) {
076: if ((userChildIndexOrder == null)
077: || (userChildIndexOrder.length != cIOArr.length)) {
078: userChildIndexOrder = new int[cIOArr.length];
079: }
080:
081: System.arraycopy(cIOArr, 0, userChildIndexOrder, 0,
082: userChildIndexOrder.length);
083: } else {
084: userChildIndexOrder = null;
085: }
086:
087: if (source.isLive()) {
088: int[] newArr = new int[cIOArr.length];
089: System.arraycopy(cIOArr, 0, newArr, 0, newArr.length);
090: J3dMessage m;
091: m = new J3dMessage();
092: m.threads = J3dThread.UPDATE_RENDER;
093: m.type = J3dMessage.ORDERED_GROUP_TABLE_CHANGED;
094: m.universe = universe;
095: m.args[3] = this ;
096: m.args[4] = newArr;
097: VirtualUniverse.mc.processMessage(m);
098: }
099: }
100:
101: int[] getChildIndexOrder() {
102: if (userChildIndexOrder == null) {
103: return null;
104: }
105:
106: int[] newArr = new int[userChildIndexOrder.length];
107: System.arraycopy(userChildIndexOrder, 0, newArr, 0,
108: userChildIndexOrder.length);
109: return newArr;
110:
111: }
112:
113: Integer getOrderedChildId() {
114: Integer orderedChildId;
115: synchronized (orderedChildIdFreeList) {
116: if (orderedChildIdFreeList.size() == 0) {
117: orderedChildId = new Integer(orderedChildIdCount);
118: orderedChildIdCount++;
119: } else {
120: orderedChildId = (Integer) orderedChildIdFreeList
121: .remove(0);
122: }
123: }
124: return (orderedChildId);
125: }
126:
127: void freeOrderedChildId(int id) {
128: synchronized (orderedChildIdFreeList) {
129: orderedChildIdFreeList.add(new Integer(id));
130: }
131: }
132:
133: int getOrderedChildCount() {
134: int count;
135:
136: synchronized (orderedChildIdFreeList) {
137: count = orderedChildIdCount;
138: }
139: return count;
140: }
141:
142: void addChild(Node child) {
143: if (userChildIndexOrder != null) {
144: doAddChildIndexEntry();
145: }
146:
147: // GroupRetained.addChild have to check for case of non-null child index order
148: // array and handle it.
149: super .addChild(child);
150:
151: }
152:
153: void addChild(Node child, int[] cIOArr) {
154: if (cIOArr != null) {
155: userChildIndexOrder = new int[cIOArr.length];
156:
157: System.arraycopy(cIOArr, 0, userChildIndexOrder, 0,
158: userChildIndexOrder.length);
159: } else {
160: userChildIndexOrder = null;
161: }
162:
163: // GroupRetained.addChild have to check for case of non-null child
164: // index order array and handle it.
165: super .addChild(child);
166:
167: }
168:
169: void moveTo(BranchGroup bg) {
170: if (userChildIndexOrder != null) {
171: doAddChildIndexEntry();
172: }
173:
174: // GroupRetained.moveto have to check for case of non-null child
175: // index order array and handle it.
176: super .moveTo(bg);
177: }
178:
179: void doRemoveChildIndexEntry(int index) {
180:
181: int[] newArr = new int[userChildIndexOrder.length - 1];
182:
183: for (int i = 0, j = 0; i < userChildIndexOrder.length; i++) {
184: if (userChildIndexOrder[i] > index) {
185: newArr[j] = userChildIndexOrder[i] - 1;
186: j++;
187: } else if (userChildIndexOrder[i] < index) {
188: newArr[j] = userChildIndexOrder[i];
189: j++;
190: }
191: }
192:
193: userChildIndexOrder = newArr;
194:
195: }
196:
197: void doAddChildIndexEntry() {
198: int[] newArr = new int[userChildIndexOrder.length + 1];
199:
200: System.arraycopy(userChildIndexOrder, 0, newArr, 0,
201: userChildIndexOrder.length);
202:
203: newArr[userChildIndexOrder.length] = userChildIndexOrder.length;
204:
205: userChildIndexOrder = newArr;
206: }
207:
208: /**
209: * Compiles the children of the OrderedGroup, preventing shape merging at
210: * this level or above
211: */
212: void compile(CompileState compState) {
213:
214: super .compile(compState);
215:
216: // don't remove this group node
217: mergeFlag = SceneGraphObjectRetained.DONT_MERGE;
218:
219: if (J3dDebug.devPhase && J3dDebug.debug) {
220: compState.numOrderedGroups++;
221: }
222: }
223:
224: void setOrderedBin(OrderedBin ob, int index) {
225: synchronized (orderedBin) {
226: orderedBin[index] = ob;
227: }
228: }
229:
230: // Get the orderedBin for this view index
231: OrderedBin getOrderedBin(int index) {
232: OrderedBin ob;
233: synchronized (orderedBin) {
234: if (index >= orderedBin.length) {
235: OrderedBin[] newList = new OrderedBin[index + 1];
236: for (int i = 0; i < orderedBin.length; i++) {
237: newList[i] = orderedBin[i];
238: }
239: newList[index] = null;
240: orderedBin = newList;
241: }
242: }
243: return (orderedBin[index]);
244: }
245:
246: void updateChildIdTableInserted(int childId, int orderedId) {
247: int size = 0;
248: int i;
249:
250: //System.err.println("updateChildIdTableInserted childId " + childId + " orderedId " + orderedId + " " + this);
251: if (orderedChildIdTable != null) {
252: size = orderedChildIdTable.length;
253: for (i = 0; i < size; i++) {
254: if (orderedChildIdTable[i] != -1) {
255: if (orderedChildIdTable[i] >= childId) {
256: orderedChildIdTable[i]++; // shift upward
257: }
258: }
259: }
260: }
261: if (orderedId >= size) {
262: int newTable[];
263: newTable = new int[orderedId + 1];
264: if (size > 0) {
265: System.arraycopy(orderedChildIdTable, 0, newTable, 0,
266: orderedChildIdTable.length);
267: } else {
268: for (i = 0; i < newTable.length; i++) {
269: newTable[i] = -1;
270: }
271: }
272: orderedChildIdTable = newTable;
273: }
274: orderedChildIdTable[orderedId] = childId;
275: //printTable(orderedChildIdTable);
276:
277: }
278:
279: void updateChildIdTableRemoved(int childId) {
280: // If the orderedGroup itself has been clearLived, then the ids
281: // have been returned, if only some of the children of the
282: // OGs is removed, then removed the specific entries
283: // from the table
284: if (orderedChildIdTable == null)
285: return;
286:
287: for (int i = 0; i < orderedChildIdTable.length; i++) {
288: if (orderedChildIdTable[i] != -1) {
289: if (orderedChildIdTable[i] > childId) {
290: orderedChildIdTable[i]--; // shift downward
291: } else if (orderedChildIdTable[i] == childId) {
292: orderedChildIdTable[i] = -1;
293: //System.err.println("og.updateChildIdTableRemoved freeId " + i);
294: freeOrderedChildId(i);
295: }
296: }
297: }
298:
299: }
300:
301: void setAuxData(SetLiveState s, int index, int hkIndex) {
302: OrderedPath setLiveStateOrderedPath, newOrderedPath;
303: ArrayList childOrderedPaths;
304: NodeRetained child;
305:
306: setLiveStateOrderedPath = (OrderedPath) s.orderedPaths
307: .get(hkIndex);
308: for (int i = 0; i < children.size(); i++) {
309: child = (NodeRetained) children.get(i);
310: if (refCount == s.refCount) {
311: // only need to do it once if in shared group when the first
312: // instances is to be added
313: child.orderedId = getOrderedChildId();
314: }
315:
316: newOrderedPath = setLiveStateOrderedPath.clonePath();
317: newOrderedPath.addElementToPath(this , child.orderedId);
318: childOrderedPaths = (ArrayList) childrenOrderedPaths.get(i);
319: childOrderedPaths.add(hkIndex, newOrderedPath);
320: }
321: }
322:
323: void setLive(SetLiveState s) {
324: super .setLive(s);
325: s.orderedPaths = orderedPaths;
326: if ((userChildIndexOrder != null) && (refCount == 1)) {
327:
328: // Don't send a message for initial set live.
329: int[] newArr = new int[userChildIndexOrder.length];
330: System.arraycopy(userChildIndexOrder, 0, newArr, 0,
331: userChildIndexOrder.length);
332: childIndexOrder = newArr;
333: }
334: }
335:
336: void clearLive(SetLiveState s) {
337: super .clearLive(s);
338: // This is used to clear the childIdTable and set the orderedBin
339: // for all views to be null
340:
341: if (refCount == 0) {
342: s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT;
343: // only need to do it once if in shared group
344: s.nodeList.add(this );
345: s.ogCIOList.add(this );
346: s.ogCIOTableList.add(null);
347: userChildIndexOrder = null;
348: }
349: s.orderedPaths = orderedPaths;
350: }
351:
352: void setNodeData(SetLiveState s) {
353: super .setNodeData(s);
354: if (!inSharedGroup) {
355: setAuxData(s, 0, 0);
356: } else {
357: // For inSharedGroup case.
358: int j, hkIndex;
359:
360: for (j = 0; j < s.keys.length; j++) {
361: hkIndex = s.keys[j].equals(localToVworldKeys, 0,
362: localToVworldKeys.length);
363:
364: if (hkIndex >= 0) {
365: setAuxData(s, j, hkIndex);
366:
367: } else {
368: MasterControl
369: .getCoreLogger()
370: .severe(
371: "Can't Find matching hashKey in setNodeData.");
372: }
373: }
374: }
375: // Note s.orderedPaths is to be updated in GroupRetained.setLive
376: // for each of its children
377: }
378:
379: void removeNodeData(SetLiveState s) {
380:
381: if ((inSharedGroup) && (s.keys.length != localToVworld.length)) {
382: int i, index;
383: ArrayList childOrderedPaths;
384:
385: // Must be in reverse, to preserve right indexing.
386: for (i = s.keys.length - 1; i >= 0; i--) {
387: index = s.keys[i].equals(localToVworldKeys, 0,
388: localToVworldKeys.length);
389: if (index >= 0) {
390: for (int j = 0; j < children.size(); j++) {
391: childOrderedPaths = (ArrayList) childrenOrderedPaths
392: .get(j);
393: childOrderedPaths.remove(index);
394: }
395: }
396: }
397: // Note s.orderedPaths is to be updated in GroupRetained.clearLive
398: // for each of its children
399: }
400: super .removeNodeData(s);
401: }
402:
403: // This node has been cleared, so
404: void clearDerivedDataStructures() {
405: int i;
406:
407: //System.err.println("og clearDerivedDataStructures " + this);
408: // Clear the orderedBin and childId table for all views
409: // since this orderedGroup has been clearLived!
410: for (i = 0; i < orderedBin.length; i++) {
411: if (orderedBin[i] != null) {
412: orderedBin[i].source = null;
413: orderedBin[i] = null;
414: }
415: }
416: if (orderedChildIdTable != null) {
417: for (i = 0; i < orderedChildIdTable.length; i++) {
418: if (orderedChildIdTable[i] != -1) {
419: orderedChildIdTable[i] = -1;
420: //System.err.println("og.clearDerivedDataStructures freeId " + i);
421: freeOrderedChildId(i);
422: }
423: }
424: orderedChildIdTable = null;
425: }
426: }
427:
428: void incrChildCount() {
429: childCount++;
430: }
431:
432: void decrChildCount() {
433: childCount--;
434: }
435:
436: void printTable(int[] table) {
437: for (int i = 0; i < table.length; i++) {
438: System.err.print(" " + table[i]);
439: }
440: System.err.println("");
441: }
442:
443: void insertChildrenData(int index) {
444: childrenOrderedPaths.add(index, new ArrayList(1));
445: }
446:
447: void appendChildrenData() {
448: childrenOrderedPaths.add(new ArrayList(1));
449: }
450:
451: void doRemoveChild(int index, J3dMessage messages[],
452: int messageIndex) {
453:
454: if (userChildIndexOrder != null) {
455: doRemoveChildIndexEntry(index);
456: }
457:
458: super .doRemoveChild(index, messages, messageIndex);
459:
460: }
461:
462: void removeChildrenData(int index) {
463: childrenOrderedPaths.remove(index);
464: }
465:
466: void childDoSetLive(NodeRetained child, int childIndex,
467: SetLiveState s) {
468: if (refCount == s.refCount) {
469: s.ogList.add(this );
470: s.ogChildIdList.add(new Integer(childIndex));
471: s.ogOrderedIdList.add(child.orderedId);
472: }
473: s.orderedPaths = (ArrayList) childrenOrderedPaths
474: .get(childIndex);
475: if (child != null)
476: child.setLive(s);
477: }
478:
479: void childCheckSetLive(NodeRetained child, int childIndex,
480: SetLiveState s, NodeRetained linkNode) {
481: OrderedPath childOrderedPath;
482: ArrayList childOrderedPaths;
483:
484: if (linkNode != null) {
485: int ci = children.indexOf(linkNode);
486: childOrderedPaths = (ArrayList) childrenOrderedPaths
487: .get(ci);
488: } else {
489: child.orderedId = getOrderedChildId();
490: // set this regardless of refCount
491: s.ogList.add(this );
492: s.ogChildIdList.add(new Integer(childIndex));
493: s.ogOrderedIdList.add(child.orderedId);
494:
495: if (userChildIndexOrder != null) {
496: s.ogCIOList.add(this );
497: int[] newArr = new int[userChildIndexOrder.length];
498: System.arraycopy(userChildIndexOrder, 0, newArr, 0,
499: userChildIndexOrder.length);
500:
501: s.ogCIOTableList.add(newArr);
502: }
503:
504: childOrderedPaths = (ArrayList) childrenOrderedPaths
505: .get(childIndex);
506:
507: for (int i = 0; i < orderedPaths.size(); i++) {
508: childOrderedPath = ((OrderedPath) orderedPaths.get(i))
509: .clonePath();
510: childOrderedPath
511: .addElementToPath(this, child.orderedId);
512: childOrderedPaths.add(childOrderedPath);
513: }
514: }
515: s.orderedPaths = childOrderedPaths;
516: child.setLive(s);
517: }
518: }
|