001: /*
002: * $RCSfile: LightBin.java,v $
003: *
004: * Copyright 1999-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.7 $
028: * $Date: 2008/02/28 20:17:25 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import javax.vecmath.*;
035: import java.util.ArrayList;
036:
037: /**
038: * The LightBin manages a collection of EnvironmentSet objects.
039: * The number of objects managed depends upon the number of Lights
040: * in each EnvironmentSet and the number of lights supported by
041: * the underlying rendering layer.
042: */
043:
044: class LightBin extends Object implements ObjectUpdate {
045:
046: /**
047: * The maximum number of lights in a LightBin
048: */
049: int maxLights = -1;
050:
051: /**
052: * The Array of Light references in this LightBin.
053: * This array is always maxLights in length.
054: */
055: LightRetained[] lights = null;
056:
057: /**
058: * An Array of reference counts for shared lights in
059: * among EnvirionmentSets
060: */
061: int[] lightsRef = null;
062:
063: /**
064: * The number of empty light slots in this LightBin
065: */
066: int numEmptySlots = -1;
067:
068: /**
069: * The RenderBin for this object
070: */
071: RenderBin renderBin = null;
072:
073: /**
074: * The references to the next and previous LightBins in the
075: * list.
076: */
077: LightBin next = null;
078: LightBin prev = null;
079:
080: /**
081: * The list of EnvironmentSets in this LightBin.
082: */
083: EnvironmentSet environmentSetList = null;
084:
085: /**
086: * List of envSet to be added for the next iteration
087: */
088: ArrayList insertEnvSet = new ArrayList();
089:
090: /**
091: * cache of the canvasDirty
092: */
093: int canvasDirty = 0;
094:
095: /**
096: * lightDirty Mask cache , used to
097: * mark the lightdirty bits for next frame
098: */
099: int lightDirtyMaskCache = 0;
100:
101: /**
102: * lightDirty Mask used during rendering
103: */
104: int lightDirtyMask = 0;
105:
106: /**
107: * List of pointLts in this lightbin
108: * Need to reload these lights when vworld scale changes
109: */
110: ArrayList pointLts = new ArrayList();
111: int[] pointLtsSlotIndex;
112:
113: // OrderedGroup info
114: OrderedCollection orderedCollection = null;
115:
116: boolean onUpdateList = false;
117:
118: // background node that contains geometry
119: BackgroundRetained geometryBackground = null;
120:
121: LightBin(int maxLights, RenderBin rb, boolean isOpaque) {
122: this .maxLights = maxLights;
123: this .numEmptySlots = maxLights;
124: lights = new LightRetained[maxLights];
125: lightsRef = new int[maxLights];
126: renderBin = rb;
127: }
128:
129: void reset(boolean inOpaque) {
130: prev = null;
131: next = null;
132: orderedCollection = null;
133: environmentSetList = null;
134: onUpdateList = false;
135: geometryBackground = null;
136: // No need to reset the lights and lightRef
137: if (J3dDebug.devPhase && J3dDebug.debug) {
138: for (int i = 0; i < maxLights; i++) {
139: J3dDebug.doAssert(lights[i] == null,
140: "lights[i] == null");
141: J3dDebug.doAssert(lightsRef[i] == 0,
142: "lightsRef[i] == 0");
143: }
144: }
145: }
146:
147: void setOrderedInfo(OrderedCollection oc) {
148: orderedCollection = oc;
149: }
150:
151: /**
152: * Checks to see if an EnvironmentSet will fit into
153: * this LightBin. It takes into account shared lights.
154: */
155: boolean willEnvironmentSetFit(EnvironmentSet e) {
156: int i, j, numEsLights, slotsNeeded;
157: LightRetained light;
158:
159: numEsLights = e.lights.size();
160: slotsNeeded = numEsLights;
161: for (i = 0; i < numEsLights; i++) {
162: light = (LightRetained) e.lights.get(i);
163: if (light instanceof AmbientLightRetained) {
164: continue;
165: }
166: for (j = 0; j < maxLights; j++) {
167: if (lights[j] == light) {
168: slotsNeeded--;
169: break;
170: }
171: }
172: }
173: if (slotsNeeded > numEmptySlots) {
174: return (false);
175: } else {
176: return (true);
177: }
178: }
179:
180: /**
181: * Adds the new EnvironmentSet to this LightBin.
182: */
183: void addEnvironmentSet(EnvironmentSet e, RenderBin rb) {
184: int i, j, numEsLights;
185: LightRetained light;
186:
187: numEsLights = e.lights.size();
188: for (i = 0; i < numEsLights; i++) {
189: light = (LightRetained) e.lights.get(i);
190: if (light instanceof AmbientLightRetained) {
191: continue;
192: }
193: for (j = 0; j < maxLights; j++) {
194: if (lights[j] == light) {
195: if (light.lightOn) {
196: e.enableMask |= 1 << j;
197: }
198: lightsRef[j]++;
199: // Keep a reference to the position of the light
200: // in the light bin that this light in the envSet
201: // refers
202: e.ltPos[i] = j;
203: break;
204: }
205: }
206: if (j == maxLights) {
207: // Find an empty slot
208: for (j = 0; j < maxLights; j++) {
209: if (lights[j] == null) {
210: lights[j] = light;
211: lightsRef[j] = 1;
212: if (light instanceof PointLightRetained) {
213: pointLts.add(light);
214:
215: // save the destinated light slot for point
216: // so that point light can be updated without
217: // referencing the lights list
218: int pointLtsSlotIndexLen = 0;
219: if (pointLtsSlotIndex != null)
220: pointLtsSlotIndexLen = pointLtsSlotIndex.length;
221: if (pointLtsSlotIndexLen < pointLts.size()) {
222:
223: int[] newIndexList = new int[pointLtsSlotIndexLen + 8];
224: for (int x = 0; x < pointLtsSlotIndexLen; x++) {
225: newIndexList[x] = pointLtsSlotIndex[x];
226: }
227: pointLtsSlotIndex = newIndexList;
228: }
229: pointLtsSlotIndex[pointLts.size() - 1] = j;
230: }
231: if (light.lightOn) {
232: e.enableMask |= 1 << j;
233: }
234: // Keep a reference to the position of the light
235: // in the light bin that this light in the envSet
236: // refers
237: e.ltPos[i] = j;
238: numEmptySlots--;
239: break;
240: }
241: }
242: }
243: }
244: e.lightBin = this ;
245: e.enableMaskCache = e.enableMask;
246: insertEnvSet.add(e);
247: if (!onUpdateList) {
248: rb.objUpdateList.add(this );
249: onUpdateList = true;
250: }
251:
252: }
253:
254: public void updateObject() {
255: int i, j;
256: EnvironmentSet e;
257:
258: // Handle insertion
259: if (insertEnvSet.size() > 0) {
260: e = (EnvironmentSet) insertEnvSet.get(0);
261: if (environmentSetList == null) {
262: environmentSetList = e;
263: } else {
264: e.next = environmentSetList;
265: environmentSetList.prev = e;
266: environmentSetList = e;
267: }
268: for (i = 1; i < insertEnvSet.size(); i++) {
269: e = (EnvironmentSet) insertEnvSet.get(i);
270: e.next = environmentSetList;
271: environmentSetList.prev = e;
272: environmentSetList = e;
273: }
274: }
275:
276: insertEnvSet.clear();
277: if (canvasDirty != 0) {
278:
279: Canvas3D canvases[] = renderBin.view.getCanvases();
280: for (i = 0; i < canvases.length; i++) {
281: canvases[i].canvasDirty |= canvasDirty;
282: }
283: lightDirtyMask = lightDirtyMaskCache;
284: canvasDirty = 0;
285: lightDirtyMaskCache = 0;
286: }
287: onUpdateList = false;
288: }
289:
290: /**
291: * Removes the given EnvironmentSet from this LightBin.
292: */
293: void removeEnvironmentSet(EnvironmentSet e) {
294: int i, j, numEsLights;
295: LightRetained light;
296:
297: e.lightBin = null;
298: // If envSet being remove is contained in envSet, then
299: // remove the envSet from the addList
300: if (insertEnvSet.contains(e)) {
301: insertEnvSet.remove(insertEnvSet.indexOf(e));
302: } else {
303: numEsLights = e.lights.size();
304: for (i = 0; i < numEsLights; i++) {
305: light = (LightRetained) e.lights.get(i);
306: for (j = 0; j < maxLights; j++) {
307: if (lights[j] == light) {
308: lightsRef[j]--;
309: if (lightsRef[j] == 0) {
310: if (light instanceof PointLightRetained)
311: pointLts
312: .remove(pointLts.indexOf(light));
313: lights[j] = null;
314: // If the lightBin is dirty unset the mask
315: lightDirtyMaskCache &= ~(1 << j);
316: // since the canvas may already be updated,
317: lightDirtyMask &= ~(1 << j);
318: numEmptySlots++;
319: }
320: break;
321: }
322: }
323: }
324:
325: if (e.prev == null) { // At the head of the list
326: environmentSetList = e.next;
327: if (e.next != null) {
328: e.next.prev = null;
329: }
330: } else { // In the middle or at the end.
331: e.prev.next = e.next;
332: if (e.next != null) {
333: e.next.prev = e.prev;
334: }
335: }
336:
337: // Mark all canvases that uses this environment set as
338: Canvas3D canvases[] = renderBin.view.getCanvases();
339: for (i = 0; i < canvases.length; i++) {
340: // Mark the environmentSet cached by all the canvases as null
341: // to force to reEvaluate when it comes back from the freelist
342: // During envset::render(), we only check for the pointers not
343: // being the same, so we need to take care of the env set
344: // gotten from the freelist from one frame to another
345: canvases[i].environmentSet = null;
346: }
347:
348: }
349: e.prev = null;
350: e.next = null;
351:
352: if (environmentSetList == null && insertEnvSet.size() == 0) {
353: renderBin.removeLightBin(this );
354: geometryBackground = null;
355: }
356:
357: }
358:
359: /**
360: * Renders this LightBin
361: */
362: void render(Canvas3D cv) {
363: EnvironmentSet e;
364:
365: // include this LightBin to the to-be-updated list in Canvas
366: cv.setStateToUpdate(Canvas3D.LIGHTBIN_BIT, this );
367:
368: e = environmentSetList;
369: while (e != null) {
370: e.render(cv);
371: e = e.next;
372: }
373: }
374:
375: void updateAttributes(Canvas3D cv) {
376: int i;
377: double scale;
378:
379: int frameCount = VirtualUniverse.mc.frameCount;
380:
381: // TODO: When working on issue 15 and 88, we realise that the
382: // logic in this method flaw. As we are ready into 1.3.2beta1
383: // phase, and there isn't an existing issue related to the logic
384: // error in method, we decided not to fix it for now. This method
385: // should have the logic as in EnvironmentSet.updateAttributes();
386: // The fix to issue 15 and 88.
387:
388: // within frames
389: if (cv.lightBin != this ) {
390:
391: if (geometryBackground == null) {
392: scale = cv.canvasViewCache
393: .getVworldToCoexistenceScale();
394: cv.setModelViewMatrix(cv.ctx, cv.vpcToEc.mat,
395: renderBin.vworldToVpc);
396: } else {
397: scale = cv.canvasViewCache
398: .getInfVworldToCoexistenceScale();
399: cv.setModelViewMatrix(cv.ctx, cv.vpcToEc.mat,
400: renderBin.infVworldToVpc);
401: }
402:
403: for (i = 0; i < maxLights; i++) {
404: if (lights[i] != null) {
405: if (cv.lights[i] != lights[i]
406: || cv.frameCount[i] != frameCount) {
407: cv.lights[i] = lights[i];
408: cv.frameCount[i] = frameCount;
409: lights[i].update(cv.ctx, i, scale);
410: }
411: }
412: }
413: cv.lightBin = this ;
414: cv.canvasDirty &= ~Canvas3D.LIGHTBIN_DIRTY;
415: // invalidate canvas cached enableMask
416: cv.enableMask = -1;
417: }
418: // across frames
419: else if ((cv.canvasDirty & Canvas3D.LIGHTBIN_DIRTY) != 0) {
420: // Just update the dirty lights
421: if (geometryBackground == null) {
422: scale = cv.canvasViewCache
423: .getVworldToCoexistenceScale();
424: cv.setModelViewMatrix(cv.ctx, cv.vpcToEc.mat,
425: renderBin.vworldToVpc);
426: } else {
427: scale = cv.canvasViewCache
428: .getInfVworldToCoexistenceScale();
429: cv.setModelViewMatrix(cv.ctx, cv.vpcToEc.mat,
430: renderBin.infVworldToVpc);
431: }
432: i = 0;
433: int mask = lightDirtyMask;
434: while (mask != 0) {
435: if ((mask & 1) != 0) {
436: lights[i].update(cv.ctx, i, scale);
437: cv.lights[i] = lights[i];
438: cv.frameCount[i] = frameCount;
439: }
440: mask >>= 1;
441: i++;
442: }
443:
444: cv.canvasDirty &= ~Canvas3D.LIGHTBIN_DIRTY;
445: } else if ((pointLts.size() > 0)
446: && ((cv.canvasDirty & Canvas3D.VIEW_MATRIX_DIRTY) != 0)) {
447: if (geometryBackground == null) {
448: scale = cv.canvasViewCache
449: .getVworldToCoexistenceScale();
450: cv.setModelViewMatrix(cv.ctx, cv.vpcToEc.mat,
451: renderBin.vworldToVpc);
452: } else {
453: scale = cv.canvasViewCache
454: .getInfVworldToCoexistenceScale();
455: cv.setModelViewMatrix(cv.ctx, cv.vpcToEc.mat,
456: renderBin.infVworldToVpc);
457: }
458: for (i = 0; i < pointLts.size(); i++) {
459: LightRetained lt = (LightRetained) pointLts.get(i);
460: lt.update(cv.ctx, pointLtsSlotIndex[i], scale);
461: cv.lights[pointLtsSlotIndex[i]] = lt;
462: cv.frameCount[pointLtsSlotIndex[i]] = frameCount;
463: }
464: }
465: }
466: }
|