0001: /*
0002: * $RCSfile: TextureRetained.java,v $
0003: *
0004: * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0006: *
0007: * This code is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU General Public License version 2 only, as
0009: * published by the Free Software Foundation. Sun designates this
0010: * particular file as subject to the "Classpath" exception as provided
0011: * by Sun in the LICENSE file that accompanied this code.
0012: *
0013: * This code is distributed in the hope that it will be useful, but WITHOUT
0014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0016: * version 2 for more details (a copy is included in the LICENSE file that
0017: * accompanied this code).
0018: *
0019: * You should have received a copy of the GNU General Public License version
0020: * 2 along with this work; if not, write to the Free Software Foundation,
0021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0022: *
0023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0024: * CA 95054 USA or visit www.sun.com if you need additional information or
0025: * have any questions.
0026: *
0027: * $Revision: 1.17 $
0028: * $Date: 2008/02/28 20:17:32 $
0029: * $State: Exp $
0030: */
0031:
0032: package javax.media.j3d;
0033:
0034: import java.util.*;
0035: import javax.vecmath.*;
0036: import java.awt.image.DataBufferByte;
0037: import java.awt.image.RenderedImage;
0038:
0039: /**
0040: * The Texture object is a component object of an Appearance object
0041: * that defines the texture properties used when texture mapping is
0042: * enabled. Texture object is an abstract class and all texture
0043: * objects must be created as either a Texture2D object or a
0044: * Texture3D object.
0045: */
0046: abstract class TextureRetained extends NodeComponentRetained {
0047: // A list of pre-defined bits to indicate which component
0048: // in this Texture object changed.
0049: static final int ENABLE_CHANGED = 0x001;
0050: static final int COLOR_CHANGED = 0x002;
0051: static final int IMAGE_CHANGED = 0x004;
0052: static final int STATE_CHANGED = 0x008;
0053: static final int UPDATE_IMAGE = 0x010;
0054: static final int IMAGES_CHANGED = 0x020;
0055: static final int BASE_LEVEL_CHANGED = 0x040;
0056: static final int MAX_LEVEL_CHANGED = 0x080;
0057: static final int MIN_LOD_CHANGED = 0x100;
0058: static final int MAX_LOD_CHANGED = 0x200;
0059: static final int LOD_OFFSET_CHANGED = 0x400;
0060:
0061: // constants for min and mag filter
0062: static final int MIN_FILTER = 0;
0063: static final int MAG_FILTER = 1;
0064:
0065: // Boundary width
0066: int boundaryWidth = 0;
0067:
0068: // Boundary modes (wrap, clamp, clamp_to_edge, clamp_to_boundary)
0069: int boundaryModeS = Texture.WRAP;
0070: int boundaryModeT = Texture.WRAP;
0071:
0072: // Filter modes
0073: int minFilter = Texture.BASE_LEVEL_POINT;
0074: int magFilter = Texture.BASE_LEVEL_POINT;
0075:
0076: // Integer flag that contains bitset to indicate
0077: // which field changed.
0078: int isDirty = 0xffff;
0079:
0080: // Texture boundary color
0081: Color4f boundaryColor = new Color4f(0.0f, 0.0f, 0.0f, 0.0f);
0082:
0083: // Texture Object Id used by native code.
0084: int objectId = -1;
0085:
0086: int mipmapMode = Texture.BASE_LEVEL; // Type of mip-mapping
0087: int format = Texture.RGB; // Texture format
0088: int width = 1; // Width in pixels (2**n)
0089: int height = 1; // Height in pixels (2**m)
0090:
0091: // true if width or height is non power of two
0092: private boolean widthOrHeightIsNPOT = false;
0093: // Array of images (one for each mipmap level)
0094: ImageComponentRetained images[][];
0095: // maximum number of levels needed for the mipmapMode of this texture
0096: int maxLevels = 0;
0097: // maximum number of mipmap levels that can be defined for this texture
0098: private int maxMipMapLevels = 0;
0099:
0100: int numFaces = 1; // For CubeMap, it is 6
0101: int baseLevel = 0;
0102: int maximumLevel = 0;
0103: float minimumLod = -1000.0f;
0104: float maximumLod = 1000.0f;
0105: Point3f lodOffset = null;
0106:
0107: private boolean useAsRaster = false; // true if used by Raster or Background.
0108:
0109: // Texture mapping enable switch
0110: // This enable is derived from the user specified enable
0111: // and whether the buf image in the imagecomp is null
0112: boolean enable = true;
0113:
0114: // User specified enable
0115: boolean userSpecifiedEnable = true;
0116:
0117: // true if alpha channel need update during rendering
0118: boolean isAlphaNeedUpdate = false;
0119:
0120: // sharpen texture info
0121: int numSharpenTextureFuncPts = 0;
0122: float sharpenTextureFuncPts[] = null; // array of pairs of floats
0123: // first value for LOD
0124: // second value for the fcn value
0125:
0126: // filter4 info
0127: float filter4FuncPts[] = null;
0128:
0129: // anisotropic filter info
0130: int anisotropicFilterMode = Texture.ANISOTROPIC_NONE;
0131: float anisotropicFilterDegree = 1.0f;
0132:
0133: // Each bit corresponds to a unique renderer if shared context
0134: // or a unique canvas otherwise.
0135: // This mask specifies which renderer/canvas has loaded the
0136: // texture images. 0 means no renderer/canvas has loaded the texture.
0137: // 1 at the particular bit means that renderer/canvas has loaded the
0138: // texture. 0 means otherwise.
0139: int resourceCreationMask = 0x0;
0140:
0141: // Each bit corresponds to a unique renderer if shared context
0142: // or a unique canvas otherwise
0143: // This mask specifies if texture images are up-to-date.
0144: // 0 at a particular bit means texture images are not up-to-date.
0145: // 1 means otherwise. If it specifies 0, then it needs to go
0146: // through the imageUpdateInfo to update the images accordingly.
0147: //
0148: int resourceUpdatedMask = 0x0;
0149:
0150: // Each bit corresponds to a unique renderer if shared context
0151: // or a unique canvas otherwise
0152: // This mask specifies if texture lod info is up-to-date.
0153: // 0 at a particular bit means texture lod info is not up-to-date.
0154: // 1 means otherwise.
0155: //
0156: int resourceLodUpdatedMask = 0x0;
0157:
0158: // Each bit corresponds to a unique renderer if shared context
0159: // or a unique canvas otherwise
0160: // This mask specifies if texture is in the resource reload list
0161: // 0 at a particular bit means texture is not in reload list
0162: // 1 means otherwise.
0163: //
0164: int resourceInReloadList = 0x0;
0165:
0166: // image update info
0167: ArrayList imageUpdateInfo[][];
0168:
0169: int imageUpdatePruneMask[];
0170:
0171: // Issue 357 - we need a separate reference counter per RenderBin, since
0172: // each RenderBin keeps an independent list of Texture objects to be freed.
0173: // Since this is accessed infrequently, we will use a HashMap for the
0174: // textureBin reference counter
0175: private HashMap<RenderBin, Integer> textureBinRefCount = new HashMap<RenderBin, Integer>();
0176:
0177: // This is used for D3D only to check whether texture need to
0178: // resend down
0179: private int texTimestamp = 0;
0180:
0181: // need to synchronize access from multiple rendering threads
0182: Object resourceLock = new Object();
0183:
0184: private static boolean isPowerOfTwo(int val) {
0185: return ((val & (val - 1)) == 0);
0186: }
0187:
0188: void initialize(int format, int width, int widLevels, int height,
0189: int heiLevels, int mipmapMode, int boundaryWidth) {
0190:
0191: this .mipmapMode = mipmapMode;
0192: this .format = format;
0193: this .width = width;
0194: this .height = height;
0195: this .boundaryWidth = boundaryWidth;
0196:
0197: if (!isPowerOfTwo(width) || !isPowerOfTwo(height)) {
0198: this .widthOrHeightIsNPOT = true;
0199: }
0200:
0201: // determine the maximum number of mipmap levels that can be
0202: // defined from the specified dimension
0203:
0204: if (widLevels > heiLevels) {
0205: maxMipMapLevels = widLevels + 1;
0206: } else {
0207: maxMipMapLevels = heiLevels + 1;
0208: }
0209:
0210: // determine the maximum number of mipmap levels that will be
0211: // needed with the current mipmapMode
0212:
0213: if (mipmapMode != Texture.BASE_LEVEL) {
0214: baseLevel = 0;
0215: maximumLevel = maxMipMapLevels - 1;
0216: maxLevels = maxMipMapLevels;
0217: } else {
0218: baseLevel = 0;
0219: maximumLevel = 0;
0220: maxLevels = 1;
0221: }
0222:
0223: images = new ImageComponentRetained[numFaces][maxLevels];
0224:
0225: for (int j = 0; j < numFaces; j++) {
0226: for (int i = 0; i < maxLevels; i++) {
0227: images[j][i] = null;
0228: }
0229: }
0230: }
0231:
0232: final int getFormat() {
0233: return this .format;
0234: }
0235:
0236: final int getWidth() {
0237: return this .width;
0238: }
0239:
0240: final int getHeight() {
0241: return this .height;
0242: }
0243:
0244: final int numMipMapLevels() {
0245: return (maximumLevel - baseLevel + 1);
0246: }
0247:
0248: /**
0249: * Sets the boundary mode for the S coordinate in this texture object.
0250: * @param boundaryModeS the boundary mode for the S coordinate,
0251: * one of: CLAMP or WRAP.
0252: * @exception RestrictedAccessException if the method is called
0253: * when this object is part of live or compiled scene graph.
0254: */
0255: final void initBoundaryModeS(int boundaryModeS) {
0256: this .boundaryModeS = boundaryModeS;
0257: }
0258:
0259: /**
0260: * Retrieves the boundary mode for the S coordinate.
0261: * @return the current boundary mode for the S coordinate.
0262: * @exception RestrictedAccessException if the method is called
0263: * when this object is part of live or compiled scene graph.
0264: */
0265: final int getBoundaryModeS() {
0266: return boundaryModeS;
0267: }
0268:
0269: /**
0270: * Sets the boundary mode for the T coordinate in this texture object.
0271: * @param boundaryModeT the boundary mode for the T coordinate,
0272: * one of: CLAMP or WRAP.
0273: * @exception RestrictedAccessException if the method is called
0274: * when this object is part of live or compiled scene graph.
0275: */
0276: final void initBoundaryModeT(int boundaryModeT) {
0277: this .boundaryModeT = boundaryModeT;
0278: }
0279:
0280: /**
0281: * Retrieves the boundary mode for the T coordinate.
0282: * @return the current boundary mode for the T coordinate.
0283: * @exception RestrictedAccessException if the method is called
0284: * when this object is part of live or compiled scene graph.
0285: */
0286: final int getBoundaryModeT() {
0287: return boundaryModeT;
0288: }
0289:
0290: /**
0291: * Retrieves the boundary width.
0292: * @return the boundary width of this texture.
0293: */
0294: final int getBoundaryWidth() {
0295: return boundaryWidth;
0296: }
0297:
0298: /**
0299: * Sets the minification filter function. This
0300: * function is used when the pixel being rendered maps to an area
0301: * greater than one texel.
0302: * @param minFilter the minification filter, one of:
0303: * FASTEST, NICEST, BASE_LEVEL_POINT, BASE_LEVEL_LINEAR,
0304: * MULTI_LEVEL_POINT, MULTI_LEVEL_LINEAR.
0305: * @exception RestrictedAccessException if the method is called
0306: * when this object is part of live or compiled scene graph.
0307: */
0308: final void initMinFilter(int minFilter) {
0309: this .minFilter = minFilter;
0310: }
0311:
0312: /**
0313: * Retrieves the minification filter.
0314: * @return the current minification filter function.
0315: * @exception RestrictedAccessException if the method is called
0316: * when this object is part of live or compiled scene graph.
0317: */
0318: final int getMinFilter() {
0319: return minFilter;
0320: }
0321:
0322: /**
0323: * Sets the magnification filter function. This
0324: * function is used when the pixel being rendered maps to an area
0325: * less than or equal to one texel.
0326: * @param magFilter the magnification filter, one of:
0327: * FASTEST, NICEST, BASE_LEVEL_POINT, or BASE_LEVEL_LINEAR.
0328: * @exception RestrictedAccessException if the method is called
0329: * when this object is part of live or compiled scene graph.
0330: */
0331: final void initMagFilter(int magFilter) {
0332: this .magFilter = magFilter;
0333: }
0334:
0335: /**
0336: * Retrieves the magnification filter.
0337: * @return the current magnification filter function.
0338: * @exception RestrictedAccessException if the method is called
0339: * when this object is part of live or compiled scene graph.
0340: */
0341: final int getMagFilter() {
0342: return magFilter;
0343: }
0344:
0345: /**
0346: * Sets a specified mipmap level.
0347: * @param level mipmap level to set: 0 is the base level
0348: * @param image pixel array object containing the texture image
0349: * @exception RestrictedAccessException if the method is called
0350: * when this object is part of live or compiled scene graph.
0351: * @exception IllegalArgumentException if an ImageComponent3D
0352: * is used in a Texture2D or ImageComponent2D in Texture3D
0353: * power of 2 OR invalid format/mipmapMode is specified.
0354: */
0355: void initImage(int level, ImageComponent image) {
0356:
0357: // Issue 172 : call checkImageSize even for non-live setImage calls
0358: checkImageSize(level, image);
0359:
0360: if (this .images == null) {
0361: throw new IllegalArgumentException(J3dI18N
0362: .getString("TextureRetained0"));
0363: }
0364:
0365: if (this .source instanceof Texture2D) {
0366: if (image instanceof ImageComponent3D)
0367: throw new IllegalArgumentException(J3dI18N
0368: .getString("Texture8"));
0369: } else {
0370:
0371: if (image instanceof ImageComponent2D)
0372: throw new IllegalArgumentException(J3dI18N
0373: .getString("Texture14"));
0374: }
0375:
0376: if (this .source.isLive()) {
0377:
0378: if (this .images[0][level] != null) {
0379: this .images[0][level].clearLive(refCount);
0380: }
0381:
0382: if (image != null) {
0383: ((ImageComponentRetained) image.retained).setLive(
0384: inBackgroundGroup, refCount);
0385: }
0386: }
0387:
0388: if (image != null) {
0389: this .images[0][level] = (ImageComponentRetained) image.retained;
0390:
0391: } else {
0392: this .images[0][level] = null;
0393: }
0394: }
0395:
0396: final void checkImageSize(int level, ImageComponent image) {
0397: if (image != null) {
0398: int imgWidth = ((ImageComponentRetained) image.retained).width;
0399: int imgHeight = ((ImageComponentRetained) image.retained).height;
0400:
0401: int wdh = width;
0402: int hgt = height;
0403: for (int i = 0; i < level; i++) {
0404: wdh >>= 1;
0405: hgt >>= 1;
0406: }
0407:
0408: if (wdh < 1)
0409: wdh = 1;
0410: if (hgt < 1)
0411: hgt = 1;
0412:
0413: if ((wdh != (imgWidth - 2 * boundaryWidth))
0414: || (hgt != (imgHeight - 2 * boundaryWidth))) {
0415: throw new IllegalArgumentException(J3dI18N
0416: .getString("TextureRetained1"));
0417: }
0418: }
0419: }
0420:
0421: final void checkSizes(ImageComponentRetained images[]) {
0422: // Issue 172 : this method is now redundant
0423:
0424: // Assertion check that the image at each level is the correct size
0425: // This shouldn't be needed since we already should have checked the
0426: // size at each level, and verified that all levels are set.
0427: if (images != null) {
0428: int hgt = height;
0429: int wdh = width;
0430: for (int level = 0; level < images.length; level++) {
0431: int imgWidth = images[level].width;
0432: int imgHeight = images[level].height;
0433:
0434: assert (wdh == (imgWidth - 2 * boundaryWidth))
0435: && (hgt == (imgHeight - 2 * boundaryWidth));
0436:
0437: wdh /= 2;
0438: hgt /= 2;
0439: if (wdh < 1)
0440: wdh = 1;
0441: if (hgt < 1)
0442: hgt = 1;
0443: }
0444: }
0445: }
0446:
0447: final void setImage(int level, ImageComponent image) {
0448: initImage(level, image);
0449:
0450: Object arg[] = new Object[3];
0451: arg[0] = new Integer(level);
0452: arg[1] = image;
0453: arg[2] = new Integer(0);
0454: sendMessage(IMAGE_CHANGED, arg);
0455:
0456: // If the user has set enable to true, then if the image is null
0457: // turn off texture enable
0458:
0459: if (userSpecifiedEnable) {
0460: enable = userSpecifiedEnable;
0461: if (image != null && level >= baseLevel
0462: && level <= maximumLevel) {
0463: ImageComponentRetained img = (ImageComponentRetained) image.retained;
0464: if (img.isByReference()) {
0465: if (img.getRefImage(0) == null) {
0466: enable = false;
0467: }
0468: } else {
0469: if (img.getImageData(isUseAsRaster()).get() == null) {
0470: enable = false;
0471: }
0472: }
0473: if (!enable)
0474: sendMessage(ENABLE_CHANGED, Boolean.FALSE);
0475: }
0476: }
0477: }
0478:
0479: void initImages(ImageComponent[] images) {
0480:
0481: if (images.length != maxLevels)
0482: throw new IllegalArgumentException(J3dI18N
0483: .getString("Texture20"));
0484:
0485: for (int i = 0; i < images.length; i++) {
0486: initImage(i, images[i]);
0487: }
0488: }
0489:
0490: final void setImages(ImageComponent[] images) {
0491:
0492: int i;
0493:
0494: initImages(images);
0495:
0496: ImageComponent[] imgs = new ImageComponent[images.length];
0497: for (i = 0; i < images.length; i++) {
0498: imgs[i] = images[i];
0499: }
0500:
0501: Object arg[] = new Object[2];
0502: arg[0] = imgs;
0503: arg[1] = new Integer(0);
0504:
0505: sendMessage(IMAGES_CHANGED, arg);
0506:
0507: // If the user has set enable to true, then if the image is null
0508: // turn off texture enable
0509:
0510: if (userSpecifiedEnable) {
0511: enable = userSpecifiedEnable;
0512: for (i = baseLevel; i <= maximumLevel && enable; i++) {
0513: if (images[i] != null) {
0514: ImageComponentRetained img = (ImageComponentRetained) images[i].retained;
0515: if (img.isByReference()) {
0516: if (img.getRefImage(0) == null) {
0517: enable = false;
0518: }
0519: } else {
0520: if (img.getImageData(isUseAsRaster()).get() == null) {
0521: enable = false;
0522: }
0523: }
0524: }
0525: }
0526: if (!enable) {
0527: sendMessage(ENABLE_CHANGED, Boolean.FALSE);
0528: }
0529: }
0530: }
0531:
0532: /**
0533: * Gets a specified mipmap level.
0534: * @param level mipmap level to get: 0 is the base level
0535: * @return the pixel array object containing the texture image
0536: * @exception RestrictedAccessException if the method is called
0537: * when this object is part of live or compiled scene graph.
0538: */
0539: final ImageComponent getImage(int level) {
0540: return (((images != null) && (images[0][level] != null)) ? (ImageComponent) images[0][level].source
0541: : null);
0542: }
0543:
0544: final ImageComponent[] getImages() {
0545: if (images == null)
0546: return null;
0547:
0548: ImageComponent[] rImages = new ImageComponent[images[0].length];
0549: for (int i = 0; i < images[0].length; i++) {
0550: if (images[0][i] != null)
0551: rImages[i] = (ImageComponent) images[0][i].source;
0552: else
0553: rImages[i] = null;
0554: }
0555: return rImages;
0556: }
0557:
0558: /**
0559: * Sets mipmap mode for texture mapping for this texture object.
0560: * @param mipMapMode the new mipmap mode for this object. One of:
0561: * BASE_LEVEL or MULTI_LEVEL_MIPMAP.
0562: * @exception RestrictedAccessException if the method is called
0563: */
0564: final void initMipMapMode(int mipmapMode) {
0565:
0566: if (this .mipmapMode == mipmapMode)
0567: return;
0568:
0569: int prevMaxLevels = maxLevels; // previous maxLevels
0570:
0571: this .mipmapMode = mipmapMode;
0572:
0573: if (mipmapMode != Texture.BASE_LEVEL) {
0574: maxLevels = maxMipMapLevels;
0575: } else {
0576: baseLevel = 0;
0577: maximumLevel = 0;
0578: maxLevels = 1;
0579: }
0580:
0581: ImageComponentRetained[][] newImages = new ImageComponentRetained[numFaces][maxLevels];
0582:
0583: if (prevMaxLevels < maxLevels) {
0584: for (int f = 0; f < numFaces; f++) {
0585: for (int i = 0; i < prevMaxLevels; i++) {
0586: newImages[f][i] = images[f][i];
0587: }
0588:
0589: for (int j = prevMaxLevels; j < maxLevels; j++) {
0590: newImages[f][j] = null;
0591: }
0592: }
0593: } else {
0594: for (int f = 0; f < numFaces; f++) {
0595: for (int i = 0; i < maxLevels; i++)
0596: newImages[f][i] = images[f][i];
0597: }
0598: }
0599: images = newImages;
0600: }
0601:
0602: /**
0603: * Retrieves current mipmap mode.
0604: * @return current mipmap mode of this texture object.
0605: * @exception RestrictedAccessException if the method is called
0606: */
0607: final int getMipMapMode() {
0608: return this .mipmapMode;
0609: }
0610:
0611: /**
0612: * Enables or disables texture mapping for this
0613: * appearance component object.
0614: * @param state true or false to enable or disable texture mapping
0615: */
0616: final void initEnable(boolean state) {
0617: userSpecifiedEnable = state;
0618: }
0619:
0620: /**
0621: * Enables or disables texture mapping for this
0622: * appearance component object and sends a
0623: * message notifying the interested structures of the change.
0624: * @param state true or false to enable or disable texture mapping
0625: */
0626: final void setEnable(boolean state) {
0627:
0628: initEnable(state);
0629:
0630: if (state == enable) {
0631: // if enable flag is same as user specified one
0632: // this is only possible when enable is false
0633: // because one of the images is null and user specifies false
0634: return;
0635: }
0636:
0637: enable = state;
0638:
0639: for (int j = 0; j < numFaces && enable; j++) {
0640: for (int i = baseLevel; i <= maximumLevel && enable; i++) {
0641: if (images[j][i].isByReference()) {
0642: if (images[j][i].getRefImage(0) == null) {
0643: enable = false;
0644: }
0645: } else {
0646: if (images[j][i].getImageData(isUseAsRaster())
0647: .get() == null) {
0648: enable = false;
0649: }
0650: }
0651: }
0652: }
0653: sendMessage(ENABLE_CHANGED, (enable ? Boolean.TRUE
0654: : Boolean.FALSE));
0655: }
0656:
0657: /**
0658: * Retrieves the state of the texture enable flag.
0659: * @return true if texture mapping is enabled,
0660: * false if texture mapping is disabled
0661: */
0662: final boolean getEnable() {
0663: return userSpecifiedEnable;
0664: }
0665:
0666: final void initBaseLevel(int level) {
0667: if ((level < 0) || (level > maximumLevel)) {
0668: throw new IllegalArgumentException(J3dI18N
0669: .getString("Texture36"));
0670: }
0671: baseLevel = level;
0672: }
0673:
0674: final void setBaseLevel(int level) {
0675:
0676: if (level == baseLevel)
0677: return;
0678:
0679: initBaseLevel(level);
0680: sendMessage(BASE_LEVEL_CHANGED, new Integer(level));
0681: }
0682:
0683: final int getBaseLevel() {
0684: return baseLevel;
0685: }
0686:
0687: final void initMaximumLevel(int level) {
0688: if ((level < baseLevel) || (level >= maxMipMapLevels)) {
0689: throw new IllegalArgumentException(J3dI18N
0690: .getString("Texture37"));
0691: }
0692: if ((mipmapMode == Texture.BASE_LEVEL) && (level != 0)) {
0693: throw new IllegalArgumentException(J3dI18N
0694: .getString("Texture48"));
0695: }
0696:
0697: maximumLevel = level;
0698: }
0699:
0700: final void setMaximumLevel(int level) {
0701:
0702: if (level == maximumLevel)
0703: return;
0704:
0705: initMaximumLevel(level);
0706: sendMessage(MAX_LEVEL_CHANGED, new Integer(level));
0707: }
0708:
0709: final int getMaximumLevel() {
0710: return maximumLevel;
0711: }
0712:
0713: final void initMinimumLOD(float lod) {
0714: if (lod > maximumLod) {
0715: throw new IllegalArgumentException(J3dI18N
0716: .getString("Texture42"));
0717: }
0718: minimumLod = lod;
0719: }
0720:
0721: final void setMinimumLOD(float lod) {
0722: initMinimumLOD(lod);
0723: sendMessage(MIN_LOD_CHANGED, new Float(lod));
0724: }
0725:
0726: final float getMinimumLOD() {
0727: return minimumLod;
0728: }
0729:
0730: final void initMaximumLOD(float lod) {
0731: if (lod < minimumLod) {
0732: throw new IllegalArgumentException(J3dI18N
0733: .getString("Texture42"));
0734: }
0735: maximumLod = lod;
0736: }
0737:
0738: final void setMaximumLOD(float lod) {
0739: initMaximumLOD(lod);
0740: sendMessage(MAX_LOD_CHANGED, new Float(lod));
0741: }
0742:
0743: final float getMaximumLOD() {
0744: return maximumLod;
0745: }
0746:
0747: final void initLodOffset(float s, float t, float r) {
0748: if (lodOffset == null) {
0749: lodOffset = new Point3f(s, t, r);
0750: } else {
0751: lodOffset.set(s, t, r);
0752: }
0753: }
0754:
0755: final void setLodOffset(float s, float t, float r) {
0756: initLodOffset(s, t, r);
0757: sendMessage(LOD_OFFSET_CHANGED, new Point3f(s, t, r));
0758: }
0759:
0760: final void getLodOffset(Tuple3f offset) {
0761: if (lodOffset == null) {
0762: offset.set(0.0f, 0.0f, 0.0f);
0763: } else {
0764: offset.set(lodOffset);
0765: }
0766: }
0767:
0768: /**
0769: * Sets the texture boundary color for this texture object. The
0770: * texture boundary color is used when boundaryModeS or boundaryModeT
0771: * is set to CLAMP.
0772: * @param boundaryColor the new texture boundary color.
0773: */
0774: final void initBoundaryColor(Color4f boundaryColor) {
0775: this .boundaryColor.set(boundaryColor);
0776: }
0777:
0778: /**
0779: * Sets the texture boundary color for this texture object. The
0780: * texture boundary color is used when boundaryModeS or boundaryModeT
0781: * is set to CLAMP.
0782: * @param r the red component of the color.
0783: * @param g the green component of the color.
0784: * @param b the blue component of the color.
0785: * @param a the alpha component of the color.
0786: */
0787: final void initBoundaryColor(float r, float g, float b, float a) {
0788: this .boundaryColor.set(r, g, b, a);
0789: }
0790:
0791: /**
0792: * Retrieves the texture boundary color for this texture object.
0793: * @param boundaryColor the vector that will receive the
0794: * current texture boundary color.
0795: */
0796: final void getBoundaryColor(Color4f boundaryColor) {
0797: boundaryColor.set(this .boundaryColor);
0798: }
0799:
0800: /**
0801: * Set Anisotropic Filter
0802: */
0803: final void initAnisotropicFilterMode(int mode) {
0804: anisotropicFilterMode = mode;
0805: }
0806:
0807: final int getAnisotropicFilterMode() {
0808: return anisotropicFilterMode;
0809: }
0810:
0811: final void initAnisotropicFilterDegree(float degree) {
0812: anisotropicFilterDegree = degree;
0813: }
0814:
0815: final float getAnisotropicFilterDegree() {
0816: return anisotropicFilterDegree;
0817: }
0818:
0819: /**
0820: * Set Sharpen Texture function
0821: */
0822: final void initSharpenTextureFunc(float[] lod, float[] pts) {
0823: if (lod == null) { // pts will be null too.
0824: sharpenTextureFuncPts = null;
0825: numSharpenTextureFuncPts = 0;
0826: } else {
0827: numSharpenTextureFuncPts = lod.length;
0828: if ((sharpenTextureFuncPts == null)
0829: || (sharpenTextureFuncPts.length != lod.length * 2)) {
0830: sharpenTextureFuncPts = new float[lod.length * 2];
0831: }
0832: for (int i = 0, j = 0; i < lod.length; i++) {
0833: sharpenTextureFuncPts[j++] = lod[i];
0834: sharpenTextureFuncPts[j++] = pts[i];
0835: }
0836: }
0837: }
0838:
0839: final void initSharpenTextureFunc(Point2f[] pts) {
0840: if (pts == null) {
0841: sharpenTextureFuncPts = null;
0842: numSharpenTextureFuncPts = 0;
0843: } else {
0844: numSharpenTextureFuncPts = pts.length;
0845: if ((sharpenTextureFuncPts == null)
0846: || (sharpenTextureFuncPts.length != pts.length * 2)) {
0847: sharpenTextureFuncPts = new float[pts.length * 2];
0848: }
0849: for (int i = 0, j = 0; i < pts.length; i++) {
0850: sharpenTextureFuncPts[j++] = pts[i].x;
0851: sharpenTextureFuncPts[j++] = pts[i].y;
0852: }
0853: }
0854: }
0855:
0856: final void initSharpenTextureFunc(float[] pts) {
0857: if (pts == null) {
0858: sharpenTextureFuncPts = null;
0859: numSharpenTextureFuncPts = 0;
0860: } else {
0861: numSharpenTextureFuncPts = pts.length / 2;
0862: if ((sharpenTextureFuncPts == null)
0863: || (sharpenTextureFuncPts.length != pts.length)) {
0864: sharpenTextureFuncPts = new float[pts.length];
0865: }
0866: for (int i = 0; i < pts.length; i++) {
0867: sharpenTextureFuncPts[i] = pts[i];
0868: }
0869: }
0870: }
0871:
0872: /**
0873: * Get number of points in the sharpen texture LOD function
0874: */
0875: final int getSharpenTextureFuncPointsCount() {
0876: return numSharpenTextureFuncPts;
0877: }
0878:
0879: /**
0880: * Copies the array of sharpen texture LOD function points into the
0881: * specified arrays
0882: */
0883: final void getSharpenTextureFunc(float[] lod, float[] pts) {
0884: if (sharpenTextureFuncPts != null) {
0885: for (int i = 0, j = 0; i < numSharpenTextureFuncPts; i++) {
0886: lod[i] = sharpenTextureFuncPts[j++];
0887: pts[i] = sharpenTextureFuncPts[j++];
0888: }
0889: }
0890: }
0891:
0892: final void getSharpenTextureFunc(Point2f[] pts) {
0893: if (sharpenTextureFuncPts != null) {
0894: for (int i = 0, j = 0; i < numSharpenTextureFuncPts; i++) {
0895: pts[i].x = sharpenTextureFuncPts[j++];
0896: pts[i].y = sharpenTextureFuncPts[j++];
0897: }
0898: }
0899: }
0900:
0901: final void initFilter4Func(float[] weights) {
0902: if (weights == null) {
0903: filter4FuncPts = null;
0904: } else {
0905: if ((filter4FuncPts == null)
0906: || (filter4FuncPts.length != weights.length)) {
0907: filter4FuncPts = new float[weights.length];
0908: }
0909: for (int i = 0; i < weights.length; i++) {
0910: filter4FuncPts[i] = weights[i];
0911: }
0912: }
0913: }
0914:
0915: final int getFilter4FuncPointsCount() {
0916: if (filter4FuncPts == null) {
0917: return 0;
0918: } else {
0919: return filter4FuncPts.length;
0920: }
0921: }
0922:
0923: final void getFilter4Func(float[] weights) {
0924: if (filter4FuncPts != null) {
0925: for (int i = 0; i < filter4FuncPts.length; i++) {
0926: weights[i] = filter4FuncPts[i];
0927: }
0928: }
0929: }
0930:
0931: /**
0932: * internal method only -- returns internal function points
0933: */
0934: final float[] getSharpenTextureFunc() {
0935: return sharpenTextureFuncPts;
0936: }
0937:
0938: final float[] getFilter4Func() {
0939: return filter4FuncPts;
0940: }
0941:
0942: void setLive(boolean backgroundGroup, int refCount) {
0943:
0944: // This line should be assigned before calling doSetLive, so that
0945: // the mirror object's enable is assigned correctly!
0946: enable = userSpecifiedEnable;
0947:
0948: super .doSetLive(backgroundGroup, refCount);
0949:
0950: // XXXX: for now, do setLive for all the defined images.
0951: // But in theory, we only need to setLive those within the
0952: // baseLevel and maximumLevel range. But then we'll need
0953: // setLive and clearLive image when the range changes.
0954:
0955: if (images != null) {
0956:
0957: for (int j = 0; j < numFaces; j++) {
0958: for (int i = 0; i < maxLevels; i++) {
0959: if (images[j][i] == null) {
0960: throw new IllegalArgumentException(J3dI18N
0961: .getString("TextureRetained3")
0962: + i);
0963: }
0964: images[j][i].setLive(backgroundGroup, refCount);
0965: }
0966: }
0967: }
0968:
0969: // Issue 172 : assertion check the sizes of the images after we have
0970: // checked for all mipmap levels being set
0971: if (images != null) {
0972: for (int j = 0; j < numFaces; j++) {
0973: checkSizes(images[j]);
0974: }
0975: }
0976:
0977: // Send a message to Rendering Attr stucture to update the resourceMask
0978: J3dMessage createMessage = new J3dMessage();
0979: createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES;
0980: createMessage.type = J3dMessage.TEXTURE_CHANGED;
0981: createMessage.args[0] = this ;
0982: createMessage.args[1] = new Integer(UPDATE_IMAGE);
0983: createMessage.args[2] = null;
0984: createMessage.args[3] = new Integer(changedFrequent);
0985: VirtualUniverse.mc.processMessage(createMessage);
0986:
0987: // If the user has set enable to true, then if the image is null
0988: // turn off texture enable
0989: if (userSpecifiedEnable) {
0990: if (images != null) {
0991: for (int j = 0; j < numFaces && enable; j++) {
0992: for (int i = baseLevel; i <= maximumLevel && enable; i++) {
0993: if (images[j][i].isByReference()) {
0994: if (images[j][i].getRefImage(0) == null) {
0995: enable = false;
0996: }
0997: } else {
0998: if (images[j][i].getImageData(
0999: isUseAsRaster()).get() == null) {
1000: enable = false;
1001: }
1002: }
1003: }
1004: }
1005: } else {
1006: enable = false;
1007: }
1008: if (!enable)
1009: sendMessage(ENABLE_CHANGED, Boolean.FALSE);
1010: }
1011:
1012: super .markAsLive();
1013: }
1014:
1015: void clearLive(int refCount) {
1016: super .clearLive(refCount);
1017:
1018: if (images != null) {
1019: for (int j = 0; j < numFaces; j++) {
1020: for (int i = 0; i < maxLevels; i++) {
1021: images[j][i].clearLive(refCount);
1022: images[j][i].removeUser(mirror);
1023: }
1024: }
1025: }
1026: }
1027:
1028: /*
1029: * The following methods update the native context.
1030: * The implementation for Texture2D happens here.
1031: * Texture3D and TextureCubeMap implement their own versions.
1032: */
1033:
1034: void bindTexture(Context ctx, int objectId, boolean enable) {
1035: Pipeline.getPipeline().bindTexture2D(ctx, objectId, enable);
1036: }
1037:
1038: void updateTextureBoundary(Context ctx, int boundaryModeS,
1039: int boundaryModeT, float boundaryRed, float boundaryGreen,
1040: float boundaryBlue, float boundaryAlpha) {
1041:
1042: Pipeline.getPipeline().updateTexture2DBoundary(ctx,
1043: boundaryModeS, boundaryModeT, boundaryRed,
1044: boundaryGreen, boundaryBlue, boundaryAlpha);
1045: }
1046:
1047: void updateTextureFilterModes(Context ctx, int minFilter,
1048: int magFilter) {
1049:
1050: Pipeline.getPipeline().updateTexture2DFilterModes(ctx,
1051: minFilter, magFilter);
1052: }
1053:
1054: void updateTextureSharpenFunc(Context ctx,
1055: int numSharpenTextureFuncPts, float[] sharpenTextureFuncPts) {
1056:
1057: Pipeline.getPipeline().updateTexture2DSharpenFunc(ctx,
1058: numSharpenTextureFuncPts, sharpenTextureFuncPts);
1059: }
1060:
1061: void updateTextureFilter4Func(Context ctx, int numFilter4FuncPts,
1062: float[] filter4FuncPts) {
1063:
1064: Pipeline.getPipeline().updateTexture2DFilter4Func(ctx,
1065: numFilter4FuncPts, filter4FuncPts);
1066: }
1067:
1068: void updateTextureAnisotropicFilter(Context ctx, float degree) {
1069: Pipeline.getPipeline().updateTexture2DAnisotropicFilter(ctx,
1070: degree);
1071: }
1072:
1073: void updateTextureLodRange(Context ctx, int baseLevel,
1074: int maximumLevel, float minimumLod, float maximumLod) {
1075:
1076: Pipeline.getPipeline().updateTexture2DLodRange(ctx, baseLevel,
1077: maximumLevel, minimumLod, maximumLod);
1078: }
1079:
1080: void updateTextureLodOffset(Context ctx, float lodOffsetX,
1081: float lodOffsetY, float lodOffsetZ) {
1082:
1083: Pipeline.getPipeline().updateTexture2DLodOffset(ctx,
1084: lodOffsetX, lodOffsetY, lodOffsetZ);
1085: }
1086:
1087: // get an ID for Texture 2D
1088: int getTextureId() {
1089: return (VirtualUniverse.mc.getTexture2DId());
1090: }
1091:
1092: // free a Texture2D id
1093: void freeTextureId(int id) {
1094: synchronized (resourceLock) {
1095: if (objectId == id) {
1096: objectId = -1;
1097: VirtualUniverse.mc.freeTexture2DId(id);
1098: }
1099: }
1100: }
1101:
1102: private boolean isEnabled(Canvas3D cv) {
1103: if (widthOrHeightIsNPOT
1104: && !isUseAsRaster()
1105: && ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_NON_POWER_OF_TWO) == 0)) {
1106: return false;
1107: }
1108: return enable;
1109: }
1110:
1111: // bind a named texture to a texturing target
1112: void bindTexture(Canvas3D cv) {
1113:
1114: synchronized (resourceLock) {
1115: if (objectId == -1) {
1116: objectId = getTextureId();
1117: }
1118: cv.addTextureResource(objectId, this );
1119: }
1120: bindTexture(cv.ctx, objectId, isEnabled(cv));
1121: }
1122:
1123: /**
1124: * load level 0 explicitly with null pointer to enable
1125: * mipmapping when level 0 is not the base level
1126: */
1127: void updateTextureDimensions(Canvas3D cv) {
1128: if (images[0][0] != null) {
1129: updateTextureImage(cv, 0, maxLevels, 0, format,
1130: images[0][0].getImageFormatTypeIntValue(false),
1131: width, height, boundaryWidth, images[0][0]
1132: .getImageDataTypeIntValue(), null);
1133: }
1134: }
1135:
1136: void updateTextureLOD(Canvas3D cv) {
1137:
1138: if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_LOD_RANGE) != 0) {
1139:
1140: int max = 0;
1141: if (mipmapMode == Texture.BASE_LEVEL) {
1142: max = maxMipMapLevels;
1143: } else {
1144: max = maximumLevel;
1145: }
1146:
1147: updateTextureLodRange(cv.ctx, baseLevel, max, minimumLod,
1148: maximumLod);
1149: }
1150:
1151: if ((lodOffset != null)
1152: && ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_LOD_OFFSET) != 0)) {
1153: updateTextureLodOffset(cv.ctx, lodOffset.x, lodOffset.y,
1154: lodOffset.z);
1155: }
1156: }
1157:
1158: void updateTextureBoundary(Canvas3D cv) {
1159: updateTextureBoundary(cv.ctx, boundaryModeS, boundaryModeT,
1160: boundaryColor.x, boundaryColor.y, boundaryColor.z,
1161: boundaryColor.w);
1162: }
1163:
1164: void updateTextureFields(Canvas3D cv) {
1165:
1166: int magnificationFilter = magFilter;
1167: int minificationFilter = minFilter;
1168:
1169: // update sharpen texture function if applicable
1170:
1171: if ((magnificationFilter >= Texture.LINEAR_SHARPEN)
1172: && (magnificationFilter <= Texture.LINEAR_SHARPEN_ALPHA)) {
1173:
1174: if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_SHARPEN) != 0) {
1175:
1176: // send down sharpen texture LOD function
1177: //
1178: updateTextureSharpenFunc(cv.ctx,
1179: numSharpenTextureFuncPts, sharpenTextureFuncPts);
1180:
1181: } else {
1182:
1183: // sharpen texture is not supported by the underlying
1184: // library, fallback to BASE_LEVEL_LINEAR
1185:
1186: magnificationFilter = Texture.BASE_LEVEL_LINEAR;
1187: }
1188: } else if ((magnificationFilter >= Texture2D.LINEAR_DETAIL)
1189: && (magnificationFilter <= Texture2D.LINEAR_DETAIL_ALPHA)) {
1190: if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_DETAIL) == 0) {
1191:
1192: // detail texture is not supported by the underlying
1193: // library, fallback to BASE_LEVEL_LINEAR
1194:
1195: magnificationFilter = Texture.BASE_LEVEL_LINEAR;
1196: }
1197: }
1198:
1199: if (minificationFilter == Texture.FILTER4
1200: || magnificationFilter == Texture.FILTER4) {
1201:
1202: boolean noFilter4 = false;
1203:
1204: if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_FILTER4) != 0) {
1205:
1206: if (filter4FuncPts == null) {
1207:
1208: // filter4 function is not defined,
1209: // fallback to BASE_LEVEL_LINEAR
1210:
1211: noFilter4 = true;
1212: } else {
1213: updateTextureFilter4Func(cv.ctx,
1214: filter4FuncPts.length, filter4FuncPts);
1215: }
1216: } else {
1217:
1218: // filter4 is not supported by the underlying
1219: // library, fallback to BASE_LEVEL_LINEAR
1220:
1221: noFilter4 = true;
1222: }
1223:
1224: if (noFilter4) {
1225: if (minificationFilter == Texture.FILTER4) {
1226: minificationFilter = Texture.BASE_LEVEL_LINEAR;
1227: }
1228: if (magnificationFilter == Texture.FILTER4) {
1229: magnificationFilter = Texture.BASE_LEVEL_LINEAR;
1230: }
1231: }
1232: }
1233:
1234: // Fallback to BASE mode if hardware mipmap generation is not supported.
1235: if ((mipmapMode == Texture.BASE_LEVEL)
1236: && ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_AUTO_MIPMAP_GENERATION) == 0)) {
1237:
1238: if (minificationFilter == Texture.NICEST
1239: || minificationFilter == Texture.MULTI_LEVEL_LINEAR) {
1240: minificationFilter = Texture.BASE_LEVEL_LINEAR;
1241: } else if (minificationFilter == Texture.MULTI_LEVEL_POINT) {
1242: minificationFilter = Texture.BASE_LEVEL_POINT;
1243: }
1244: }
1245:
1246: // update texture filtering modes
1247: updateTextureFilterModes(cv.ctx, minificationFilter,
1248: magnificationFilter);
1249:
1250: if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_ANISOTROPIC_FILTER) != 0) {
1251: if (anisotropicFilterMode == Texture.ANISOTROPIC_NONE) {
1252: updateTextureAnisotropicFilter(cv.ctx, 1.0f);
1253: } else {
1254: updateTextureAnisotropicFilter(cv.ctx,
1255: anisotropicFilterDegree);
1256: }
1257: }
1258:
1259: // update texture boundary modes, boundary color
1260:
1261: updateTextureBoundary(cv);
1262:
1263: }
1264:
1265: // Wrapper around the native call for 2D textures; overridden for
1266: // TextureCureMap
1267: void updateTextureImage(Canvas3D cv, int face, int numLevels,
1268: int level, int textureFormat, int imageFormat, int width,
1269: int height, int boundaryWidth, int imageDataType,
1270: Object data) {
1271:
1272: Pipeline.getPipeline().updateTexture2DImage(cv.ctx, numLevels,
1273: level, textureFormat, imageFormat, width, height,
1274: boundaryWidth, imageDataType, data,
1275: useAutoMipMapGeneration(cv));
1276: }
1277:
1278: // Wrapper around the native call for 2D textures; overridden for
1279: // TextureCureMap
1280: void updateTextureSubImage(Canvas3D cv, int face, int level,
1281: int xoffset, int yoffset, int textureFormat,
1282: int imageFormat, int imgXOffset, int imgYOffset, int tilew,
1283: int width, int height, int imageDataType, Object data) {
1284:
1285: Pipeline.getPipeline().updateTexture2DSubImage(cv.ctx, level,
1286: xoffset, yoffset, textureFormat, imageFormat,
1287: imgXOffset, imgYOffset, tilew, width, height,
1288: imageDataType, data, useAutoMipMapGeneration(cv));
1289: }
1290:
1291: /**
1292: * reloadTextureImage is used to load a particular level of image
1293: * This method needs to take care of RenderedImage as well as
1294: * BufferedImage
1295: */
1296: void reloadTextureImage(Canvas3D cv, int face, int level,
1297: ImageComponentRetained image, int numLevels) {
1298:
1299: boolean useAsRaster = isUseAsRaster();
1300: ImageComponentRetained.ImageData imageData = image
1301: .getImageData(useAsRaster);
1302:
1303: assert imageData != null;
1304:
1305: updateTextureImage(cv, face, numLevels, level, format, image
1306: .getImageFormatTypeIntValue(useAsRaster), imageData
1307: .getWidth(), imageData.getHeight(), boundaryWidth,
1308: image.getImageDataTypeIntValue(), imageData.get());
1309:
1310: // TODO : Dead code - need to clean up for 1.6
1311: // Now take care of the RenderedImage (byRef and yUp) case. Note, if image
1312: // is a RenderedImage ( byRef and yUp), then imageData will be null
1313:
1314: if (imageData == null) {
1315: // System.err.println("==========. subImage");
1316: // Download all the tiles for this texture
1317: int xoffset = 0, yoffset = 0;
1318: int tmpw = image.width;
1319: int tmph = image.height;
1320: int endXTile = image.tilew;
1321: int endYTile = image.tileh;
1322: int curw = endXTile;
1323: int curh = endYTile;
1324:
1325: if (tmpw < curw) {
1326: curw = tmpw;
1327: }
1328:
1329: if (tmph < curh) {
1330: curh = tmph;
1331: }
1332:
1333: int startw = curw;
1334: int imageXOffset = image.tilew - curw;
1335: int imageYOffset = image.tileh - curh;
1336: for (int m = 0; m < image.numYTiles; m++) {
1337: xoffset = 0;
1338: tmpw = width;
1339: curw = startw;
1340: imageXOffset = image.tilew - curw;
1341: for (int n = 0; n < image.numXTiles; n++) {
1342: java.awt.image.Raster ras;
1343: ras = ((RenderedImage) image.getRefImage(0))
1344: .getTile(n, m);
1345: byte[] data = ((DataBufferByte) ras.getDataBuffer())
1346: .getData();
1347: updateTextureSubImage(
1348: cv,
1349: face,
1350: level,
1351: xoffset,
1352: yoffset,
1353: format,
1354: image.getImageFormatTypeIntValue(false),
1355: imageXOffset,
1356: imageYOffset,
1357: image.tilew,
1358: curw,
1359: curh,
1360: ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY,
1361: (Object) data);
1362: xoffset += curw;
1363: imageXOffset = 0;
1364: tmpw -= curw;
1365: if (tmpw < image.tilew)
1366: curw = tmpw;
1367: else
1368: curw = image.tilew;
1369: }
1370: yoffset += curh;
1371: imageYOffset = 0;
1372: tmph -= curh;
1373: if (tmph < image.tileh)
1374: curh = tmph;
1375: else
1376: curh = image.tileh;
1377: }
1378: }
1379: }
1380:
1381: /**
1382: * update a subregion of the texture image
1383: * This method needs to take care of RenderedImage as well as
1384: * BufferedImage
1385: */
1386: void reloadTextureSubImage(Canvas3D cv, int face, int level,
1387: ImageComponentUpdateInfo info, ImageComponentRetained image) {
1388:
1389: int x = info.x, y = info.y, width = info.width, height = info.height;
1390:
1391: //The x and y here specifies the subregion of the imageData of
1392: //the associated RenderedImage.
1393:
1394: //System.err.println("\nupdateTextureSubImage: x= " + x + " y= " + y +
1395: // " width= " + width + " height= " + height +
1396: // " format= " + format);
1397:
1398: ImageComponentRetained.ImageData imageData = image
1399: .getImageData(isUseAsRaster());
1400: if (imageData != null) {
1401: int xoffset = x;
1402: int yoffset = y;
1403:
1404: // TODO Check this logic : If !yUp adjust yoffset
1405: if (!image.yUp) {
1406: yoffset = image.height - yoffset - height;
1407: }
1408:
1409: updateTextureSubImage(cv, face, level, xoffset, yoffset,
1410: format, image.getImageFormatTypeIntValue(false),
1411: xoffset, yoffset, image.width, width, height, image
1412: .getImageDataTypeIntValue(), imageData
1413: .get());
1414:
1415: } else {
1416:
1417: assert false;
1418:
1419: // TODO : Dead code - need to clean up for 1.6
1420: // System.err.println("RenderedImage subImage update");
1421: // determine the first tile of the image
1422:
1423: float mt;
1424: int minTileX, minTileY;
1425:
1426: int rx = x;
1427: int ry = y;
1428:
1429: mt = (float) (rx) / (float) image.tilew;
1430: if (mt < 0) {
1431: minTileX = (int) (mt - 1);
1432: } else {
1433: minTileX = (int) mt;
1434: }
1435:
1436: mt = (float) (ry) / (float) image.tileh;
1437: if (mt < 0) {
1438: minTileY = (int) (mt - 1);
1439: } else {
1440: minTileY = (int) mt;
1441: }
1442:
1443: // determine the pixel offset of the upper-left corner of the
1444: // first tile
1445: int startXTile = minTileX * image.tilew;
1446: int startYTile = minTileY * image.tilew;
1447:
1448: // image dimension in the first tile
1449:
1450: int curw = (startXTile + image.tilew - rx);
1451: int curh = (startYTile + image.tileh - ry);
1452:
1453: // check if the to-be-copied region is less than the tile image
1454: // if so, update the to-be-copied dimension of this tile
1455:
1456: if (curw > width) {
1457: curw = width;
1458: }
1459:
1460: if (curh > height) {
1461: curh = height;
1462: }
1463:
1464: // save the to-be-copied width of the left most tile
1465:
1466: int startw = curw;
1467:
1468: // temporary variable for dimension of the to-be-copied region
1469:
1470: int tmpw = width;
1471: int tmph = height;
1472:
1473: // offset of the first pixel of the tile to be copied; offset is
1474: // relative to the upper left corner of the title
1475:
1476: int imgX = rx - startXTile;
1477: int imgY = ry - startYTile;
1478:
1479: // determine the number of tiles in each direction that the
1480: // image spans
1481:
1482: int numXTiles = (width + imgX) / image.tilew;
1483: int numYTiles = (height + imgY) / image.tileh;
1484:
1485: if (((float) (width + imgX) % (float) image.tilew) > 0) {
1486: numXTiles += 1;
1487: }
1488:
1489: if (((float) (height + imgY) % (float) image.tileh) > 0) {
1490: numYTiles += 1;
1491: }
1492:
1493: java.awt.image.Raster ras;
1494:
1495: int textureX = x; // x offset in the texture
1496: int textureY = y; // y offset in the texture
1497:
1498: for (int yTile = minTileY; yTile < minTileY + numYTiles; yTile++) {
1499:
1500: tmpw = width;
1501: curw = startw;
1502: imgX = rx - startXTile;
1503:
1504: for (int xTile = minTileX; xTile < minTileX + numXTiles; xTile++) {
1505: ras = ((RenderedImage) image.getRefImage(0))
1506: .getTile(xTile, yTile);
1507: byte[] data = ((DataBufferByte) ras.getDataBuffer())
1508: .getData();
1509:
1510: updateTextureSubImage(
1511: cv,
1512: face,
1513: level,
1514: textureX,
1515: textureY,
1516: format,
1517: image.getImageFormatTypeIntValue(false),
1518: imgX,
1519: imgY,
1520: image.tilew,
1521: curw,
1522: curh,
1523: ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY,
1524: (Object) data);
1525:
1526: // move to the next tile in x direction
1527:
1528: textureX += curw;
1529: imgX = 0;
1530:
1531: // determine the width of copy region of the next tile
1532:
1533: tmpw -= curw;
1534: if (tmpw < image.tilew) {
1535: curw = tmpw;
1536: } else {
1537: curw = image.tilew;
1538: }
1539: }
1540:
1541: // move to the next set of tiles in y direction
1542: textureY += curh;
1543: imgY = 0;
1544:
1545: // determine the height of copy region for the next set
1546: // of tiles
1547: tmph -= curh;
1548: if (tmph < image.tileh) {
1549: curh = tmph;
1550: } else {
1551: curh = image.tileh;
1552: }
1553: }
1554: }
1555: }
1556:
1557: // reload texture mipmap
1558:
1559: void reloadTexture(Canvas3D cv) {
1560:
1561: int blevel, mlevel;
1562:
1563: //System.err.println("reloadTexture: baseLevel= " + baseLevel +
1564: // " maximumLevel= " + maximumLevel);
1565:
1566: if ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_LOD_RANGE) == 0) {
1567: blevel = 0;
1568: mlevel = maxLevels - 1;
1569: } else {
1570: blevel = baseLevel;
1571: mlevel = maximumLevel;
1572: }
1573:
1574: if (blevel != 0) {
1575: // level 0 is not the base level, hence, need
1576: // to load level 0 explicitly with a null pointer in order
1577: // for mipmapping to be active.
1578:
1579: updateTextureDimensions(cv);
1580: }
1581:
1582: for (int j = 0; j < numFaces; j++) {
1583: for (int i = blevel; i <= mlevel; i++) {
1584:
1585: // it is possible to have null pointer if only a subset
1586: // of mipmap levels is defined but the canvas does not
1587: // support lod_range extension
1588:
1589: ImageComponentRetained image = images[j][i];
1590: if (image != null) {
1591: // Issue 366: call evaluateExtensions, since it may not
1592: // have been called yet in all cases
1593: image.evaluateExtensions(cv);
1594: reloadTextureImage(cv, j, i, image, maxLevels);
1595: }
1596: }
1597: }
1598: }
1599:
1600: // update texture mipmap based on the imageUpdateInfo
1601:
1602: void updateTexture(Canvas3D cv, int resourceBit) {
1603:
1604: //System.err.println("updateTexture\n");
1605:
1606: ImageComponentUpdateInfo info;
1607:
1608: for (int k = 0; k < numFaces; k++) {
1609: for (int i = baseLevel; i <= maximumLevel; i++) {
1610: if (imageUpdateInfo[k][i] != null) {
1611: for (int j = 0; j < imageUpdateInfo[k][i].size(); j++) {
1612:
1613: info = (ImageComponentUpdateInfo) imageUpdateInfo[k][i]
1614: .get(j);
1615:
1616: synchronized (resourceLock) {
1617:
1618: // if this info is updated, move on to the next one
1619:
1620: if ((info.updateMask & resourceBit) == 0)
1621: continue;
1622:
1623: // check if all canvases have processed this update
1624: info.updateMask &= ~resourceBit;
1625:
1626: // all the current resources have updated this
1627: // info, so this info can be removed from the
1628: // update list
1629: if ((info.updateMask & resourceCreationMask) == 0) {
1630: info.updateMask = 0; // mark this update as
1631: // done
1632:
1633: // mark the prune flag so as to prune the
1634: // update list next time when the update
1635: // list is to be modified.
1636: // Don't want to clean up the list at
1637: // rendering time because (1) MT issue,
1638: // other renderer could be processing
1639: // the update list now;
1640: // (2) takes up rendering time.
1641: if (imageUpdatePruneMask == null) {
1642: imageUpdatePruneMask = new int[numFaces];
1643: }
1644: imageUpdatePruneMask[k] = 1 << i;
1645: }
1646: }
1647:
1648: if (info.entireImage == true) {
1649: reloadTextureImage(cv, k, i, images[k][i],
1650: maxLevels);
1651: } else {
1652: reloadTextureSubImage(cv, k, i, info,
1653: images[k][i]);
1654: }
1655:
1656: }
1657: }
1658: }
1659: }
1660: }
1661:
1662: /**
1663: * reloadTextureSharedContext is called to reload texture
1664: * on a shared context. It is invoked from the Renderer
1665: * before traversing the RenderBin. The idea is to reload
1666: * all necessary textures up front for all shared contexts
1667: * in order to minimize the context switching overhead.
1668: */
1669: void reloadTextureSharedContext(Canvas3D cv) {
1670:
1671: // if texture is not enabled, don't bother downloading the
1672: // the texture state
1673:
1674: if (!isEnabled(cv)) {
1675: return;
1676: }
1677:
1678: bindTexture(cv);
1679:
1680: // reload all levels of texture image
1681:
1682: // update texture parameters such as boundary modes, filtering
1683:
1684: updateTextureFields(cv);
1685:
1686: // update texture Lod parameters
1687:
1688: updateTextureLOD(cv);
1689:
1690: // update all texture images
1691:
1692: reloadTexture(cv);
1693:
1694: synchronized (resourceLock) {
1695: resourceCreationMask |= cv.screen.renderer.rendererBit;
1696: resourceUpdatedMask |= cv.screen.renderer.rendererBit;
1697: resourceLodUpdatedMask |= cv.screen.renderer.rendererBit;
1698: resourceInReloadList &= ~cv.screen.renderer.rendererBit;
1699: }
1700: }
1701:
1702: /**
1703: * updateNative is called while traversing the RenderBin to
1704: * update the texture state
1705: */
1706: void updateNative(Canvas3D cv) {
1707: boolean reloadTexture = false; // true - reload all levels of texture
1708: boolean updateTexture = false; // true - update a portion of texture
1709: boolean updateTextureLod = false; // true - update texture Lod info
1710:
1711: //System.err.println("Texture/updateNative: " + this + "object= " + objectId + " enable= " + enable);
1712:
1713: bindTexture(cv);
1714:
1715: // if texture is not enabled, don't bother downloading the
1716: // the texture state
1717:
1718: if (!isEnabled(cv)) {
1719: return;
1720: }
1721:
1722: if (cv.useSharedCtx && cv.screen.renderer.sharedCtx != null) {
1723:
1724: if ((resourceCreationMask & cv.screen.renderer.rendererBit) == 0) {
1725: reloadTexture = true;
1726: } else {
1727: if (((resourceUpdatedMask & cv.screen.renderer.rendererBit) == 0)
1728: && (imageUpdateInfo != null)) {
1729: updateTexture = true;
1730: }
1731:
1732: if ((resourceLodUpdatedMask & cv.screen.renderer.rendererBit) == 0) {
1733: updateTextureLod = true;
1734: }
1735: }
1736: if (reloadTexture || updateTexture || updateTextureLod) {
1737: cv.makeCtxCurrent(cv.screen.renderer.sharedCtx);
1738: bindTexture(cv);
1739: }
1740: } else {
1741: if ((resourceCreationMask & cv.canvasBit) == 0) {
1742: reloadTexture = true;
1743: } else {
1744: if (((resourceUpdatedMask & cv.canvasBit) == 0)
1745: && (imageUpdateInfo != null)) {
1746: updateTexture = true;
1747: }
1748:
1749: if ((resourceLodUpdatedMask & cv.canvasBit) == 0) {
1750: updateTextureLod = true;
1751: }
1752: }
1753: }
1754:
1755: if (VirtualUniverse.mc.isD3D()) {
1756: if (texTimestamp != VirtualUniverse.mc.resendTexTimestamp) {
1757: texTimestamp = VirtualUniverse.mc.resendTexTimestamp;
1758: reloadTexture = true;
1759: }
1760:
1761: if (!reloadTexture) {
1762: // D3D didn't store texture properties during Texture binding
1763: updateTextureFields(cv);
1764: }
1765: }
1766:
1767: //System.err.println("......... reloadTexture= " + reloadTexture +
1768: // " updateTexture= " + updateTexture +
1769: // " updateTextureLod= " + updateTextureLod);
1770:
1771: //System.err.println("......... resourceCreationMask= " + resourceCreationMask +
1772: // " resourceUpdatedMask= " + resourceUpdatedMask);
1773:
1774: if (reloadTexture) {
1775:
1776: // reload all levels of texture image
1777:
1778: // update texture parameters such as boundary modes, filtering
1779:
1780: updateTextureFields(cv);
1781:
1782: // update texture Lod parameters
1783:
1784: updateTextureLOD(cv);
1785:
1786: // update all texture images
1787:
1788: reloadTexture(cv);
1789:
1790: if (cv.useSharedCtx) {
1791: cv.makeCtxCurrent(cv.ctx);
1792: synchronized (resourceLock) {
1793: resourceCreationMask |= cv.screen.renderer.rendererBit;
1794: resourceUpdatedMask |= cv.screen.renderer.rendererBit;
1795: resourceLodUpdatedMask |= cv.screen.renderer.rendererBit;
1796: }
1797: } else {
1798: synchronized (resourceLock) {
1799: resourceCreationMask |= cv.canvasBit;
1800: resourceUpdatedMask |= cv.canvasBit;
1801: resourceLodUpdatedMask |= cv.canvasBit;
1802: }
1803: }
1804: } else if (updateTextureLod || updateTexture) {
1805:
1806: if (updateTextureLod) {
1807: updateTextureLOD(cv);
1808: }
1809:
1810: if (updateTexture) {
1811:
1812: // update texture image
1813:
1814: int resourceBit = 0;
1815:
1816: if (cv.useSharedCtx) {
1817: resourceBit = cv.screen.renderer.rendererBit;
1818: } else {
1819: resourceBit = cv.canvasBit;
1820: }
1821:
1822: // update texture based on the imageComponent update info
1823:
1824: updateTexture(cv, resourceBit);
1825: }
1826:
1827: // set the appropriate bit in the resource update masks showing
1828: // that the resource is up-to-date
1829:
1830: if (cv.useSharedCtx) {
1831: cv.makeCtxCurrent(cv.ctx);
1832: synchronized (resourceLock) {
1833: resourceUpdatedMask |= cv.screen.renderer.rendererBit;
1834: resourceLodUpdatedMask |= cv.screen.renderer.rendererBit;
1835: }
1836: } else {
1837: synchronized (resourceLock) {
1838: resourceUpdatedMask |= cv.canvasBit;
1839: resourceLodUpdatedMask |= cv.canvasBit;
1840: }
1841: }
1842: }
1843: }
1844:
1845: synchronized void createMirrorObject() {
1846: if (mirror == null) {
1847: if (this instanceof Texture3DRetained) {
1848: Texture3DRetained t3d = (Texture3DRetained) this ;
1849: Texture3D tex = new Texture3D(t3d.mipmapMode,
1850: t3d.format, t3d.width, t3d.height, t3d.depth,
1851: t3d.boundaryWidth);
1852: mirror = (Texture3DRetained) tex.retained;
1853: ;
1854:
1855: } else if (this instanceof TextureCubeMapRetained) {
1856: TextureCubeMap tex = new TextureCubeMap(mipmapMode,
1857: format, width, boundaryWidth);
1858: mirror = (TextureCubeMapRetained) tex.retained;
1859:
1860: } else {
1861: Texture2D tex = new Texture2D(mipmapMode, format,
1862: width, height, boundaryWidth);
1863: mirror = (Texture2DRetained) tex.retained;
1864: }
1865:
1866: ((TextureRetained) mirror).objectId = -1;
1867: }
1868: initMirrorObject();
1869: }
1870:
1871: /**
1872: * Initializes a mirror object, point the mirror object to the retained
1873: * object if the object is not editable
1874: */
1875: synchronized void initMirrorObject() {
1876: mirror.source = source;
1877: if (this instanceof Texture3DRetained) {
1878: Texture3DRetained t3d = (Texture3DRetained) this ;
1879:
1880: ((Texture3DRetained) mirror).boundaryModeR = t3d.boundaryModeR;
1881: ((Texture3DRetained) mirror).depth = t3d.depth;
1882: }
1883: TextureRetained mirrorTexture = (TextureRetained) mirror;
1884:
1885: mirrorTexture.boundaryModeS = boundaryModeS;
1886: mirrorTexture.boundaryModeT = boundaryModeT;
1887: mirrorTexture.minFilter = minFilter;
1888: mirrorTexture.magFilter = magFilter;
1889: mirrorTexture.boundaryColor.set(boundaryColor);
1890: mirrorTexture.enable = enable;
1891: mirrorTexture.userSpecifiedEnable = enable;
1892: mirrorTexture.enable = enable;
1893: mirrorTexture.numFaces = numFaces;
1894: mirrorTexture.resourceCreationMask = 0x0;
1895: mirrorTexture.resourceUpdatedMask = 0x0;
1896: mirrorTexture.resourceLodUpdatedMask = 0x0;
1897: mirrorTexture.resourceInReloadList = 0x0;
1898:
1899: // LOD information
1900: mirrorTexture.baseLevel = baseLevel;
1901: mirrorTexture.maximumLevel = maximumLevel;
1902: mirrorTexture.minimumLod = minimumLod;
1903: mirrorTexture.maximumLod = maximumLod;
1904: mirrorTexture.lodOffset = lodOffset;
1905:
1906: // sharpen texture LOD function
1907:
1908: mirrorTexture.numSharpenTextureFuncPts = numSharpenTextureFuncPts;
1909: if (sharpenTextureFuncPts == null) {
1910: mirrorTexture.sharpenTextureFuncPts = null;
1911: } else {
1912: if ((mirrorTexture.sharpenTextureFuncPts == null)
1913: || (mirrorTexture.sharpenTextureFuncPts.length != sharpenTextureFuncPts.length)) {
1914: mirrorTexture.sharpenTextureFuncPts = new float[sharpenTextureFuncPts.length];
1915: }
1916: for (int i = 0; i < sharpenTextureFuncPts.length; i++) {
1917: mirrorTexture.sharpenTextureFuncPts[i] = sharpenTextureFuncPts[i];
1918: }
1919: }
1920:
1921: // filter4 function
1922: if (filter4FuncPts == null) {
1923: mirrorTexture.filter4FuncPts = null;
1924: } else {
1925: if ((mirrorTexture.filter4FuncPts == null)
1926: || (mirrorTexture.filter4FuncPts.length != filter4FuncPts.length)) {
1927: mirrorTexture.filter4FuncPts = new float[filter4FuncPts.length];
1928: }
1929: for (int i = 0; i < filter4FuncPts.length; i++) {
1930: mirrorTexture.filter4FuncPts[i] = filter4FuncPts[i];
1931: }
1932: }
1933:
1934: // Anisotropic Filter
1935: mirrorTexture.anisotropicFilterMode = anisotropicFilterMode;
1936: mirrorTexture.anisotropicFilterDegree = anisotropicFilterDegree;
1937:
1938: mirrorTexture.maxLevels = maxLevels;
1939: if (images != null) {
1940:
1941: for (int j = 0; j < numFaces; j++) {
1942: for (int i = 0; i < maxLevels; i++) {
1943: mirrorTexture.images[j][i] = images[j][i];
1944:
1945: // add texture to the userList of the images
1946: if (images[j][i] != null) {
1947: images[j][i].addUser(mirrorTexture);
1948: }
1949: }
1950: }
1951: }
1952: }
1953:
1954: boolean useAutoMipMapGeneration(Canvas3D cv) {
1955: if (mipmapMode == Texture.BASE_LEVEL
1956: && (minFilter == Texture.NICEST
1957: || minFilter == Texture.MULTI_LEVEL_POINT || minFilter == Texture.MULTI_LEVEL_LINEAR)
1958: && ((cv.textureExtendedFeatures & Canvas3D.TEXTURE_AUTO_MIPMAP_GENERATION) != 0)) {
1959: return true;
1960: }
1961:
1962: return false;
1963: }
1964:
1965: /**
1966: * Go through the image update info list
1967: * and remove those that are already done
1968: * by all the resources
1969: */
1970: void pruneImageUpdateInfo() {
1971: ImageComponentUpdateInfo info;
1972:
1973: //System.err.println("Texture.pruneImageUpdateInfo");
1974:
1975: for (int k = 0; k < numFaces; k++) {
1976: for (int i = baseLevel; i <= maximumLevel; i++) {
1977: if ((imageUpdatePruneMask[k] & (1 << i)) != 0) {
1978: if (imageUpdateInfo[k][i] != null) {
1979: for (int j = 0; j < imageUpdateInfo[k][i]
1980: .size(); j++) {
1981: info = (ImageComponentUpdateInfo) imageUpdateInfo[k][i]
1982: .get(j);
1983: if (info.updateMask == 0) {
1984: // this update info is done, remove it
1985: // from the update list
1986: imageUpdateInfo[k][i].remove(j);
1987: }
1988: }
1989: }
1990: imageUpdatePruneMask[k] &= ~(1 << i);
1991: }
1992: }
1993: }
1994: }
1995:
1996: /**
1997: * addImageUpdateInfo(int level) is to update a particular level.
1998: * In this case, it supercedes all the subImage update for this level,
1999: * and all those update info can be removed from the update list.
2000: *
2001: * Note: this method is called from mirror only
2002: */
2003: void addImageUpdateInfo(int level, int face,
2004: ImageComponentUpdateInfo arg) {
2005:
2006: ImageComponentUpdateInfo info;
2007:
2008: if (imageUpdateInfo == null) {
2009: imageUpdateInfo = new ArrayList[numFaces][maxLevels];
2010: }
2011:
2012: if (imageUpdateInfo[face][level] == null) {
2013: imageUpdateInfo[face][level] = new ArrayList();
2014: }
2015:
2016: info = new ImageComponentUpdateInfo();
2017:
2018: if (arg == null) {
2019: // no subimage info, so the entire image is to be updated
2020: info.entireImage = true;
2021: // Fix issue 117 using ogl subimage always
2022: // } else if ((arg.width >= width/2) && (arg.height >= height/2)) {
2023: //
2024: // // if the subimage dimension is close to the complete dimension,
2025: // // use the full update (it's more efficient)
2026: // info.entireImage = true;
2027: } else {
2028: info.entireImage = false;
2029: }
2030:
2031: if (info.entireImage) {
2032: // the entire image update supercedes all the subimage update;
2033: // hence, remove all the existing updates from the list
2034: imageUpdateInfo[face][level].clear();
2035:
2036: // reset the update prune mask for this level
2037: if (imageUpdatePruneMask != null) {
2038: imageUpdatePruneMask[face] &= ~(1 << level);
2039: }
2040:
2041: } else {
2042: // subimage update, needs to save the subimage info
2043: info.x = arg.x;
2044: info.y = arg.y;
2045: info.z = arg.z;
2046: info.width = arg.width;
2047: info.height = arg.height;
2048: }
2049:
2050: // save the mask which shows the canvases that have created resources
2051: // for this image, aka, these are the resources that need to be
2052: // updated.
2053: info.updateMask = resourceCreationMask;
2054:
2055: // add the image update to the list
2056: imageUpdateInfo[face][level].add(info);
2057:
2058: // check if the update list stills need to be pruned
2059: if (imageUpdatePruneMask != null) {
2060: pruneImageUpdateInfo();
2061: }
2062: }
2063:
2064: void validate() {
2065: enable = true;
2066: for (int j = 0; j < numFaces && enable; j++) {
2067: for (int i = baseLevel; i <= maximumLevel && enable; i++) {
2068: if (images[j][i] == null) {
2069: enable = false;
2070: }
2071: }
2072: }
2073: }
2074:
2075: /**
2076: * Update the "component" field of the mirror object with the
2077: * given "value"
2078: */
2079: synchronized void updateMirrorObject(int component, Object value) {
2080:
2081: TextureRetained mirrorTexture = (TextureRetained) mirror;
2082:
2083: if ((component & ENABLE_CHANGED) != 0) {
2084: mirrorTexture.enable = ((Boolean) value).booleanValue();
2085:
2086: } else if ((component & IMAGE_CHANGED) != 0) {
2087:
2088: Object[] arg = (Object[]) value;
2089: int level = ((Integer) arg[0]).intValue();
2090: ImageComponent image = (ImageComponent) arg[1];
2091: int face = ((Integer) arg[2]).intValue();
2092:
2093: // first remove texture from the userList of the current
2094: // referencing image and
2095:
2096: if (mirrorTexture.images[face][level] != null) {
2097: mirrorTexture.images[face][level].removeUser(mirror);
2098: }
2099:
2100: // assign the new image and add texture to the userList
2101: if (image == null) {
2102: mirrorTexture.images[face][level] = null;
2103:
2104: } else {
2105: mirrorTexture.images[face][level] = (ImageComponentRetained) image.retained;
2106: mirrorTexture.images[face][level].addUser(mirror);
2107:
2108: }
2109:
2110: // NOTE: the old image has to be removed from the
2111: // renderBins' NodeComponentList and new image has to be
2112: // added to the lists. This will be taken care of
2113: // in the RenderBin itself in response to the
2114: // IMAGE_CHANGED message
2115:
2116: // mark that texture images need to be updated
2117: mirrorTexture.resourceUpdatedMask = 0;
2118:
2119: // add update info to the update list
2120: mirrorTexture.addImageUpdateInfo(level, face, null);
2121:
2122: } else if ((component & IMAGES_CHANGED) != 0) {
2123:
2124: Object[] arg = (Object[]) value;
2125: ImageComponent[] images = (ImageComponent[]) arg[0];
2126: int face = ((Integer) arg[1]).intValue();
2127:
2128: for (int i = 0; i < images.length; i++) {
2129:
2130: // first remove texture from the userList of the current
2131: // referencing image
2132: if (mirrorTexture.images[face][i] != null) {
2133: mirrorTexture.images[face][i].removeUser(mirror);
2134: }
2135:
2136: // assign the new image and add texture to the userList
2137: if (images[i] == null) {
2138: mirrorTexture.images[face][i] = null;
2139: } else {
2140: mirrorTexture.images[face][i] = (ImageComponentRetained) images[i].retained;
2141: mirrorTexture.images[face][i].addUser(mirror);
2142: }
2143: }
2144: mirrorTexture.updateResourceCreationMask();
2145:
2146: // NOTE: the old images have to be removed from the
2147: // renderBins' NodeComponentList and new image have to be
2148: // added to the lists. This will be taken care of
2149: // in the RenderBin itself in response to the
2150: // IMAGES_CHANGED message
2151:
2152: } else if ((component & BASE_LEVEL_CHANGED) != 0) {
2153: int level = ((Integer) value).intValue();
2154:
2155: if (level < mirrorTexture.baseLevel) {
2156:
2157: // add texture to the userList of those new levels of
2158: // enabling images
2159:
2160: for (int j = 0; j < numFaces; j++) {
2161: for (int i = level; i < mirrorTexture.baseLevel; i++) {
2162:
2163: if (mirrorTexture.images[j][i] == null) {
2164: mirrorTexture.enable = false;
2165: } else {
2166: mirrorTexture
2167: .addImageUpdateInfo(i, j, null);
2168: }
2169: }
2170: }
2171:
2172: mirrorTexture.baseLevel = level;
2173:
2174: // mark that texture images need to be updated
2175: mirrorTexture.resourceUpdatedMask = 0;
2176:
2177: } else {
2178:
2179: mirrorTexture.baseLevel = level;
2180:
2181: if (userSpecifiedEnable
2182: && (mirrorTexture.enable == false)) {
2183:
2184: // if texture is to be enabled but is currently
2185: // disabled, it's probably disabled because
2186: // some of the images are missing. Now that
2187: // the baseLevel is modified, validate the
2188: // texture images again
2189:
2190: mirrorTexture.validate();
2191: }
2192: }
2193:
2194: // mark that texture lod info needs to be updated
2195: mirrorTexture.resourceLodUpdatedMask = 0;
2196:
2197: } else if ((component & MAX_LEVEL_CHANGED) != 0) {
2198: int level = ((Integer) value).intValue();
2199:
2200: if (level > mirrorTexture.maximumLevel) {
2201:
2202: // add texture to the userList of those new levels of
2203: // enabling images
2204:
2205: for (int j = 0; j < numFaces; j++) {
2206: for (int i = mirrorTexture.maximumLevel; i < level; i++) {
2207:
2208: if (mirrorTexture.images[j][i] == null) {
2209: mirrorTexture.enable = false;
2210: } else {
2211: mirrorTexture
2212: .addImageUpdateInfo(i, j, null);
2213: }
2214: }
2215: }
2216:
2217: mirrorTexture.maximumLevel = level;
2218:
2219: // mark that texture images need to be updated
2220: mirrorTexture.resourceUpdatedMask = 0;
2221:
2222: } else {
2223:
2224: mirrorTexture.maximumLevel = level;
2225:
2226: if (userSpecifiedEnable
2227: && (mirrorTexture.enable == false)) {
2228:
2229: // if texture is to be enabled but is currently
2230: // disabled, it's probably disabled because
2231: // some of the images are missing. Now that
2232: // the baseLevel is modified, validate the
2233: // texture images again
2234:
2235: mirrorTexture.validate();
2236: }
2237: }
2238:
2239: // mark that texture lod info needs to be updated
2240: mirrorTexture.resourceLodUpdatedMask = 0;
2241:
2242: } else if ((component & MIN_LOD_CHANGED) != 0) {
2243: mirrorTexture.minimumLod = ((Float) value).floatValue();
2244:
2245: // mark that texture lod info needs to be updated
2246: mirrorTexture.resourceLodUpdatedMask = 0;
2247:
2248: } else if ((component & MAX_LOD_CHANGED) != 0) {
2249: mirrorTexture.maximumLod = ((Float) value).floatValue();
2250:
2251: // mark that texture lod info needs to be updated
2252: mirrorTexture.resourceLodUpdatedMask = 0;
2253:
2254: } else if ((component & LOD_OFFSET_CHANGED) != 0) {
2255: if ((mirrorTexture.lodOffset) == null) {
2256: mirrorTexture.lodOffset = new Point3f((Point3f) value);
2257: } else {
2258: mirrorTexture.lodOffset.set((Point3f) value);
2259: }
2260:
2261: // mark that texture lod info needs to be updated
2262: mirrorTexture.resourceLodUpdatedMask = 0;
2263:
2264: } else if ((component & UPDATE_IMAGE) != 0) {
2265: mirrorTexture.updateResourceCreationMask();
2266: }
2267:
2268: }
2269:
2270: // notifies the Texture mirror object that the image data in a referenced
2271: // ImageComponent object is changed. Need to update the texture image
2272: // accordingly.
2273: // Note: this is called from mirror object only
2274:
2275: void notifyImageComponentImageChanged(ImageComponentRetained image,
2276: ImageComponentUpdateInfo value) {
2277:
2278: //System.err.println("Texture.notifyImageComponentImageChanged");
2279:
2280: // if this texture is to be reloaded, don't bother to keep
2281: // the update info
2282:
2283: if (resourceCreationMask == 0) {
2284:
2285: if (imageUpdateInfo != null) {
2286:
2287: //remove all the existing updates from the list
2288:
2289: for (int face = 0; face < numFaces; face++) {
2290: for (int level = 0; level < maxLevels; level++) {
2291: if (imageUpdateInfo[face][level] != null) {
2292: imageUpdateInfo[face][level].clear();
2293: }
2294: }
2295:
2296: // reset the update prune mask for this level
2297: if (imageUpdatePruneMask != null) {
2298: imageUpdatePruneMask[face] = 0;
2299: }
2300: }
2301: }
2302:
2303: return;
2304: }
2305:
2306: // first find which texture image is being affected
2307:
2308: boolean done;
2309:
2310: for (int j = 0; j < numFaces; j++) {
2311:
2312: done = false;
2313: for (int i = baseLevel; i <= maximumLevel && !done; i++) {
2314: if (images[j][i] == image) {
2315:
2316: // reset the resourceUpdatedMask to tell the
2317: // rendering method to update the resource
2318: resourceUpdatedMask = 0;
2319:
2320: // add update info to the update list
2321: addImageUpdateInfo(i, j, value);
2322:
2323: // set done to true for this face because no two levels
2324: // can reference the same ImageComponent object
2325: done = true;
2326: }
2327: }
2328: }
2329: }
2330:
2331: // reset the resourceCreationMask
2332: // Note: called from the mirror object only
2333:
2334: void updateResourceCreationMask() {
2335: resourceCreationMask = 0x0;
2336: }
2337:
2338: void incTextureBinRefCount(TextureBin tb) {
2339:
2340: ImageComponentRetained image;
2341:
2342: setTextureBinRefCount(tb, getTextureBinRefCount(tb) + 1);
2343:
2344: // check to see if there is any modifiable images,
2345: // if yes, add those images to nodeComponentList in RenderBin
2346: // so that RenderBin can acquire a lock before rendering
2347: // to prevent updating of image data while rendering
2348:
2349: for (int j = 0; j < numFaces; j++) {
2350: for (int i = 0; i < maxLevels; i++) {
2351: image = images[j][i];
2352:
2353: // it is possible that image.source == null because
2354: // the mipmap could have been created by the library, and
2355: // hence don't have source and therefore they are
2356: // guaranteed not modifiable
2357:
2358: if (image != null
2359: && (image.isByReference() || (image.source != null && image.source
2360: .getCapability(ImageComponent.ALLOW_IMAGE_WRITE)))) {
2361: tb.renderBin.addNodeComponent(image);
2362: }
2363: }
2364: }
2365: }
2366:
2367: void decTextureBinRefCount(TextureBin tb) {
2368:
2369: ImageComponentRetained image;
2370:
2371: setTextureBinRefCount(tb, getTextureBinRefCount(tb) - 1);
2372:
2373: // remove any modifiable images from RenderBin nodeComponentList
2374:
2375: for (int j = 0; j < numFaces; j++) {
2376: for (int i = 0; i < maxLevels; i++) {
2377: image = images[j][i];
2378: if (image != null
2379: && (image.isByReference() || (image.source != null && image.source
2380: .getCapability(ImageComponent.ALLOW_IMAGE_WRITE)))) {
2381: tb.renderBin.removeNodeComponent(image);
2382: }
2383: }
2384: }
2385: }
2386:
2387: final void sendMessage(int attrMask, Object attr) {
2388:
2389: ArrayList univList = new ArrayList();
2390: ArrayList gaList = Shape3DRetained.getGeomAtomsList(
2391: mirror.users, univList);
2392:
2393: // Send to rendering attribute structure, regardless of
2394: // whether there are users or not (alternate appearance case ..)
2395: J3dMessage createMessage = new J3dMessage();
2396: createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES;
2397: createMessage.type = J3dMessage.TEXTURE_CHANGED;
2398: createMessage.universe = null;
2399: createMessage.args[0] = this ;
2400: createMessage.args[1] = new Integer(attrMask);
2401: createMessage.args[2] = attr;
2402: createMessage.args[3] = new Integer(changedFrequent);
2403: VirtualUniverse.mc.processMessage(createMessage);
2404:
2405: // System.err.println("univList.size is " + univList.size());
2406: for (int i = 0; i < univList.size(); i++) {
2407: createMessage = new J3dMessage();
2408: createMessage.threads = J3dThread.UPDATE_RENDER;
2409: createMessage.type = J3dMessage.TEXTURE_CHANGED;
2410:
2411: createMessage.universe = (VirtualUniverse) univList.get(i);
2412: createMessage.args[0] = this ;
2413: createMessage.args[1] = new Integer(attrMask);
2414: createMessage.args[2] = attr;
2415:
2416: ArrayList gL = (ArrayList) gaList.get(i);
2417: GeometryAtom[] gaArr = new GeometryAtom[gL.size()];
2418: gL.toArray(gaArr);
2419: createMessage.args[3] = gaArr;
2420:
2421: VirtualUniverse.mc.processMessage(createMessage);
2422: }
2423:
2424: }
2425:
2426: void handleFrequencyChange(int bit) {
2427: switch (bit) {
2428: case Texture.ALLOW_ENABLE_WRITE:
2429: case Texture.ALLOW_IMAGE_WRITE:
2430: case Texture.ALLOW_LOD_RANGE_WRITE: {
2431: setFrequencyChangeMask(bit, bit);
2432: }
2433: default:
2434: break;
2435: }
2436: }
2437:
2438: void setUseAsRaster(boolean useAsRaster) {
2439: this .useAsRaster = useAsRaster;
2440: }
2441:
2442: boolean isUseAsRaster() {
2443: return this .useAsRaster;
2444: }
2445:
2446: // Issue 357 - {get/set}TextureBinRefCount now uses a separate reference
2447: // counter per RenderBin. The absence of the RenderBin key in the hash map
2448: // is used to indicate a value of 0. This makes initialization easier, and
2449: // prevents a small amount of garbage accumulating for inactive RenderBins.
2450:
2451: int getTextureBinRefCount(TextureBin tb) {
2452: Integer i = textureBinRefCount.get(tb.renderBin);
2453: return i == null ? 0 : i.intValue();
2454: }
2455:
2456: private void setTextureBinRefCount(TextureBin tb, int refCount) {
2457: if (refCount == 0) {
2458: textureBinRefCount.remove(tb.renderBin);
2459: } else {
2460: textureBinRefCount.put(tb.renderBin, new Integer(refCount));
2461: }
2462: }
2463:
2464: }
|