0001: /*
0002: * $RCSfile: ImageComponentRetained.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.19 $
0028: * $Date: 2008/02/28 20:17:23 $
0029: * $State: Exp $
0030: */
0031:
0032: package javax.media.j3d;
0033:
0034: import java.nio.Buffer;
0035: import java.util.*;
0036: import java.awt.image.*;
0037: import java.awt.color.ColorSpace;
0038: import java.awt.geom.AffineTransform;
0039: import java.awt.image.AffineTransformOp;
0040: import java.awt.image.RenderedImage;
0041: import java.nio.ByteBuffer;
0042: import java.nio.ByteOrder;
0043: import java.nio.IntBuffer;
0044: import java.util.logging.Level;
0045:
0046: /**
0047: * Abstract class that is used to define 2D or 3D ImageComponent classes
0048: * used in a Java 3D scene graph.
0049: * This is used for texture images, background images and raster components
0050: * of Shape3D nodes.
0051: */
0052:
0053: abstract class ImageComponentRetained extends NodeComponentRetained {
0054:
0055: // change flag
0056: static final int IMAGE_CHANGED = 0x01;
0057: static final int SUBIMAGE_CHANGED = 0x02;
0058:
0059: static final int TYPE_BYTE_BGR = 0x1;
0060: static final int TYPE_BYTE_RGB = 0x2;
0061: static final int TYPE_BYTE_ABGR = 0x4;
0062: static final int TYPE_BYTE_RGBA = 0x8;
0063: static final int TYPE_BYTE_LA = 0x10;
0064: static final int TYPE_BYTE_GRAY = 0x20;
0065: static final int TYPE_USHORT_GRAY = 0x40;
0066: static final int TYPE_INT_BGR = 0x80;
0067: static final int TYPE_INT_RGB = 0x100;
0068: static final int TYPE_INT_ARGB = 0x200;
0069:
0070: static final int IMAGE_SIZE_512X512 = 262144;
0071:
0072: enum ImageFormatType {
0073: TYPE_UNKNOWN, TYPE_BYTE_BGR, TYPE_BYTE_RGB, TYPE_BYTE_ABGR, TYPE_BYTE_RGBA, TYPE_BYTE_LA, TYPE_BYTE_GRAY, TYPE_USHORT_GRAY, TYPE_INT_BGR, TYPE_INT_RGB, TYPE_INT_ARGB
0074: }
0075:
0076: static final int IMAGE_DATA_TYPE_BYTE_ARRAY = 0x1000;
0077: static final int IMAGE_DATA_TYPE_INT_ARRAY = 0x2000;
0078: static final int IMAGE_DATA_TYPE_BYTE_BUFFER = 0x4000;
0079: static final int IMAGE_DATA_TYPE_INT_BUFFER = 0x8000;
0080:
0081: enum ImageDataType {
0082: TYPE_NULL, TYPE_BYTE_ARRAY, TYPE_INT_ARRAY, TYPE_BYTE_BUFFER, TYPE_INT_BUFFER
0083: }
0084:
0085: private int apiFormat; // The format set by user.
0086: int width; // Width of PixelArray
0087: int height; // Height of PixelArray
0088: int depth; // Depth of PixelArray
0089: boolean byReference = false; // Is the imageComponent by reference
0090: boolean yUp = false;
0091: boolean imageTypeIsSupported;
0092: boolean abgrSupported = true;
0093: boolean npotSupported = true;
0094: private int unitsPerPixel;
0095: private int numberOfComponents;
0096:
0097: // Note : This is unuse for NioImageBuffer.
0098: // The image type of the input image. Using the constant in BufferedImage
0099: private int imageType;
0100:
0101: private ImageFormatType imageFormatType = ImageFormatType.TYPE_UNKNOWN;
0102: ImageData imageData;
0103: private ImageComponent.ImageClass imageClass = ImageComponent.ImageClass.BUFFERED_IMAGE;
0104:
0105: // To support Non power of 2 (NPOT) image
0106: // if enforceNonPowerOfTwoSupport is true (for examples Raster and Background)
0107: // and imageData is a non power of 2 image
0108: // and graphics driver doesn't support NPOT extension.
0109: private ImageData imageDataPowerOfTwo;
0110: private AffineTransformOp powerOfTwoATOp;
0111: // The following flag means that if the image is non-power-of-two and the
0112: // card doesn't support NPOT texture, we will scale the image to a power
0113: // of two.
0114: private boolean enforceNonPowerOfTwoSupport = false;
0115: private boolean usedByOffScreenCanvas = false;
0116:
0117: // This will store the referenced Images for reference case.
0118: // private RenderedImage refImage[] = null;
0119: private Object refImage[] = null;
0120:
0121: // Issue 366: Lock for evaluateExtensions
0122: Object evaluateExtLock = new Object();
0123:
0124: // Lock used in the "by ref case"
0125: GeometryLock geomLock = new GeometryLock();
0126:
0127: int tilew = 0;
0128: int tileh = 0;
0129: int numXTiles = 0;
0130: int numYTiles = 0;
0131:
0132: // lists of Node Components that are referencing this ImageComponent
0133: // object. This list is used to notify the referencing node components
0134: // of any changes of this ImageComponent.
0135: ArrayList userList = new ArrayList();
0136:
0137: /**
0138: * Retrieves the width of this image component object.
0139: * @return the width of this image component object
0140: */
0141: int getWidth() {
0142: return width;
0143: }
0144:
0145: /**
0146: * Retrieves the height of this image component object.
0147: * @return the height of this image component object
0148: */
0149: int getHeight() {
0150: return height;
0151: }
0152:
0153: /**
0154: * Retrieves the apiFormat of this image component object.
0155: *
0156: * @return the apiFormat of this image component object
0157: */
0158: int getFormat() {
0159: return apiFormat;
0160: }
0161:
0162: void setFormat(int format) {
0163: this .apiFormat = format;
0164: }
0165:
0166: void setByReference(boolean byReference) {
0167: this .byReference = byReference;
0168: }
0169:
0170: boolean isByReference() {
0171: return byReference;
0172: }
0173:
0174: void setYUp(boolean yUp) {
0175: this .yUp = yUp;
0176: }
0177:
0178: boolean isYUp() {
0179: return yUp;
0180: }
0181:
0182: int getUnitsPerPixel() {
0183: return unitsPerPixel;
0184: }
0185:
0186: void setUnitsPerPixel(int ipp) {
0187: unitsPerPixel = ipp;
0188: }
0189:
0190: ImageComponent.ImageClass getImageClass() {
0191: return imageClass;
0192: }
0193:
0194: void setImageClass(RenderedImage image) {
0195: if (image instanceof BufferedImage) {
0196: imageClass = ImageComponent.ImageClass.BUFFERED_IMAGE;
0197: } else {
0198: imageClass = ImageComponent.ImageClass.RENDERED_IMAGE;
0199: }
0200: }
0201:
0202: void setImageClass(NioImageBuffer image) {
0203: imageClass = ImageComponent.ImageClass.NIO_IMAGE_BUFFER;
0204: }
0205:
0206: void setEnforceNonPowerOfTwoSupport(boolean npot) {
0207: this .enforceNonPowerOfTwoSupport = npot;
0208: }
0209:
0210: void setUsedByOffScreen(boolean used) {
0211: usedByOffScreenCanvas = used;
0212: }
0213:
0214: boolean getUsedByOffScreen() {
0215: return usedByOffScreenCanvas;
0216: }
0217:
0218: int getNumberOfComponents() {
0219: return numberOfComponents;
0220: }
0221:
0222: void setNumberOfComponents(int numberOfComponents) {
0223: this .numberOfComponents = numberOfComponents;
0224: }
0225:
0226: int getImageDataTypeIntValue() {
0227: int idtValue = -1;
0228: switch (imageData.imageDataType) {
0229: case TYPE_BYTE_ARRAY:
0230: idtValue = IMAGE_DATA_TYPE_BYTE_ARRAY;
0231: break;
0232: case TYPE_INT_ARRAY:
0233: idtValue = IMAGE_DATA_TYPE_INT_ARRAY;
0234: break;
0235: case TYPE_BYTE_BUFFER:
0236: idtValue = IMAGE_DATA_TYPE_BYTE_BUFFER;
0237: break;
0238: case TYPE_INT_BUFFER:
0239: idtValue = IMAGE_DATA_TYPE_INT_BUFFER;
0240: break;
0241: default:
0242: assert false;
0243: }
0244: return idtValue;
0245:
0246: }
0247:
0248: int getImageFormatTypeIntValue(boolean powerOfTwoData) {
0249: int iftValue = -1;
0250: switch (imageFormatType) {
0251: case TYPE_BYTE_BGR:
0252: iftValue = TYPE_BYTE_BGR;
0253: break;
0254: case TYPE_BYTE_RGB:
0255: iftValue = TYPE_BYTE_RGB;
0256: break;
0257: case TYPE_BYTE_ABGR:
0258: iftValue = TYPE_BYTE_ABGR;
0259: break;
0260: case TYPE_BYTE_RGBA:
0261: if ((imageDataPowerOfTwo != null) && (powerOfTwoData)) {
0262: iftValue = TYPE_BYTE_ABGR;
0263: } else {
0264: iftValue = TYPE_BYTE_RGBA;
0265: }
0266: break;
0267: case TYPE_BYTE_LA:
0268: iftValue = TYPE_BYTE_LA;
0269: break;
0270: case TYPE_BYTE_GRAY:
0271: iftValue = TYPE_BYTE_GRAY;
0272: break;
0273: case TYPE_USHORT_GRAY:
0274: iftValue = TYPE_USHORT_GRAY;
0275: break;
0276: case TYPE_INT_BGR:
0277: iftValue = TYPE_INT_BGR;
0278: break;
0279: case TYPE_INT_RGB:
0280: iftValue = TYPE_INT_RGB;
0281: break;
0282: case TYPE_INT_ARGB:
0283: iftValue = TYPE_INT_ARGB;
0284: break;
0285: default:
0286: throw new AssertionError();
0287: }
0288: return iftValue;
0289: }
0290:
0291: // Note: This method for RenderedImage, can't be used by NioImageBuffer.
0292: int getImageType() {
0293: return imageType;
0294: }
0295:
0296: void setImageFormatType(ImageFormatType ift) {
0297: this .imageFormatType = ift;
0298: }
0299:
0300: ImageFormatType getImageFormatType() {
0301: return this .imageFormatType;
0302: }
0303:
0304: void setRefImage(Object image, int index) {
0305: this .refImage[index] = image;
0306: }
0307:
0308: Object getRefImage(int index) {
0309: return this .refImage[index];
0310: }
0311:
0312: ImageData getImageData(boolean npotSupportNeeded) {
0313: if (npotSupportNeeded) {
0314: assert enforceNonPowerOfTwoSupport;
0315: if (imageDataPowerOfTwo != null) {
0316: return imageDataPowerOfTwo;
0317: }
0318: }
0319: return imageData;
0320: }
0321:
0322: boolean useBilinearFilter() {
0323: if (imageDataPowerOfTwo != null) {
0324: return true;
0325: }
0326:
0327: return false;
0328: }
0329:
0330: boolean isImageTypeSupported() {
0331: return imageTypeIsSupported;
0332: }
0333:
0334: /**
0335: * Check if ImageComponent parameters have valid values.
0336: */
0337: void processParams(int format, int width, int height, int depth) {
0338: if (width < 1)
0339: throw new IllegalArgumentException(J3dI18N
0340: .getString("ImageComponentRetained0"));
0341:
0342: if (height < 1)
0343: throw new IllegalArgumentException(J3dI18N
0344: .getString("ImageComponentRetained1"));
0345:
0346: if (depth < 1)
0347: throw new IllegalArgumentException(J3dI18N
0348: .getString("ImageComponentRetained2"));
0349:
0350: // If the format is 8bit per component, we may send it down
0351: // to OpenGL directly if its by ref case
0352: switch (format) {
0353: case ImageComponent.FORMAT_RGB:// same as ImageComponent.FORMAT_RGB8
0354: case ImageComponent.FORMAT_RGB4: // Need to be Deprecated
0355: case ImageComponent.FORMAT_RGB5: // Need to be Deprecated
0356: case ImageComponent.FORMAT_R3_G3_B2: // Need to be Deprecated
0357: numberOfComponents = 3;
0358: break;
0359: case ImageComponent.FORMAT_RGBA:// same as ImageComponent.FORMAT_RGBA8
0360: case ImageComponent.FORMAT_RGB5_A1: // Need to be Deprecated
0361: case ImageComponent.FORMAT_RGBA4: // Need to be Deprecated
0362: numberOfComponents = 4;
0363: break;
0364: case ImageComponent.FORMAT_LUM4_ALPHA4: // Need to be Deprecated
0365: case ImageComponent.FORMAT_LUM8_ALPHA8:
0366: numberOfComponents = 2;
0367: break;
0368: case ImageComponent.FORMAT_CHANNEL8:
0369: numberOfComponents = 1;
0370: break;
0371: default:
0372: throw new IllegalArgumentException(J3dI18N
0373: .getString("ImageComponentRetained3"));
0374: }
0375:
0376: this .setFormat(format);
0377: this .width = width;
0378: this .height = height;
0379: this .depth = depth;
0380: refImage = new Object[depth];
0381: }
0382:
0383: int evaluateImageType(RenderedImage ri) {
0384: int imageType = BufferedImage.TYPE_CUSTOM;
0385:
0386: if (ri instanceof BufferedImage) {
0387: imageType = ((BufferedImage) ri).getType();
0388:
0389: if (imageType != BufferedImage.TYPE_CUSTOM) {
0390: return imageType;
0391: }
0392: } else {
0393: // Fix to Issue 412. Force copy for RenderedImage of type not equal to BufferedImage.
0394: return imageType;
0395: }
0396:
0397: // System.err.println("This is a RenderedImage or BufferedImage with TYPE_CUSTOM. It imageType classification may not be correct.");
0398: ColorModel cm = ri.getColorModel();
0399: ColorSpace cs = cm.getColorSpace();
0400: SampleModel sm = ri.getSampleModel();
0401:
0402: int csType = cs.getType();
0403: boolean isAlphaPre = cm.isAlphaPremultiplied();
0404:
0405: if (csType == ColorSpace.TYPE_GRAY
0406: && cm instanceof ComponentColorModel) {
0407: if (sm.getDataType() == DataBuffer.TYPE_BYTE) {
0408: imageType = BufferedImage.TYPE_BYTE_GRAY;
0409: } else if (sm.getDataType() == DataBuffer.TYPE_USHORT) {
0410: imageType = BufferedImage.TYPE_USHORT_GRAY;
0411: }
0412: }
0413:
0414: // RGB , only interested in BYTE ABGR and BGR for now
0415: // all others will be copied to a buffered image
0416: else if (csType == ColorSpace.TYPE_RGB) {
0417: int comparedBit = 0;
0418: int smDataType = sm.getDataType();
0419: if (smDataType == DataBuffer.TYPE_BYTE) {
0420: comparedBit = 8;
0421: } else if (smDataType == DataBuffer.TYPE_INT) {
0422: comparedBit = 32;
0423: }
0424:
0425: if (comparedBit != 0) {
0426: int numBands = sm.getNumBands();
0427: if (cm instanceof ComponentColorModel
0428: && sm instanceof PixelInterleavedSampleModel) {
0429: PixelInterleavedSampleModel csm = (PixelInterleavedSampleModel) sm;
0430: int[] offs = csm.getBandOffsets();
0431: ComponentColorModel ccm = (ComponentColorModel) cm;
0432: int[] nBits = ccm.getComponentSize();
0433: boolean isNBit = true;
0434: for (int i = 0; i < numBands; i++) {
0435: if (nBits[i] != comparedBit) {
0436: isNBit = false;
0437: break;
0438: }
0439: }
0440:
0441: // Handle TYPE_BYTE
0442: if (comparedBit == 8) {
0443: if (isNBit && offs[0] == numBands - 1
0444: && offs[1] == numBands - 2
0445: && offs[2] == numBands - 3) {
0446: if (numBands == 3) {
0447: imageType = BufferedImage.TYPE_3BYTE_BGR;
0448: } else if (offs[3] == 0) {
0449: imageType = (isAlphaPre ? BufferedImage.TYPE_4BYTE_ABGR_PRE
0450: : BufferedImage.TYPE_4BYTE_ABGR);
0451: }
0452: }
0453: }
0454: //Handle TYPE_INT
0455: else {
0456: if (isNBit) {
0457: if (numBands == 3) {
0458: if (offs[0] == numBands - 1
0459: && offs[1] == numBands - 2
0460: && offs[2] == numBands - 3) {
0461: imageType = BufferedImage.TYPE_INT_BGR;
0462: } else if (offs[0] == 0 && offs[1] == 1
0463: && offs[2] == 2) {
0464: imageType = BufferedImage.TYPE_INT_RGB;
0465: }
0466: } else if (offs[0] == 3 && offs[1] == 0
0467: && offs[2] == 1 && offs[3] == 2) {
0468: imageType = (isAlphaPre ? BufferedImage.TYPE_INT_ARGB_PRE
0469: : BufferedImage.TYPE_INT_ARGB);
0470: }
0471: }
0472: }
0473: }
0474: }
0475: }
0476:
0477: return imageType;
0478: }
0479:
0480: // Assume ri's imageType is BufferedImage.TYPE_CUSTOM
0481: boolean is3ByteRGB(RenderedImage ri) {
0482: boolean value = false;
0483: int i;
0484: ColorModel cm = ri.getColorModel();
0485: ColorSpace cs = cm.getColorSpace();
0486: SampleModel sm = ri.getSampleModel();
0487: boolean isAlphaPre = cm.isAlphaPremultiplied();
0488: int csType = cs.getType();
0489: if (csType == ColorSpace.TYPE_RGB) {
0490: int numBands = sm.getNumBands();
0491: if ((numBands == 3)
0492: && (sm.getDataType() == DataBuffer.TYPE_BYTE)) {
0493: if (cm instanceof ComponentColorModel
0494: && sm instanceof PixelInterleavedSampleModel) {
0495: PixelInterleavedSampleModel csm = (PixelInterleavedSampleModel) sm;
0496: int[] offs = csm.getBandOffsets();
0497: ComponentColorModel ccm = (ComponentColorModel) cm;
0498: int[] nBits = ccm.getComponentSize();
0499: boolean is8Bit = true;
0500: for (i = 0; i < numBands; i++) {
0501: if (nBits[i] != 8) {
0502: is8Bit = false;
0503: break;
0504: }
0505: }
0506: if (is8Bit && offs[0] == 0 && offs[1] == 1
0507: && offs[2] == 2) {
0508: value = true;
0509: }
0510: }
0511: }
0512: }
0513: return value;
0514: }
0515:
0516: // Assume ri's imageType is BufferedImage.TYPE_CUSTOM
0517: boolean is4ByteRGBA(RenderedImage ri) {
0518: boolean value = false;
0519: int i;
0520: ColorModel cm = ri.getColorModel();
0521: ColorSpace cs = cm.getColorSpace();
0522: SampleModel sm = ri.getSampleModel();
0523: boolean isAlphaPre = cm.isAlphaPremultiplied();
0524: int csType = cs.getType();
0525: if (csType == ColorSpace.TYPE_RGB) {
0526: int numBands = sm.getNumBands();
0527: if ((numBands == 4)
0528: && (sm.getDataType() == DataBuffer.TYPE_BYTE)) {
0529: if (cm instanceof ComponentColorModel
0530: && sm instanceof PixelInterleavedSampleModel) {
0531: PixelInterleavedSampleModel csm = (PixelInterleavedSampleModel) sm;
0532: int[] offs = csm.getBandOffsets();
0533: ComponentColorModel ccm = (ComponentColorModel) cm;
0534: int[] nBits = ccm.getComponentSize();
0535: boolean is8Bit = true;
0536: for (i = 0; i < numBands; i++) {
0537: if (nBits[i] != 8) {
0538: is8Bit = false;
0539: break;
0540: }
0541: }
0542: if (is8Bit && offs[0] == 0 && offs[1] == 1
0543: && offs[2] == 2 && offs[3] == 3
0544: && !isAlphaPre) {
0545: value = true;
0546: }
0547: }
0548: }
0549: }
0550: return value;
0551: }
0552:
0553: // Note: This method for RenderedImage, can't be used by NioImageBuffer.
0554: /* Check if sub-image type matches image type */
0555: boolean isSubImageTypeEqual(RenderedImage ri) {
0556: int subImageType = evaluateImageType(ri);
0557:
0558: // This test is likely too loose, but the specification isn't clear either.
0559: // Assuming TYPE_CUSTOM of sub-image == the TYPE_CUSTOM of existing image.
0560: if (imageType == subImageType) {
0561: return true;
0562: } else {
0563: return false;
0564: }
0565:
0566: }
0567:
0568: // This method only support caller of offScreenBuffer and readRaster.
0569: void createBlankImageData() {
0570:
0571: assert (imageData == null);
0572:
0573: switch (numberOfComponents) {
0574: case 4:
0575: imageType = BufferedImage.TYPE_INT_ARGB;
0576: imageFormatType = ImageFormatType.TYPE_INT_ARGB;
0577: unitsPerPixel = 1;
0578: break;
0579:
0580: case 3:
0581: imageType = BufferedImage.TYPE_INT_RGB;
0582: imageFormatType = ImageFormatType.TYPE_INT_RGB;
0583: unitsPerPixel = 1;
0584: break;
0585: default:
0586: // Only valid for 3 and 4 channel case. ( Read back from framebuffer )
0587: assert false;
0588: }
0589:
0590: imageTypeIsSupported = true;
0591: imageData = createRenderedImageDataObject(null);
0592:
0593: }
0594:
0595: // This method will set imageType, imageFormatType, and unitsPerPixel
0596: // as it evaluates NioImageBuffer is supported. It will also reset
0597: // abgrSupported.
0598: boolean isImageTypeSupported(NioImageBuffer nioImgBuf) {
0599:
0600: boolean isSupported = true;
0601: NioImageBuffer.ImageType nioImageType = nioImgBuf
0602: .getImageType();
0603:
0604: switch (numberOfComponents) {
0605: case 4:
0606: switch (nioImageType) {
0607: case TYPE_4BYTE_ABGR:
0608: // TODO : This approach will lead to a very slow path
0609: // for unsupported case.
0610: if (abgrSupported) {
0611: imageFormatType = ImageFormatType.TYPE_BYTE_ABGR;
0612: } else {
0613: // Unsupported format on HW, switch to slow copy.
0614: imageFormatType = ImageFormatType.TYPE_BYTE_RGBA;
0615: isSupported = false;
0616: }
0617: unitsPerPixel = 4;
0618: break;
0619: case TYPE_4BYTE_RGBA:
0620: imageFormatType = ImageFormatType.TYPE_BYTE_RGBA;
0621: unitsPerPixel = 4;
0622: break;
0623: case TYPE_INT_ARGB:
0624: imageFormatType = ImageFormatType.TYPE_INT_ARGB;
0625: unitsPerPixel = 1;
0626: break;
0627: default:
0628: throw new IllegalArgumentException(J3dI18N
0629: .getString("ImageComponent5"));
0630:
0631: }
0632: break;
0633: case 3:
0634: switch (nioImageType) {
0635: case TYPE_3BYTE_BGR:
0636: imageFormatType = ImageFormatType.TYPE_BYTE_BGR;
0637: unitsPerPixel = 3;
0638: break;
0639: case TYPE_3BYTE_RGB:
0640: imageFormatType = ImageFormatType.TYPE_BYTE_RGB;
0641: unitsPerPixel = 3;
0642: break;
0643: case TYPE_INT_BGR:
0644: imageFormatType = ImageFormatType.TYPE_INT_BGR;
0645: unitsPerPixel = 1;
0646: break;
0647: case TYPE_INT_RGB:
0648: imageFormatType = ImageFormatType.TYPE_INT_RGB;
0649: unitsPerPixel = 1;
0650: break;
0651: default:
0652: throw new IllegalArgumentException(J3dI18N
0653: .getString("ImageComponent5"));
0654: }
0655: break;
0656:
0657: case 2:
0658: throw new IllegalArgumentException(J3dI18N
0659: .getString("ImageComponent5"));
0660: case 1:
0661: if (nioImageType == NioImageBuffer.ImageType.TYPE_BYTE_GRAY) {
0662: imageFormatType = ImageFormatType.TYPE_BYTE_GRAY;
0663: unitsPerPixel = 1;
0664: } else {
0665: throw new IllegalArgumentException(J3dI18N
0666: .getString("ImageComponent5"));
0667: }
0668: break;
0669:
0670: default:
0671: throw new AssertionError();
0672: }
0673:
0674: return isSupported;
0675: }
0676:
0677: // This method will set imageType, imageFormatType, and unitsPerPixel
0678: // as it evaluates RenderedImage is supported. It will also reset
0679: // abgrSupported.
0680: boolean isImageTypeSupported(RenderedImage ri) {
0681:
0682: boolean isSupported = true;
0683: imageType = evaluateImageType(ri);
0684:
0685: switch (numberOfComponents) {
0686: case 4:
0687: if (imageType == BufferedImage.TYPE_4BYTE_ABGR) {
0688:
0689: // TODO : This approach will lead to a very slow path
0690: // for unsupported case.
0691: if (abgrSupported) {
0692: imageFormatType = ImageFormatType.TYPE_BYTE_ABGR;
0693: } else {
0694: // Unsupported format on HW, switch to slow copy.
0695: imageFormatType = ImageFormatType.TYPE_BYTE_RGBA;
0696: isSupported = false;
0697: }
0698: unitsPerPixel = 4;
0699: } else if (imageType == BufferedImage.TYPE_INT_ARGB) {
0700: imageFormatType = ImageFormatType.TYPE_INT_ARGB;
0701: unitsPerPixel = 1;
0702: } else if (is4ByteRGBA(ri)) {
0703: imageFormatType = ImageFormatType.TYPE_BYTE_RGBA;
0704: unitsPerPixel = 4;
0705: } else {
0706: // System.err.println("Image format is unsupported --- Case 4");
0707: // Convert unsupported format to TYPE_BYTE_RGBA.
0708: imageFormatType = ImageFormatType.TYPE_BYTE_RGBA;
0709: isSupported = false;
0710: unitsPerPixel = 4;
0711: }
0712: break;
0713:
0714: case 3:
0715: if (imageType == BufferedImage.TYPE_3BYTE_BGR) {
0716: imageFormatType = ImageFormatType.TYPE_BYTE_BGR;
0717: unitsPerPixel = 3;
0718: } else if (imageType == BufferedImage.TYPE_INT_BGR) {
0719: imageFormatType = ImageFormatType.TYPE_INT_BGR;
0720: unitsPerPixel = 1;
0721: } else if (imageType == BufferedImage.TYPE_INT_RGB) {
0722: imageFormatType = ImageFormatType.TYPE_INT_RGB;
0723: unitsPerPixel = 1;
0724: } else if (is3ByteRGB(ri)) {
0725: imageFormatType = ImageFormatType.TYPE_BYTE_RGB;
0726: unitsPerPixel = 3;
0727: } else {
0728: // System.err.println("Image format is unsupported --- Case 3");
0729: // Convert unsupported format to TYPE_BYTE_RGB.
0730: imageFormatType = ImageFormatType.TYPE_BYTE_RGB;
0731: isSupported = false;
0732: unitsPerPixel = 3;
0733: }
0734: break;
0735:
0736: case 2:
0737: // System.err.println("Image format is unsupported --- Case 2");
0738: // Convert unsupported format to TYPE_BYTE_LA.
0739: imageFormatType = ImageFormatType.TYPE_BYTE_LA;
0740: isSupported = false;
0741: unitsPerPixel = 2;
0742: break;
0743:
0744: case 1:
0745: if (imageType == BufferedImage.TYPE_BYTE_GRAY) {
0746: imageFormatType = ImageFormatType.TYPE_BYTE_GRAY;
0747: unitsPerPixel = 1;
0748: } else {
0749: // System.err.println("Image format is unsupported --- Case 1");
0750: // Convert unsupported format to TYPE_BYTE_GRAY.
0751: imageFormatType = ImageFormatType.TYPE_BYTE_GRAY;
0752: isSupported = false;
0753: unitsPerPixel = 1;
0754: }
0755: break;
0756:
0757: default:
0758: throw new AssertionError();
0759: }
0760:
0761: return isSupported;
0762: }
0763:
0764: /*
0765: * This method assume that the following members have been initialized :
0766: * width, height, depth, imageFormatType, and unitsPerPixel.
0767: */
0768: ImageData createNioImageBufferDataObject(
0769: NioImageBuffer nioImageBuffer) {
0770:
0771: switch (imageFormatType) {
0772: case TYPE_BYTE_GRAY:
0773: case TYPE_BYTE_LA:
0774: case TYPE_BYTE_RGB:
0775: case TYPE_BYTE_BGR:
0776: case TYPE_BYTE_RGBA:
0777: case TYPE_BYTE_ABGR:
0778: if (nioImageBuffer != null) {
0779: return new ImageData(ImageDataType.TYPE_BYTE_BUFFER,
0780: width * height * depth * unitsPerPixel, width,
0781: height, nioImageBuffer);
0782: } else {
0783: // This is needed only if abgr is unsupported.
0784: return new ImageData(ImageDataType.TYPE_BYTE_BUFFER,
0785: width * height * depth * unitsPerPixel, width,
0786: height);
0787: }
0788: case TYPE_INT_RGB:
0789: case TYPE_INT_BGR:
0790: case TYPE_INT_ARGB:
0791: return new ImageData(ImageDataType.TYPE_INT_BUFFER, width
0792: * height * depth * unitsPerPixel, width, height,
0793: nioImageBuffer);
0794: default:
0795: throw new AssertionError();
0796: }
0797: }
0798:
0799: /*
0800: * This method assume that the following members have been initialized :
0801: * depth, imageType, imageFormatType, and unitsPerPixel.
0802: */
0803: ImageData createRenderedImageDataObject(RenderedImage byRefImage,
0804: int dataWidth, int dataHeight) {
0805: switch (imageFormatType) {
0806: case TYPE_BYTE_GRAY:
0807: case TYPE_BYTE_LA:
0808: case TYPE_BYTE_RGB:
0809: case TYPE_BYTE_BGR:
0810: case TYPE_BYTE_RGBA:
0811: case TYPE_BYTE_ABGR:
0812: if (byRefImage != null) {
0813: return new ImageData(ImageDataType.TYPE_BYTE_ARRAY,
0814: dataWidth * dataHeight * depth * unitsPerPixel,
0815: dataWidth, dataHeight, byRefImage);
0816: } else {
0817: return new ImageData(ImageDataType.TYPE_BYTE_ARRAY,
0818: dataWidth * dataHeight * depth * unitsPerPixel,
0819: dataWidth, dataHeight);
0820: }
0821: case TYPE_INT_RGB:
0822: case TYPE_INT_BGR:
0823: case TYPE_INT_ARGB:
0824: if (byRefImage != null) {
0825: return new ImageData(ImageDataType.TYPE_INT_ARRAY,
0826: dataWidth * dataHeight * depth * unitsPerPixel,
0827: dataWidth, dataHeight, byRefImage);
0828: } else {
0829: return new ImageData(ImageDataType.TYPE_INT_ARRAY,
0830: dataWidth * dataHeight * depth * unitsPerPixel,
0831: dataWidth, dataHeight);
0832: }
0833: default:
0834: throw new AssertionError();
0835: }
0836: }
0837:
0838: private void updateImageDataPowerOfTwo(int depthIndex) {
0839: assert enforceNonPowerOfTwoSupport;
0840: BufferedImage bufImage = imageData
0841: .createBufferedImage(depthIndex);
0842: BufferedImage scaledImg = powerOfTwoATOp.filter(bufImage, null);
0843: copySupportedImageToImageData(scaledImg, 0, imageDataPowerOfTwo);
0844: }
0845:
0846: /*
0847: * This method assume that the following members have been initialized :
0848: * width, height, depth, imageType, imageFormatType, and bytesPerPixel.
0849: */
0850: ImageData createRenderedImageDataObject(RenderedImage byRefImage) {
0851:
0852: return createRenderedImageDataObject(byRefImage, width, height);
0853:
0854: }
0855:
0856: /**
0857: * Copy specified region of image data from RenderedImage to
0858: * ImageComponent's imageData object
0859: */
0860: void copySupportedImageToImageData(RenderedImage ri, int srcX,
0861: int srcY, int dstX, int dstY, int depthIndex,
0862: int copyWidth, int copyHeight, ImageData data) {
0863:
0864: assert (data != null);
0865:
0866: ColorModel cm = ri.getColorModel();
0867:
0868: int xoff = ri.getTileGridXOffset(); // tile origin x offset
0869: int yoff = ri.getTileGridYOffset(); // tile origin y offset
0870: int minTileX = ri.getMinTileX(); // min tile x index
0871: int minTileY = ri.getMinTileY(); // min tile y index
0872: tilew = ri.getTileWidth(); // tile width in pixels
0873: tileh = ri.getTileHeight(); // tile height in pixels
0874:
0875: // determine the first tile of the image
0876: float mt;
0877:
0878: mt = (float) (srcX - xoff) / (float) tilew;
0879: if (mt < 0) {
0880: minTileX = (int) (mt - 1);
0881: } else {
0882: minTileX = (int) mt;
0883: }
0884:
0885: mt = (float) (srcY - yoff) / (float) tileh;
0886: if (mt < 0) {
0887: minTileY = (int) (mt - 1);
0888: } else {
0889: minTileY = (int) mt;
0890: }
0891:
0892: // determine the pixel offset of the upper-left corner of the
0893: // first tile
0894: int startXTile = minTileX * tilew + xoff;
0895: int startYTile = minTileY * tileh + yoff;
0896:
0897: // image dimension in the first tile
0898: int curw = (startXTile + tilew - srcX);
0899: int curh = (startYTile + tileh - srcY);
0900:
0901: // check if the to-be-copied region is less than the tile image
0902: // if so, update the to-be-copied dimension of this tile
0903: if (curw > copyWidth) {
0904: curw = copyWidth;
0905: }
0906:
0907: if (curh > copyHeight) {
0908: curh = copyHeight;
0909: }
0910:
0911: // save the to-be-copied width of the left most tile
0912: int startw = curw;
0913:
0914: // temporary variable for dimension of the to-be-copied region
0915: int tmpw = copyWidth;
0916: int tmph = copyHeight;
0917:
0918: // offset of the first pixel of the tile to be copied; offset is
0919: // relative to the upper left corner of the title
0920: int x = srcX - startXTile;
0921: int y = srcY - startYTile;
0922:
0923: // determine the number of tiles in each direction that the
0924: // image spans
0925: numXTiles = (copyWidth + x) / tilew;
0926: numYTiles = (copyHeight + y) / tileh;
0927:
0928: if (((float) (copyWidth + x) % (float) tilew) > 0) {
0929: numXTiles += 1;
0930: }
0931:
0932: if (((float) (copyHeight + y) % (float) tileh) > 0) {
0933: numYTiles += 1;
0934: }
0935:
0936: int offset;
0937: int w, h, i, j, m, n;
0938: int dstBegin;
0939: Object pixel = null;
0940: java.awt.image.Raster ras;
0941: int lineUnits; // nbytes per line in dst image buffer
0942: int sign; // -1 for going down
0943: int dstLineUnits; // sign * lineUnits
0944: int tileStart; // destination buffer offset
0945: // at the next left most tile
0946:
0947: byte[] dstByteBuffer = null;
0948: int[] dstIntBuffer = null;
0949:
0950: switch (data.getType()) {
0951: case TYPE_BYTE_ARRAY:
0952: dstByteBuffer = data.getAsByteArray();
0953: break;
0954: case TYPE_INT_ARRAY:
0955: dstIntBuffer = data.getAsIntArray();
0956: break;
0957: default:
0958: assert false;
0959: }
0960:
0961: int dataWidth = data.dataWidth;
0962: int dataHeight = data.dataHeight;
0963:
0964: lineUnits = dataWidth * unitsPerPixel;
0965: if (yUp) {
0966: // destination buffer offset
0967: tileStart = (depthIndex * dataWidth * dataHeight + dstY
0968: * dataWidth + dstX)
0969: * unitsPerPixel;
0970: sign = 1;
0971: dstLineUnits = lineUnits;
0972: } else {
0973: // destination buffer offset
0974: tileStart = (depthIndex * dataWidth * dataHeight
0975: + (dataHeight - dstY - 1) * dataWidth + dstX)
0976: * unitsPerPixel;
0977: sign = -1;
0978: dstLineUnits = -lineUnits;
0979: }
0980:
0981: /*
0982: System.err.println("tileStart= " + tileStart + " dstLineUnits= " + dstLineUnits);
0983: System.err.println("startw= " + startw);
0984: */
0985:
0986: // allocate memory for a pixel
0987: ras = ri.getTile(minTileX, minTileY);
0988: pixel = getDataElementBuffer(ras);
0989:
0990: int srcOffset, dstOffset;
0991: int tileLineUnits = tilew * unitsPerPixel;
0992: int copyUnits;
0993:
0994: for (n = minTileY; n < minTileY + numYTiles; n++) {
0995:
0996: dstBegin = tileStart; // destination buffer offset
0997: tmpw = copyWidth; // reset the width to be copied
0998: curw = startw; // reset the width to be copied of
0999: // the left most tile
1000: x = srcX - startXTile; // reset the starting x offset of
1001: // the left most tile
1002:
1003: for (m = minTileX; m < minTileX + numXTiles; m++) {
1004:
1005: // retrieve the raster for the next tile
1006: ras = ri.getTile(m, n);
1007:
1008: srcOffset = (y * tilew + x) * unitsPerPixel;
1009: dstOffset = dstBegin;
1010:
1011: copyUnits = curw * unitsPerPixel;
1012:
1013: //System.err.println("curh = "+curh+" curw = "+curw);
1014: //System.err.println("x = "+x+" y = "+y);
1015:
1016: switch (data.getType()) {
1017: case TYPE_BYTE_ARRAY:
1018: byte[] srcByteBuffer = ((DataBufferByte) ras
1019: .getDataBuffer()).getData();
1020: for (h = 0; h < curh; h++) {
1021: System.arraycopy(srcByteBuffer, srcOffset,
1022: dstByteBuffer, dstOffset, copyUnits);
1023: srcOffset += tileLineUnits;
1024: dstOffset += dstLineUnits;
1025: }
1026: break;
1027: case TYPE_INT_ARRAY:
1028: int[] srcIntBuffer = ((DataBufferInt) ras
1029: .getDataBuffer()).getData();
1030: for (h = 0; h < curh; h++) {
1031: System.arraycopy(srcIntBuffer, srcOffset,
1032: dstIntBuffer, dstOffset, copyUnits);
1033: srcOffset += tileLineUnits;
1034: dstOffset += dstLineUnits;
1035: }
1036: break;
1037: default:
1038: assert false;
1039: }
1040:
1041: // advance the destination buffer offset
1042: dstBegin += curw * unitsPerPixel;
1043:
1044: // move to the next tile in x direction
1045: x = 0;
1046:
1047: // determine the width of copy region of the next tile
1048:
1049: tmpw -= curw;
1050: if (tmpw < tilew) {
1051: curw = tmpw;
1052: } else {
1053: curw = tilew;
1054: }
1055: }
1056:
1057: // we are done copying an array of tiles in the x direction
1058: // advance the tileStart offset
1059: tileStart += dataWidth * unitsPerPixel * curh * sign;
1060:
1061: // move to the next set of tiles in y direction
1062: y = 0;
1063:
1064: // determine the height of copy region for the next set
1065: // of tiles
1066: tmph -= curh;
1067: if (tmph < tileh) {
1068: curh = tmph;
1069: } else {
1070: curh = tileh;
1071: }
1072: }
1073:
1074: if ((imageData == data) && (imageDataPowerOfTwo != null)) {
1075: updateImageDataPowerOfTwo(depthIndex);
1076: }
1077: }
1078:
1079: // Quick line by line copy
1080: void copyImageLineByLine(BufferedImage bi, int srcX, int srcY,
1081: int dstX, int dstY, int depthIndex, int copyWidth,
1082: int copyHeight, ImageData data) {
1083:
1084: assert (data != null);
1085:
1086: int h;
1087: int rowBegin, // src begin row index
1088: srcBegin, // src begin offset
1089: dstBegin; // dst begin offset
1090:
1091: int dataWidth = data.dataWidth;
1092: int dataHeight = data.dataHeight;
1093: int dstUnitsPerRow = dataWidth * unitsPerPixel; // bytes per row in dst image
1094: rowBegin = srcY;
1095:
1096: if (yUp) {
1097: dstBegin = (depthIndex * dataWidth * dataHeight + dstY
1098: * dataWidth + dstX)
1099: * unitsPerPixel;
1100: } else {
1101: dstBegin = (depthIndex * dataWidth * dataHeight
1102: + (dataHeight - dstY - 1) * dataWidth + dstX)
1103: * unitsPerPixel;
1104: dstUnitsPerRow = -1 * dstUnitsPerRow;
1105: }
1106:
1107: int copyUnits = copyWidth * unitsPerPixel;
1108: int srcWidth = bi.getWidth();
1109: int srcUnitsPerRow = srcWidth * unitsPerPixel;
1110: srcBegin = (rowBegin * srcWidth + srcX) * unitsPerPixel;
1111:
1112: switch (data.getType()) {
1113: case TYPE_BYTE_ARRAY:
1114: byte[] srcByteBuffer = ((DataBufferByte) bi.getRaster()
1115: .getDataBuffer()).getData();
1116: byte[] dstByteBuffer = data.getAsByteArray();
1117: for (h = 0; h < copyHeight; h++) {
1118: System.arraycopy(srcByteBuffer, srcBegin,
1119: dstByteBuffer, dstBegin, copyUnits);
1120: dstBegin += dstUnitsPerRow;
1121: srcBegin += srcUnitsPerRow;
1122: }
1123: break;
1124:
1125: case TYPE_INT_ARRAY:
1126: int[] srcIntBuffer = ((DataBufferInt) bi.getRaster()
1127: .getDataBuffer()).getData();
1128: int[] dstIntBuffer = data.getAsIntArray();
1129: for (h = 0; h < copyHeight; h++) {
1130: System.arraycopy(srcIntBuffer, srcBegin, dstIntBuffer,
1131: dstBegin, copyUnits);
1132: dstBegin += dstUnitsPerRow;
1133: srcBegin += srcUnitsPerRow;
1134: }
1135: break;
1136: default:
1137: assert false;
1138: }
1139:
1140: if ((imageData == data) && (imageDataPowerOfTwo != null)) {
1141: updateImageDataPowerOfTwo(depthIndex);
1142: }
1143: }
1144:
1145: // Quick block copy for yUp image
1146: void copyImageByBlock(BufferedImage bi, int depthIndex,
1147: ImageData data) {
1148:
1149: assert ((data != null) && yUp);
1150:
1151: int dataWidth = data.dataWidth;
1152: int dataHeight = data.dataHeight;
1153:
1154: int dstBegin; // dst begin offset
1155: dstBegin = depthIndex * dataWidth * dataHeight * unitsPerPixel;
1156:
1157: switch (imageData.getType()) {
1158: case TYPE_BYTE_ARRAY:
1159: byte[] srcByteBuffer = ((DataBufferByte) bi.getRaster()
1160: .getDataBuffer()).getData();
1161: byte[] dstByteBuffer = data.getAsByteArray();
1162: System.arraycopy(srcByteBuffer, 0, dstByteBuffer, dstBegin,
1163: (dataWidth * dataHeight * unitsPerPixel));
1164: break;
1165: case TYPE_INT_ARRAY:
1166: int[] srcIntBuffer = ((DataBufferInt) bi.getRaster()
1167: .getDataBuffer()).getData();
1168: int[] dstIntBuffer = data.getAsIntArray();
1169: System.arraycopy(srcIntBuffer, 0, dstIntBuffer, dstBegin,
1170: (dataWidth * dataHeight * unitsPerPixel));
1171: break;
1172: default:
1173: assert false;
1174: }
1175:
1176: if ((imageData == data) && (imageDataPowerOfTwo != null)) {
1177: updateImageDataPowerOfTwo(depthIndex);
1178: }
1179:
1180: }
1181:
1182: /**
1183: * copy complete region of a RenderedImage to ImageComponent's imageData object.
1184: */
1185: void copySupportedImageToImageData(RenderedImage ri,
1186: int depthIndex, ImageData data) {
1187:
1188: if (ri instanceof BufferedImage) {
1189: if (yUp) {
1190: /* Use quick block copy when ( format is OK, Yup is true, and byRef is false). */
1191: // System.err.println("ImageComponentRetained.copySupportedImageToImageData() : (imageTypeSupported && !byReference && yUp) --- (2 BI)");
1192: copyImageByBlock((BufferedImage) ri, depthIndex, data);
1193: } else {
1194: /* Use quick inverse line by line copy when (format is OK and Yup is false). */
1195: // System.err.println("ImageComponentRetained.copySupportedImageToImageData() : (imageTypeSupported && !yUp) --- (3 BI)");
1196: copyImageLineByLine((BufferedImage) ri, 0, 0, 0, 0,
1197: depthIndex, data.dataWidth, data.dataHeight,
1198: data);
1199: }
1200: } else {
1201: // System.err.println("ImageComponentRetained.copySupportedImageToImageData() : (imageTypeSupported && !byReference ) --- (2 RI)");
1202: copySupportedImageToImageData(ri, ri.getMinX(), ri
1203: .getMinY(), 0, 0, depthIndex, data.dataWidth,
1204: data.dataHeight, data);
1205:
1206: /*
1207: * An alternative approach.
1208: *
1209: // Create a buffered image from renderImage
1210: ColorModel cm = ri.getColorModel();
1211: WritableRaster wRaster = ri.copyData(null);
1212: BufferedImage bi = new BufferedImage(cm,
1213: wRaster,
1214: cm.isAlphaPremultiplied()
1215: ,null);
1216:
1217: copySupportedImageToImageData((BufferedImage)ri, 0, 0, 0, 0, depthIndex, data.dataWidth, data.dataHeight, data);
1218:
1219: *
1220: *
1221: */
1222: }
1223: }
1224:
1225: /*
1226: * copy the complete unsupported NioImageBuffer into a supported BYTE_BUFFER format
1227: */
1228: void copyUnsupportedNioImageToImageData(NioImageBuffer nioImage,
1229: int srcX, int srcY, int dstX, int dstY, int copyWidth,
1230: int copyHeight, ImageData iData) {
1231:
1232: if (MasterControl.isDevLoggable(Level.INFO)) {
1233: MasterControl
1234: .getDevLogger()
1235: .info(
1236: "ImageComponent - Copying Unsupported NioImage, use a different image type");
1237: }
1238:
1239: assert (iData.getType() == ImageDataType.TYPE_BYTE_BUFFER);
1240: assert (getImageFormatType() == ImageFormatType.TYPE_BYTE_RGBA);
1241:
1242: int length = copyWidth * copyHeight;
1243: ByteBuffer srcBuffer = (ByteBuffer) nioImage.getDataBuffer();
1244: srcBuffer.rewind();
1245: ByteBuffer dstBuffer = iData.getAsByteBuffer();
1246: dstBuffer.rewind();
1247:
1248: // Do copy and swap.
1249: for (int i = 0; i < length; i += 4) {
1250: dstBuffer.put(i, srcBuffer.get(i + 3));
1251: dstBuffer.put(i + 1, srcBuffer.get(i + 2));
1252: dstBuffer.put(i + 2, srcBuffer.get(i + 1));
1253: dstBuffer.put(i + 3, srcBuffer.get(i));
1254: }
1255: }
1256:
1257: /*
1258: * copy the complete unsupported image into a supported BYTE_ARRAY format
1259: */
1260: void copyUnsupportedImageToImageData(RenderedImage ri,
1261: int depthIndex, ImageData data) {
1262:
1263: assert (data.getType() == ImageDataType.TYPE_BYTE_ARRAY);
1264:
1265: if (MasterControl.isDevLoggable(Level.INFO)) {
1266: MasterControl
1267: .getDevLogger()
1268: .info(
1269: "ImageComponent - Copying Unsupported Image, use a different image type");
1270: }
1271:
1272: if (ri instanceof BufferedImage) {
1273: copyUnsupportedImageToImageData((BufferedImage) ri, 0, 0,
1274: 0, 0, depthIndex, data.dataWidth, data.dataHeight,
1275: data);
1276: } else {
1277: copyUnsupportedImageToImageData(ri, ri.getMinX(), ri
1278: .getMinY(), 0, 0, depthIndex, data.dataWidth,
1279: data.dataHeight, data);
1280: }
1281: }
1282:
1283: void copyUnsupportedImageToImageData(BufferedImage bi, int srcX,
1284: int srcY, int dstX, int dstY, int depthIndex,
1285: int copyWidth, int copyHeight, ImageData data) {
1286:
1287: int w, h, i, j;
1288: int rowBegin, // src begin row index
1289: srcBegin, // src begin offset
1290: dstBegin, // dst begin offset
1291: rowInc, // row increment
1292: // -1 --- ydown
1293: // 1 --- yup
1294: row;
1295:
1296: rowBegin = srcY;
1297: rowInc = 1;
1298:
1299: assert (data != null);
1300:
1301: int dataWidth = data.dataWidth;
1302: int dataHeight = data.dataHeight;
1303: int dstBytesPerRow = dataWidth * unitsPerPixel; // bytes per row in dst image
1304:
1305: if (yUp) {
1306: dstBegin = (depthIndex * dataWidth * dataHeight + dstY
1307: * dataWidth + dstX)
1308: * unitsPerPixel;
1309: } else {
1310: dstBegin = (depthIndex * dataWidth * dataHeight
1311: + (dataHeight - dstY - 1) * dataWidth + dstX)
1312: * unitsPerPixel;
1313: dstBytesPerRow = -1 * dstBytesPerRow;
1314: }
1315:
1316: WritableRaster ras = bi.getRaster();
1317: ColorModel cm = bi.getColorModel();
1318: Object pixel = getDataElementBuffer(ras);
1319:
1320: byte[] dstBuffer = data.getAsByteArray();
1321:
1322: switch (numberOfComponents) {
1323: case 4: {
1324: for (row = rowBegin, h = 0; h < copyHeight; h++, row += rowInc) {
1325: j = dstBegin;
1326: for (w = srcX; w < (copyWidth + srcX); w++) {
1327: ras.getDataElements(w, row, pixel);
1328: dstBuffer[j++] = (byte) cm.getRed(pixel);
1329: dstBuffer[j++] = (byte) cm.getGreen(pixel);
1330: dstBuffer[j++] = (byte) cm.getBlue(pixel);
1331: dstBuffer[j++] = (byte) cm.getAlpha(pixel);
1332: }
1333: dstBegin += dstBytesPerRow;
1334: }
1335: }
1336: break;
1337:
1338: case 3: {
1339: for (row = rowBegin, h = 0; h < copyHeight; h++, row += rowInc) {
1340: j = dstBegin;
1341: for (w = srcX; w < (copyWidth + srcX); w++) {
1342: ras.getDataElements(w, row, pixel);
1343: dstBuffer[j++] = (byte) cm.getRed(pixel);
1344: dstBuffer[j++] = (byte) cm.getGreen(pixel);
1345: dstBuffer[j++] = (byte) cm.getBlue(pixel);
1346: }
1347: dstBegin += dstBytesPerRow;
1348: }
1349: }
1350: break;
1351:
1352: case 2: {
1353: for (row = rowBegin, h = 0; h < copyHeight; h++, row += rowInc) {
1354: j = dstBegin;
1355: for (w = srcX; w < (copyWidth + srcX); w++) {
1356: ras.getDataElements(w, row, pixel);
1357: dstBuffer[j++] = (byte) cm.getRed(pixel);
1358: dstBuffer[j++] = (byte) cm.getAlpha(pixel);
1359: }
1360: dstBegin += dstBytesPerRow;
1361: }
1362: }
1363: break;
1364:
1365: case 1: {
1366: for (row = rowBegin, h = 0; h < copyHeight; h++, row += rowInc) {
1367: j = dstBegin;
1368: for (w = srcX; w < (copyWidth + srcX); w++) {
1369: ras.getDataElements(w, row, pixel);
1370: dstBuffer[j++] = (byte) cm.getRed(pixel);
1371: }
1372: dstBegin += dstBytesPerRow;
1373: }
1374: }
1375: break;
1376: default:
1377: assert false;
1378: }
1379:
1380: if ((imageData == data) && (imageDataPowerOfTwo != null)) {
1381: updateImageDataPowerOfTwo(depthIndex);
1382: }
1383: }
1384:
1385: void copyUnsupportedImageToImageData(RenderedImage ri, int srcX,
1386: int srcY, int dstX, int dstY, int depthIndex,
1387: int copyWidth, int copyHeight, ImageData data) {
1388:
1389: int w, h, i, j, m, n;
1390: int dstBegin;
1391: Object pixel = null;
1392: java.awt.image.Raster ras;
1393: // dst image buffer
1394: int sign; // -1 for going down
1395: int dstLineBytes; // sign * lineBytes
1396: int tileStart; // destination buffer offset
1397: // at the next left most tile
1398:
1399: int offset;
1400:
1401: ColorModel cm = ri.getColorModel();
1402:
1403: int xoff = ri.getTileGridXOffset(); // tile origin x offset
1404: int yoff = ri.getTileGridYOffset(); // tile origin y offset
1405: int minTileX = ri.getMinTileX(); // min tile x index
1406: int minTileY = ri.getMinTileY(); // min tile y index
1407: tilew = ri.getTileWidth(); // tile width in pixels
1408: tileh = ri.getTileHeight(); // tile height in pixels
1409:
1410: // determine the first tile of the image
1411:
1412: float mt;
1413:
1414: mt = (float) (srcX - xoff) / (float) tilew;
1415: if (mt < 0) {
1416: minTileX = (int) (mt - 1);
1417: } else {
1418: minTileX = (int) mt;
1419: }
1420:
1421: mt = (float) (srcY - yoff) / (float) tileh;
1422: if (mt < 0) {
1423: minTileY = (int) (mt - 1);
1424: } else {
1425: minTileY = (int) mt;
1426: }
1427:
1428: // determine the pixel offset of the upper-left corner of the
1429: // first tile
1430: int startXTile = minTileX * tilew + xoff;
1431: int startYTile = minTileY * tileh + yoff;
1432:
1433: // image dimension in the first tile
1434: int curw = (startXTile + tilew - srcX);
1435: int curh = (startYTile + tileh - srcY);
1436:
1437: // check if the to-be-copied region is less than the tile image
1438: // if so, update the to-be-copied dimension of this tile
1439: if (curw > copyWidth) {
1440: curw = copyWidth;
1441: }
1442:
1443: if (curh > copyHeight) {
1444: curh = copyHeight;
1445: }
1446:
1447: // save the to-be-copied width of the left most tile
1448: int startw = curw;
1449:
1450: // temporary variable for dimension of the to-be-copied region
1451: int tmpw = copyWidth;
1452: int tmph = copyHeight;
1453:
1454: // offset of the first pixel of the tile to be copied; offset is
1455: // relative to the upper left corner of the title
1456: int x = srcX - startXTile;
1457: int y = srcY - startYTile;
1458:
1459: // determine the number of tiles in each direction that the
1460: // image spans
1461:
1462: numXTiles = (copyWidth + x) / tilew;
1463: numYTiles = (copyHeight + y) / tileh;
1464:
1465: if (((float) (copyWidth + x) % (float) tilew) > 0) {
1466: numXTiles += 1;
1467: }
1468:
1469: if (((float) (copyHeight + y) % (float) tileh) > 0) {
1470: numYTiles += 1;
1471: }
1472:
1473: assert (data != null);
1474: int dataWidth = data.dataWidth;
1475: int dataHeight = data.dataHeight;
1476: int lineBytes = dataWidth * unitsPerPixel; // nbytes per line in
1477:
1478: if (yUp) {
1479: // destination buffer offset
1480: tileStart = (depthIndex * dataWidth * dataHeight + dstY
1481: * dataWidth + dstX)
1482: * unitsPerPixel;
1483: sign = 1;
1484: dstLineBytes = lineBytes;
1485: } else {
1486: // destination buffer offset
1487: tileStart = (depthIndex * dataWidth * dataHeight
1488: + (dataHeight - dstY - 1) * dataWidth + dstX)
1489: * unitsPerPixel;
1490: sign = -1;
1491: dstLineBytes = -lineBytes;
1492: }
1493:
1494: /*
1495: System.err.println("tileStart= " + tileStart + " dstLineBytes= " + dstLineBytes);
1496: System.err.println("startw= " + startw);
1497: */
1498:
1499: // allocate memory for a pixel
1500: ras = ri.getTile(minTileX, minTileY);
1501: pixel = getDataElementBuffer(ras);
1502: byte[] dstBuffer = imageData.getAsByteArray();
1503:
1504: switch (numberOfComponents) {
1505: case 4: {
1506: // System.err.println("Case 1: byReference = "+byReference);
1507: for (n = minTileY; n < minTileY + numYTiles; n++) {
1508:
1509: dstBegin = tileStart; // destination buffer offset
1510: tmpw = copyWidth; // reset the width to be copied
1511: curw = startw; // reset the width to be copied of
1512: // the left most tile
1513: x = srcX - startXTile; // reset the starting x offset of
1514: // the left most tile
1515:
1516: for (m = minTileX; m < minTileX + numXTiles; m++) {
1517:
1518: // retrieve the raster for the next tile
1519: ras = ri.getTile(m, n);
1520:
1521: j = dstBegin;
1522: offset = 0;
1523:
1524: //System.err.println("curh = "+curh+" curw = "+curw);
1525: //System.err.println("x = "+x+" y = "+y);
1526:
1527: for (h = y; h < (y + curh); h++) {
1528: // System.err.println("j = "+j);
1529: for (w = x; w < (x + curw); w++) {
1530: ras.getDataElements(w, h, pixel);
1531: dstBuffer[j++] = (byte) cm.getRed(pixel);
1532: dstBuffer[j++] = (byte) cm.getGreen(pixel);
1533: dstBuffer[j++] = (byte) cm.getBlue(pixel);
1534: dstBuffer[j++] = (byte) cm.getAlpha(pixel);
1535: }
1536: offset += dstLineBytes;
1537: j = dstBegin + offset;
1538: }
1539:
1540: // advance the destination buffer offset
1541: dstBegin += curw * unitsPerPixel;
1542:
1543: // move to the next tile in x direction
1544: x = 0;
1545:
1546: // determine the width of copy region of the next tile
1547:
1548: tmpw -= curw;
1549: if (tmpw < tilew) {
1550: curw = tmpw;
1551: } else {
1552: curw = tilew;
1553: }
1554: }
1555:
1556: // we are done copying an array of tiles in the x direction
1557: // advance the tileStart offset
1558:
1559: tileStart += dataWidth * unitsPerPixel * curh * sign;
1560:
1561: // move to the next set of tiles in y direction
1562: y = 0;
1563:
1564: // determine the height of copy region for the next set
1565: // of tiles
1566: tmph -= curh;
1567: if (tmph < tileh) {
1568: curh = tmph;
1569: } else {
1570: curh = tileh;
1571: }
1572: }
1573: }
1574: break;
1575: case 3: {
1576: for (n = minTileY; n < minTileY + numYTiles; n++) {
1577:
1578: dstBegin = tileStart; // destination buffer offset
1579: tmpw = copyWidth; // reset the width to be copied
1580: curw = startw; // reset the width to be copied of
1581: // the left most tile
1582: x = srcX - startXTile; // reset the starting x offset of
1583: // the left most tile
1584:
1585: for (m = minTileX; m < minTileX + numXTiles; m++) {
1586:
1587: // retrieve the raster for the next tile
1588: ras = ri.getTile(m, n);
1589:
1590: j = dstBegin;
1591: offset = 0;
1592:
1593: //System.err.println("curh = "+curh+" curw = "+curw);
1594: //System.err.println("x = "+x+" y = "+y);
1595:
1596: for (h = y; h < (y + curh); h++) {
1597: // System.err.println("j = "+j);
1598: for (w = x; w < (x + curw); w++) {
1599: ras.getDataElements(w, h, pixel);
1600: dstBuffer[j++] = (byte) cm.getRed(pixel);
1601: dstBuffer[j++] = (byte) cm.getGreen(pixel);
1602: dstBuffer[j++] = (byte) cm.getBlue(pixel);
1603: }
1604: offset += dstLineBytes;
1605: j = dstBegin + offset;
1606: }
1607:
1608: // advance the destination buffer offset
1609: dstBegin += curw * unitsPerPixel;
1610:
1611: // move to the next tile in x direction
1612: x = 0;
1613:
1614: // determine the width of copy region of the next tile
1615:
1616: tmpw -= curw;
1617: if (tmpw < tilew) {
1618: curw = tmpw;
1619: } else {
1620: curw = tilew;
1621: }
1622: }
1623:
1624: // we are done copying an array of tiles in the x direction
1625: // advance the tileStart offset
1626:
1627: tileStart += dataWidth * unitsPerPixel * curh * sign;
1628:
1629: // move to the next set of tiles in y direction
1630: y = 0;
1631:
1632: // determine the height of copy region for the next set
1633: // of tiles
1634: tmph -= curh;
1635: if (tmph < tileh) {
1636: curh = tmph;
1637: } else {
1638: curh = tileh;
1639: }
1640: }
1641: }
1642: break;
1643: case 2: {
1644: for (n = minTileY; n < minTileY + numYTiles; n++) {
1645:
1646: dstBegin = tileStart; // destination buffer offset
1647: tmpw = copyWidth; // reset the width to be copied
1648: curw = startw; // reset the width to be copied of
1649: // the left most tile
1650: x = srcX - startXTile; // reset the starting x offset of
1651: // the left most tile
1652:
1653: for (m = minTileX; m < minTileX + numXTiles; m++) {
1654:
1655: // retrieve the raster for the next tile
1656: ras = ri.getTile(m, n);
1657:
1658: j = dstBegin;
1659: offset = 0;
1660:
1661: //System.err.println("curh = "+curh+" curw = "+curw);
1662: //System.err.println("x = "+x+" y = "+y);
1663:
1664: for (h = y; h < (y + curh); h++) {
1665: // System.err.println("j = "+j);
1666: for (w = x; w < (x + curw); w++) {
1667: ras.getDataElements(w, h, pixel);
1668: dstBuffer[j++] = (byte) cm.getRed(pixel);
1669: dstBuffer[j++] = (byte) cm.getAlpha(pixel);
1670: }
1671: offset += dstLineBytes;
1672: j = dstBegin + offset;
1673: }
1674:
1675: // advance the destination buffer offset
1676: dstBegin += curw * unitsPerPixel;
1677:
1678: // move to the next tile in x direction
1679: x = 0;
1680:
1681: // determine the width of copy region of the next tile
1682:
1683: tmpw -= curw;
1684: if (tmpw < tilew) {
1685: curw = tmpw;
1686: } else {
1687: curw = tilew;
1688: }
1689: }
1690:
1691: // we are done copying an array of tiles in the x direction
1692: // advance the tileStart offset
1693:
1694: tileStart += dataWidth * unitsPerPixel * curh * sign;
1695:
1696: // move to the next set of tiles in y direction
1697: y = 0;
1698:
1699: // determine the height of copy region for the next set
1700: // of tiles
1701: tmph -= curh;
1702: if (tmph < tileh) {
1703: curh = tmph;
1704: } else {
1705: curh = tileh;
1706: }
1707: }
1708: }
1709: break;
1710: case 1: {
1711: for (n = minTileY; n < minTileY + numYTiles; n++) {
1712:
1713: dstBegin = tileStart; // destination buffer offset
1714: tmpw = copyWidth; // reset the width to be copied
1715: curw = startw; // reset the width to be copied of
1716: // the left most tile
1717: x = srcX - startXTile; // reset the starting x offset of
1718: // the left most tile
1719:
1720: for (m = minTileX; m < minTileX + numXTiles; m++) {
1721:
1722: // retrieve the raster for the next tile
1723: ras = ri.getTile(m, n);
1724:
1725: j = dstBegin;
1726: offset = 0;
1727:
1728: //System.err.println("curh = "+curh+" curw = "+curw);
1729: //System.err.println("x = "+x+" y = "+y);
1730:
1731: for (h = y; h < (y + curh); h++) {
1732: // System.err.println("j = "+j);
1733: for (w = x; w < (x + curw); w++) {
1734: ras.getDataElements(w, h, pixel);
1735: dstBuffer[j++] = (byte) cm.getRed(pixel);
1736: }
1737: offset += dstLineBytes;
1738: j = dstBegin + offset;
1739: }
1740:
1741: // advance the destination buffer offset
1742: dstBegin += curw * unitsPerPixel;
1743:
1744: // move to the next tile in x direction
1745: x = 0;
1746:
1747: // determine the width of copy region of the next tile
1748:
1749: tmpw -= curw;
1750: if (tmpw < tilew) {
1751: curw = tmpw;
1752: } else {
1753: curw = tilew;
1754: }
1755: }
1756:
1757: // we are done copying an array of tiles in the x direction
1758: // advance the tileStart offset
1759: tileStart += dataWidth * unitsPerPixel * curh * sign;
1760:
1761: // move to the next set of tiles in y direction
1762: y = 0;
1763:
1764: // determine the height of copy region for the next set
1765: // of tiles
1766: tmph -= curh;
1767: if (tmph < tileh) {
1768: curh = tmph;
1769: } else {
1770: curh = tileh;
1771: }
1772: }
1773: }
1774: break;
1775:
1776: default:
1777: assert false;
1778: }
1779:
1780: if ((imageData == data) && (imageDataPowerOfTwo != null)) {
1781: updateImageDataPowerOfTwo(depthIndex);
1782: }
1783: }
1784:
1785: void evaluateExtensions(Canvas3D canvas) {
1786: // Issue 366: need to synchronize since it could be called concurrently
1787: // from multiple renderers (and maybe the renderer(s) and renderbin)
1788: synchronized (evaluateExtLock) {
1789: // For performance reason the ordering of the following 2 statements is intentional.
1790: // So that we only need to do format conversion for imageData only
1791: evaluateExtABGR(canvas.extensionsSupported);
1792: evaluateExtNonPowerOfTwo(canvas.textureExtendedFeatures);
1793: }
1794:
1795: }
1796:
1797: void evaluateExtABGR(int ext) {
1798:
1799: // If abgrSupported is false, a copy has been created so
1800: // we don't have to check again.
1801: if (!abgrSupported) {
1802: return;
1803: }
1804:
1805: if (getImageFormatType() != ImageFormatType.TYPE_BYTE_ABGR) {
1806: return;
1807: }
1808:
1809: if ((ext & Canvas3D.EXT_ABGR) != 0) {
1810: return;
1811: }
1812:
1813: // ABGR is unsupported, set flag to false.
1814: abgrSupported = false;
1815: convertImageDataFromABGRToRGBA();
1816:
1817: }
1818:
1819: private int getClosestPowerOf2(int value) {
1820:
1821: if (value < 1)
1822: return value;
1823:
1824: int powerValue = 1;
1825: for (;;) {
1826: powerValue *= 2;
1827: if (value < powerValue) {
1828: // Found max bound of power, determine which is closest
1829: int minBound = powerValue / 2;
1830: if ((powerValue - value) > (value - minBound))
1831: return minBound;
1832: else
1833: return powerValue;
1834: }
1835: }
1836: }
1837:
1838: private int getCeilPowerOf2(int value) {
1839:
1840: if (value < 1)
1841: return value;
1842:
1843: int powerValue = 1;
1844: for (;;) {
1845: powerValue *= 2;
1846: if (value <= powerValue) {
1847: // Found max bound of power
1848: return powerValue;
1849: }
1850: }
1851: }
1852:
1853: void evaluateExtNonPowerOfTwo(int ext) {
1854: // Only need to enforce for Raster or Background.
1855: if (!enforceNonPowerOfTwoSupport) {
1856: return;
1857: }
1858:
1859: // If npotSupported is false, a copy power of two image has been created
1860: // so we don't have to check again.
1861: if (!npotSupported) {
1862: return;
1863: }
1864:
1865: if (imageData == null && !isByReference()) {
1866: return;
1867: }
1868:
1869: if ((ext & Canvas3D.TEXTURE_NON_POWER_OF_TWO) != 0) {
1870: return;
1871: }
1872:
1873: // NPOT is unsupported, set flag to false.
1874: npotSupported = false;
1875:
1876: int npotWidth;
1877: int npotHeight;
1878: // Always scale up if image size is smaller 512*512.
1879: if ((width * height) < IMAGE_SIZE_512X512) {
1880: npotWidth = getCeilPowerOf2(width);
1881: npotHeight = getCeilPowerOf2(height);
1882: } else {
1883: npotWidth = getClosestPowerOf2(width);
1884: npotHeight = getClosestPowerOf2(height);
1885: }
1886:
1887: // System.err.println("width " + width + " height " + height + " npotWidth " + npotWidth + " npotHeight " + npotHeight);
1888:
1889: float xScale = (float) npotWidth / (float) width;
1890: float yScale = (float) npotHeight / (float) height;
1891:
1892: // scale if scales aren't 1.0
1893: if (!(xScale == 1.0f && yScale == 1.0f)) {
1894:
1895: if (imageData == null) {
1896: // This is a byRef, support format and is a RenderedImage case.
1897: // See ImageComponent2DRetained.set(RenderedImage image)
1898: RenderedImage ri = (RenderedImage) getRefImage(0);
1899:
1900: assert !(ri instanceof BufferedImage);
1901:
1902: // Create a buffered image from renderImage
1903: ColorModel cm = ri.getColorModel();
1904: WritableRaster wRaster = ri.copyData(null);
1905: ri = new BufferedImage(cm, wRaster, cm
1906: .isAlphaPremultiplied(), null);
1907:
1908: // Create image data object with buffer for image. */
1909: imageData = createRenderedImageDataObject(null);
1910: copySupportedImageToImageData(ri, 0, imageData);
1911:
1912: }
1913:
1914: assert imageData != null;
1915:
1916: // Create a supported BufferedImage type.
1917: BufferedImage bi = imageData.createBufferedImage(0);
1918:
1919: int imageType = bi.getType();
1920: BufferedImage scaledImg = new BufferedImage(npotWidth,
1921: npotHeight, imageType);
1922:
1923: AffineTransform at = AffineTransform.getScaleInstance(
1924: xScale, yScale);
1925:
1926: powerOfTwoATOp = new AffineTransformOp(at,
1927: AffineTransformOp.TYPE_BILINEAR);
1928:
1929: powerOfTwoATOp.filter(bi, scaledImg);
1930:
1931: // System.err.println("bi " + bi.getColorModel());
1932: // System.err.println("scaledImg " + scaledImg.getColorModel());
1933:
1934: imageDataPowerOfTwo = createRenderedImageDataObject(null,
1935: npotWidth, npotHeight);
1936: // Since bi is created from imageData, it's imageType is supported.
1937: copySupportedImageToImageData(scaledImg, 0,
1938: imageDataPowerOfTwo);
1939:
1940: } else {
1941: imageDataPowerOfTwo = null;
1942: }
1943: }
1944:
1945: void convertImageDataFromABGRToRGBA() {
1946:
1947: // Unsupported format on HW, switch to slow copy.
1948: imageFormatType = ImageFormatType.TYPE_BYTE_RGBA;
1949: imageTypeIsSupported = false;
1950:
1951: // Only need to convert imageData
1952: imageData.convertFromABGRToRGBA();
1953:
1954: }
1955:
1956: /**
1957: * Copy supported ImageType from ImageData to the user defined bufferedImage
1958: */
1959: void copyToRefImage(int depth) {
1960: int h;
1961: int rowBegin, // src begin row index
1962: srcBegin, // src begin offset
1963: dstBegin; // dst begin offset
1964:
1965: // refImage has to be a BufferedImage for off screen and read raster
1966: assert refImage[depth] != null;
1967: assert (refImage[depth] instanceof BufferedImage);
1968:
1969: BufferedImage bi = (BufferedImage) refImage[depth];
1970: int dstUnitsPerRow = width * unitsPerPixel; // bytes per row in dst image
1971: rowBegin = 0;
1972:
1973: if (yUp) {
1974: dstBegin = (depth * width * height) * unitsPerPixel;
1975: } else {
1976: dstBegin = (depth * width * height + (height - 1) * width)
1977: * unitsPerPixel;
1978: dstUnitsPerRow = -1 * dstUnitsPerRow;
1979: }
1980:
1981: int scanline = width * unitsPerPixel;
1982: srcBegin = (rowBegin * width) * unitsPerPixel;
1983:
1984: switch (imageData.getType()) {
1985: case TYPE_BYTE_ARRAY:
1986: byte[] dstByteBuffer = ((DataBufferByte) bi.getRaster()
1987: .getDataBuffer()).getData();
1988: byte[] srcByteBuffer = imageData.getAsByteArray();
1989: for (h = 0; h < height; h++) {
1990: System.arraycopy(srcByteBuffer, srcBegin,
1991: dstByteBuffer, dstBegin, scanline);
1992: dstBegin += dstUnitsPerRow;
1993: srcBegin += scanline;
1994: }
1995: break;
1996:
1997: case TYPE_INT_ARRAY:
1998: int[] dstIntBuffer = ((DataBufferInt) bi.getRaster()
1999: .getDataBuffer()).getData();
2000: int[] srcIntBuffer = imageData.getAsIntArray();
2001: for (h = 0; h < height; h++) {
2002: System.arraycopy(srcIntBuffer, srcBegin, dstIntBuffer,
2003: dstBegin, scanline);
2004: dstBegin += dstUnitsPerRow;
2005: srcBegin += scanline;
2006: }
2007: break;
2008: default:
2009: assert false;
2010: }
2011:
2012: }
2013:
2014: /**
2015: * Copy image to the user defined bufferedImage ( 3 or 4 components only )
2016: */
2017: void copyToRefImageWithFormatConversion(int depth) {
2018: int w, h, i, j;
2019: int dstBegin, dstInc, dstIndex, dstIndexInc;
2020: // refImage has to be a BufferedImage for off screen and read raster
2021: assert refImage[depth] != null;
2022: assert (refImage[depth] instanceof BufferedImage);
2023:
2024: BufferedImage bi = (BufferedImage) refImage[depth];
2025: int biType = bi.getType();
2026: byte[] buf = imageData.getAsByteArray();
2027:
2028: // convert from Ydown to Yup for texture
2029: if (!yUp) {
2030: dstInc = -1 * width;
2031: dstBegin = (height - 1) * width;
2032: dstIndex = height - 1;
2033: dstIndexInc = -1;
2034: } else {
2035: dstInc = width;
2036: dstBegin = 0;
2037: dstIndex = 0;
2038: dstIndexInc = 1;
2039: }
2040:
2041: switch (biType) {
2042: case BufferedImage.TYPE_INT_ARGB:
2043: int[] intData = ((DataBufferInt) bi.getRaster()
2044: .getDataBuffer()).getData();
2045: // Multiply by 4 to get the byte incr and start point
2046: j = 0;
2047: switch (imageFormatType) {
2048: case TYPE_BYTE_RGBA:
2049: for (h = 0; h < height; h++, dstBegin += dstInc) {
2050: i = dstBegin;
2051: for (w = 0; w < width; w++, j += 4, i++) {
2052: intData[i] = (((buf[j + 3] & 0xff) << 24) | // a
2053: ((buf[j] & 0xff) << 16) | // r
2054: ((buf[j + 1] & 0xff) << 8) | // g
2055: (buf[j + 2] & 0xff)); // b
2056: }
2057: }
2058: break;
2059: case TYPE_BYTE_RGB:
2060: for (h = 0; h < height; h++, dstBegin += dstInc) {
2061: i = dstBegin;
2062: for (w = 0; w < width; w++, j += 3, i++) {
2063: intData[i] = (0xff000000 | // a
2064: ((buf[j] & 0xff) << 16) | // r
2065: ((buf[j + 1] & 0xff) << 8) | // g
2066: (buf[j + 2] & 0xff)); // b
2067: }
2068: }
2069: break;
2070: default:
2071: assert false;
2072: }
2073: break;
2074:
2075: case BufferedImage.TYPE_INT_RGB:
2076: intData = ((DataBufferInt) bi.getRaster().getDataBuffer())
2077: .getData();
2078: // Multiply by 4 to get the byte incr and start point
2079: j = 0;
2080: for (h = 0; h < height; h++, dstBegin += dstInc) {
2081: i = dstBegin;
2082: for (w = 0; w < width; w++, j += 4, i++) {
2083: intData[i] = (0xff000000 | // a
2084: ((buf[j] & 0xff) << 16) | // r
2085: ((buf[j + 1] & 0xff) << 8) | // g
2086: (buf[j + 2] & 0xff)); // b
2087: }
2088: }
2089: break;
2090:
2091: case BufferedImage.TYPE_4BYTE_ABGR:
2092: byte[] byteData = ((DataBufferByte) bi.getRaster()
2093: .getDataBuffer()).getData();
2094: // Multiply by 4 to get the byte incr and start point
2095: j = 0;
2096:
2097: //Issue 381: dstBegin contains pixel count, but we are looping over byte count. In case of YDown, it contains a count that is decremented and if we do not multiply, we have an AIOOB thrown at 25% of the copy.
2098: dstBegin <<= 2;
2099:
2100: switch (imageFormatType) {
2101: case TYPE_BYTE_RGBA:
2102: for (h = 0; h < height; h++, dstBegin += (dstInc << 2)) {
2103: i = dstBegin;
2104: for (w = 0; w < width; w++, j += 4) {
2105: byteData[i++] = buf[j + 3]; // a
2106: byteData[i++] = buf[j + 2]; // b
2107: byteData[i++] = buf[j + 1];// g
2108: byteData[i++] = buf[j]; // r
2109: }
2110: }
2111: break;
2112: case TYPE_BYTE_RGB:
2113: for (h = 0; h < height; h++, dstBegin += (dstInc << 2)) {
2114: i = dstBegin;
2115: for (w = 0; w < width; w++, j += 3) {
2116: byteData[i++] = (byte) 0xff; // a
2117: byteData[i++] = buf[j + 2]; // b
2118: byteData[i++] = buf[j + 1];// g
2119: byteData[i++] = buf[j]; // r
2120: }
2121: }
2122: break;
2123: default:
2124: assert false;
2125: }
2126: break;
2127:
2128: case BufferedImage.TYPE_INT_BGR:
2129: intData = ((DataBufferInt) bi.getRaster().getDataBuffer())
2130: .getData();
2131: // Multiply by 4 to get the byte incr and start point
2132: j = 0;
2133:
2134: for (h = 0; h < height; h++, dstBegin += dstInc) {
2135: i = dstBegin;
2136: for (w = 0; w < width; w++, j += 4, i++) {
2137: intData[i] = (0xff000000 | // a
2138: ((buf[j] & 0xff)) | // r
2139: ((buf[j + 1] & 0xff) << 8) | // g
2140: (buf[j + 2] & 0xff) << 16); // b
2141: }
2142: }
2143: break;
2144: default:
2145: assert false;
2146: }
2147:
2148: }
2149:
2150: // Add a user to the userList
2151: synchronized void addUser(NodeComponentRetained node) {
2152: userList.add(node);
2153: }
2154:
2155: // Add a user to the userList
2156: synchronized void removeUser(NodeComponentRetained node) {
2157: int i = userList.indexOf(node);
2158: if (i >= 0) {
2159: userList.remove(i);
2160: }
2161: }
2162:
2163: /*
2164: *
2165: * @exception IllegalSharingException if this image is
2166: * being used by a Canvas3D as an off-screen buffer.
2167: */
2168: void setLive(boolean inBackgroundGroup, int refCount) {
2169: // Do illegalSharing check.
2170: if (getUsedByOffScreen()) {
2171: throw new IllegalSharingException(J3dI18N
2172: .getString("ImageComponent3"));
2173: }
2174: super .setLive(inBackgroundGroup, refCount);
2175: }
2176:
2177: /**
2178: * ImageComponent object doesn't really have mirror object.
2179: * But it's using the updateMirrorObject interface to propagate
2180: * the changes to the users
2181: */
2182: synchronized void updateMirrorObject(int component, Object value) {
2183:
2184: //System.err.println("ImageComponent.updateMirrorObject");
2185:
2186: Object user;
2187:
2188: if (((component & IMAGE_CHANGED) != 0)
2189: || ((component & SUBIMAGE_CHANGED) != 0)) {
2190: synchronized (userList) {
2191: for (int i = userList.size() - 1; i >= 0; i--) {
2192: user = userList.get(i);
2193: if (user != null) {
2194: if (user instanceof TextureRetained) {
2195: ((TextureRetained) user)
2196: .notifyImageComponentImageChanged(
2197: this ,
2198: (ImageComponentUpdateInfo) value);
2199: } else if (user instanceof RasterRetained) {
2200: ((RasterRetained) user)
2201: .notifyImageComponentImageChanged(
2202: this ,
2203: (ImageComponentUpdateInfo) value);
2204: } else if (user instanceof BackgroundRetained) {
2205: ((BackgroundRetained) user)
2206: .notifyImageComponentImageChanged(
2207: this ,
2208: (ImageComponentUpdateInfo) value);
2209: }
2210: }
2211: }
2212: }
2213: }
2214: }
2215:
2216: final void sendMessage(int attrMask, Object attr) {
2217:
2218: J3dMessage createMessage = new J3dMessage();
2219: createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES
2220: | J3dThread.UPDATE_RENDER;
2221: createMessage.type = J3dMessage.IMAGE_COMPONENT_CHANGED;
2222: createMessage.universe = null;
2223: createMessage.args[0] = this ;
2224: createMessage.args[1] = new Integer(attrMask);
2225: createMessage.args[2] = attr;
2226: createMessage.args[3] = new Integer(changedFrequent);
2227: VirtualUniverse.mc.processMessage(createMessage);
2228: }
2229:
2230: void handleFrequencyChange(int bit) {
2231: if (bit == ImageComponent.ALLOW_IMAGE_WRITE) {
2232: setFrequencyChangeMask(ImageComponent.ALLOW_IMAGE_WRITE,
2233: 0x1);
2234: }
2235: }
2236:
2237: static Object getDataElementBuffer(java.awt.image.Raster ras) {
2238: int nc = ras.getNumDataElements();
2239:
2240: switch (ras.getTransferType()) {
2241: case DataBuffer.TYPE_INT:
2242: return new int[nc];
2243: case DataBuffer.TYPE_BYTE:
2244: return new byte[nc];
2245: case DataBuffer.TYPE_USHORT:
2246: case DataBuffer.TYPE_SHORT:
2247: return new short[nc];
2248: case DataBuffer.TYPE_FLOAT:
2249: return new float[nc];
2250: case DataBuffer.TYPE_DOUBLE:
2251: return new double[nc];
2252: }
2253: // Should not happen
2254: return null;
2255: }
2256:
2257: /**
2258: * Wrapper class for image data.
2259: * Currently supports byte array and int array.
2260: * Will eventually support NIO ByteBuffer and IntBuffer.
2261: */
2262: class ImageData {
2263:
2264: private Object data = null;
2265: private ImageDataType imageDataType = ImageDataType.TYPE_NULL;
2266: private int length = 0;
2267: private boolean dataIsByRef = false;
2268: private int dataWidth, dataHeight;
2269:
2270: /**
2271: * Constructs a new ImageData buffer of the specified type with the
2272: * specified length.
2273: */
2274: ImageData(ImageDataType imageDataType, int length,
2275: int dataWidth, int dataHeight) {
2276: this .imageDataType = imageDataType;
2277: this .length = length;
2278: this .dataWidth = dataWidth;
2279: this .dataHeight = dataHeight;
2280: this .dataIsByRef = false;
2281:
2282: switch (imageDataType) {
2283: case TYPE_BYTE_ARRAY:
2284: data = new byte[length];
2285: break;
2286: case TYPE_INT_ARRAY:
2287: data = new int[length];
2288: break;
2289: case TYPE_BYTE_BUFFER:
2290: ByteOrder order = ByteOrder.nativeOrder();
2291: data = ByteBuffer.allocateDirect(length).order(order);
2292: break;
2293: case TYPE_INT_BUFFER:
2294: default:
2295: throw new AssertionError();
2296: }
2297: }
2298:
2299: /**
2300: * Constructs a new ImageData buffer of the specified type with the
2301: * specified length and the specified byRefImage as data.
2302: */
2303: ImageData(ImageDataType imageDataType, int length,
2304: int dataWidth, int dataHeight, Object byRefImage) {
2305: BufferedImage bi;
2306: NioImageBuffer nio;
2307:
2308: this .imageDataType = imageDataType;
2309: this .length = length;
2310: this .dataWidth = dataWidth;
2311: this .dataHeight = dataHeight;
2312: this .dataIsByRef = true;
2313:
2314: switch (imageDataType) {
2315: case TYPE_BYTE_ARRAY:
2316: bi = (BufferedImage) byRefImage;
2317: data = ((DataBufferByte) bi.getRaster().getDataBuffer())
2318: .getData();
2319: break;
2320: case TYPE_INT_ARRAY:
2321: bi = (BufferedImage) byRefImage;
2322: data = ((DataBufferInt) bi.getRaster().getDataBuffer())
2323: .getData();
2324: break;
2325: case TYPE_BYTE_BUFFER:
2326: case TYPE_INT_BUFFER:
2327: nio = (NioImageBuffer) byRefImage;
2328: data = nio.getDataBuffer();
2329: break;
2330: default:
2331: throw new AssertionError();
2332: }
2333: }
2334:
2335: /**
2336: * Constructs a new ImageData buffer from the specified
2337: * object. This object stores a reference to the input image data.
2338: */
2339: ImageData(Object data, boolean isByRef) {
2340: this .data = data;
2341: dataIsByRef = isByRef;
2342: dataWidth = ((ImageData) data).dataWidth;
2343: dataHeight = ((ImageData) data).dataHeight;
2344:
2345: if (data == null) {
2346: imageDataType = ImageDataType.TYPE_NULL;
2347: length = 0;
2348: } else if (data instanceof byte[]) {
2349: imageDataType = ImageDataType.TYPE_BYTE_ARRAY;
2350: length = ((byte[]) data).length;
2351: } else if (data instanceof int[]) {
2352: imageDataType = ImageDataType.TYPE_INT_ARRAY;
2353: length = ((int[]) data).length;
2354: } else if (data instanceof ByteBuffer) {
2355: imageDataType = ImageDataType.TYPE_BYTE_BUFFER;
2356: length = ((ByteBuffer) data).limit();
2357: } else if (data instanceof IntBuffer) {
2358: imageDataType = ImageDataType.TYPE_INT_BUFFER;
2359: length = ((IntBuffer) data).limit();
2360: } else {
2361: assert false;
2362: }
2363: }
2364:
2365: /**
2366: * Returns the type of this DataBuffer.
2367: */
2368: ImageDataType getType() {
2369: return imageDataType;
2370: }
2371:
2372: /**
2373: * Returns the number of elements in this DataBuffer.
2374: */
2375: int length() {
2376: return length;
2377: }
2378:
2379: /**
2380: * Returns the width of this DataBuffer.
2381: */
2382: int getWidth() {
2383: return dataWidth;
2384: }
2385:
2386: /**
2387: * Returns the height of this DataBuffer.
2388: */
2389: int getHeight() {
2390: return dataHeight;
2391: }
2392:
2393: /**
2394: * Returns this DataBuffer as an Object.
2395: */
2396: Object get() {
2397: return data;
2398: }
2399:
2400: /**
2401: * Returns is this data is byRef. No internal data is made.
2402: */
2403: boolean isDataByRef() {
2404: return dataIsByRef;
2405: }
2406:
2407: /**
2408: * Returns this DataBuffer as a byte array.
2409: */
2410: byte[] getAsByteArray() {
2411: return (byte[]) data;
2412: }
2413:
2414: /**
2415: * Returns this DataBuffer as an int array.
2416: */
2417: int[] getAsIntArray() {
2418: return (int[]) data;
2419: }
2420:
2421: /**
2422: * Returns this DataBuffer as an nio ByteBuffer.
2423: */
2424: ByteBuffer getAsByteBuffer() {
2425: return (ByteBuffer) data;
2426: }
2427:
2428: /**
2429: * Returns this DataBuffer as an nio IntBuffer.
2430: */
2431: IntBuffer getAsIntBuffer() {
2432: return (IntBuffer) data;
2433: }
2434:
2435: // Handle TYPE_BYTE_LA only
2436: void copyByLineAndExpand(BufferedImage bi, int depthIndex) {
2437: int h;
2438: int srcBegin, // src begin offset
2439: dstBegin; // dst begin offset
2440:
2441: assert (imageData.getType() == ImageDataType.TYPE_BYTE_ARRAY);
2442: assert (imageFormatType == ImageFormatType.TYPE_BYTE_LA);
2443:
2444: int unitsPerRow = width * unitsPerPixel; // bytes per row
2445: int scanline = unitsPerRow;
2446: if (yUp) {
2447: srcBegin = (depthIndex * width * height)
2448: * unitsPerPixel;
2449: } else {
2450: srcBegin = (depthIndex * width * height + (height - 1)
2451: * width)
2452: * unitsPerPixel;
2453: unitsPerRow = -1 * unitsPerRow;
2454: }
2455:
2456: dstBegin = 0;
2457: // ABGR is 4 bytes per pixel
2458: int dstUnitsPerRow = width * 4;
2459:
2460: byte[] dstByteBuffer = ((DataBufferByte) bi.getRaster()
2461: .getDataBuffer()).getData();
2462: byte[] srcByteBuffer = imageData.getAsByteArray();
2463: for (h = 0; h < height; h++) {
2464: for (int v = 0, w = 0; w < scanline; w += unitsPerPixel, v += 4) {
2465: dstByteBuffer[dstBegin + v] = srcByteBuffer[srcBegin
2466: + w + 1]; // Alpha
2467: dstByteBuffer[dstBegin + v + 1] = 0;
2468: dstByteBuffer[dstBegin + v + 2] = 0;
2469: dstByteBuffer[dstBegin + v + 3] = srcByteBuffer[srcBegin
2470: + w]; // Red
2471: }
2472:
2473: dstBegin += dstUnitsPerRow;
2474: srcBegin += unitsPerRow;
2475: }
2476:
2477: }
2478:
2479: // Quick line by line copy
2480: void copyByLine(BufferedImage bi, int depthIndex,
2481: boolean swapNeeded) {
2482:
2483: int h;
2484: int srcBegin, // src begin offset
2485: dstBegin; // dst begin offset
2486:
2487: int unitsPerRow = width * unitsPerPixel; // bytes per row
2488: int copyUnits = unitsPerRow;
2489: if (yUp) {
2490: srcBegin = (depthIndex * width * height)
2491: * unitsPerPixel;
2492: } else {
2493: srcBegin = (depthIndex * width * height + (height - 1)
2494: * width)
2495: * unitsPerPixel;
2496: unitsPerRow = -1 * unitsPerRow;
2497: }
2498:
2499: dstBegin = 0;
2500:
2501: switch (imageData.getType()) {
2502: case TYPE_BYTE_ARRAY:
2503: byte[] dstByteBuffer = ((DataBufferByte) bi.getRaster()
2504: .getDataBuffer()).getData();
2505: byte[] srcByteBuffer = imageData.getAsByteArray();
2506: for (h = 0; h < height; h++) {
2507: if (!swapNeeded) {
2508: System.arraycopy(srcByteBuffer, srcBegin,
2509: dstByteBuffer, dstBegin, copyUnits);
2510: } else {
2511: if (imageFormatType == ImageFormatType.TYPE_BYTE_RGB) {
2512: assert (unitsPerPixel == 3);
2513: for (int w = 0; w < copyUnits; w += unitsPerPixel) {
2514: dstByteBuffer[dstBegin + w] = srcByteBuffer[srcBegin
2515: + w + 2];
2516: dstByteBuffer[dstBegin + w + 1] = srcByteBuffer[srcBegin
2517: + w + 1];
2518: dstByteBuffer[dstBegin + w + 2] = srcByteBuffer[srcBegin
2519: + w];
2520: }
2521: } else if (imageFormatType == ImageFormatType.TYPE_BYTE_RGBA) {
2522: assert (unitsPerPixel == 4);
2523: for (int w = 0; w < copyUnits; w += unitsPerPixel) {
2524: dstByteBuffer[dstBegin + w] = srcByteBuffer[srcBegin
2525: + w + 3];
2526: dstByteBuffer[dstBegin + w + 1] = srcByteBuffer[srcBegin
2527: + w + 2];
2528: dstByteBuffer[dstBegin + w + 2] = srcByteBuffer[srcBegin
2529: + w + 1];
2530: dstByteBuffer[dstBegin + w + 3] = srcByteBuffer[srcBegin
2531: + w];
2532: }
2533: } else {
2534: assert false;
2535: }
2536: }
2537: dstBegin += copyUnits;
2538: srcBegin += unitsPerRow;
2539: }
2540: break;
2541:
2542: // INT case doesn't required to handle swapNeeded
2543: case TYPE_INT_ARRAY:
2544: assert (!swapNeeded);
2545: int[] dstIntBuffer = ((DataBufferInt) bi.getRaster()
2546: .getDataBuffer()).getData();
2547: int[] srcIntBuffer = imageData.getAsIntArray();
2548: for (h = 0; h < height; h++) {
2549: System.arraycopy(srcIntBuffer, srcBegin,
2550: dstIntBuffer, dstBegin, copyUnits);
2551: dstBegin += copyUnits;
2552: srcBegin += unitsPerRow;
2553: }
2554: break;
2555: default:
2556: assert false;
2557: }
2558: }
2559:
2560: void copyByBlock(BufferedImage bi, int depthIndex) {
2561: // src begin offset
2562: int srcBegin = depthIndex * width * height * unitsPerPixel;
2563:
2564: switch (imageData.getType()) {
2565: case TYPE_BYTE_ARRAY:
2566: byte[] dstByteBuffer = ((DataBufferByte) bi.getRaster()
2567: .getDataBuffer()).getData();
2568: byte[] srcByteBuffer = imageData.getAsByteArray();
2569: System.arraycopy(srcByteBuffer, srcBegin,
2570: dstByteBuffer, 0,
2571: (height * width * unitsPerPixel));
2572: break;
2573: case TYPE_INT_ARRAY:
2574: int[] dstIntBuffer = ((DataBufferInt) bi.getRaster()
2575: .getDataBuffer()).getData();
2576: int[] srcIntBuffer = imageData.getAsIntArray();
2577: System.arraycopy(srcIntBuffer, srcBegin, dstIntBuffer,
2578: 0, (height * width * unitsPerPixel));
2579: break;
2580: default:
2581: assert false;
2582: }
2583: }
2584:
2585: // Need to check for imageData is null. if it is null return null.
2586: BufferedImage createBufferedImage(int depthIndex) {
2587: if (data != null) {
2588: int bufferType = BufferedImage.TYPE_CUSTOM;
2589: boolean swapNeeded = false;
2590:
2591: switch (imageFormatType) {
2592: case TYPE_BYTE_BGR:
2593: bufferType = BufferedImage.TYPE_3BYTE_BGR;
2594: break;
2595: case TYPE_BYTE_RGB:
2596: bufferType = BufferedImage.TYPE_3BYTE_BGR;
2597: swapNeeded = true;
2598: break;
2599: case TYPE_BYTE_ABGR:
2600: bufferType = BufferedImage.TYPE_4BYTE_ABGR;
2601: break;
2602: case TYPE_BYTE_RGBA:
2603: bufferType = BufferedImage.TYPE_4BYTE_ABGR;
2604: swapNeeded = true;
2605: break;
2606: // This is a special case. Need to handle separately.
2607: case TYPE_BYTE_LA:
2608: bufferType = BufferedImage.TYPE_4BYTE_ABGR;
2609: break;
2610: case TYPE_BYTE_GRAY:
2611: bufferType = BufferedImage.TYPE_BYTE_GRAY;
2612: break;
2613: case TYPE_INT_BGR:
2614: bufferType = BufferedImage.TYPE_INT_BGR;
2615: break;
2616: case TYPE_INT_RGB:
2617: bufferType = BufferedImage.TYPE_INT_RGB;
2618: break;
2619: case TYPE_INT_ARGB:
2620: bufferType = BufferedImage.TYPE_INT_ARGB;
2621: break;
2622: // Unsupported case, so shouldn't be here.
2623: case TYPE_USHORT_GRAY:
2624: bufferType = BufferedImage.TYPE_USHORT_GRAY;
2625: default:
2626: assert false;
2627:
2628: }
2629:
2630: BufferedImage bi = new BufferedImage(width, height,
2631: bufferType);
2632: if ((!swapNeeded)
2633: && (imageFormatType != ImageFormatType.TYPE_BYTE_LA)) {
2634: if (yUp) {
2635: copyByBlock(bi, depthIndex);
2636: } else {
2637: copyByLine(bi, depthIndex, false);
2638: }
2639: } else if (swapNeeded) {
2640: copyByLine(bi, depthIndex, swapNeeded);
2641: } else if (imageFormatType == ImageFormatType.TYPE_BYTE_LA) {
2642: copyByLineAndExpand(bi, depthIndex);
2643: } else {
2644: assert false;
2645: }
2646:
2647: return bi;
2648:
2649: }
2650: return null;
2651: }
2652:
2653: void convertFromABGRToRGBA() {
2654: int i;
2655:
2656: if (imageDataType == ImageComponentRetained.ImageDataType.TYPE_BYTE_ARRAY) {
2657: // Note : Highly inefficient for depth > 0 case.
2658: // This method doesn't take into account of depth, it is assuming that
2659: // depth == 0, which is true for ImageComponent2D.
2660: byte[] srcBuffer, dstBuffer;
2661: srcBuffer = getAsByteArray();
2662:
2663: if (dataIsByRef) {
2664: dstBuffer = new byte[length];
2665: // Do copy and swap.
2666: for (i = 0; i < length; i += 4) {
2667: dstBuffer[i] = srcBuffer[i + 3];
2668: dstBuffer[i + 1] = srcBuffer[i + 2];
2669: dstBuffer[i + 2] = srcBuffer[i + 1];
2670: dstBuffer[i + 3] = srcBuffer[i];
2671: }
2672: data = dstBuffer;
2673: dataIsByRef = false;
2674:
2675: } else {
2676: byte a, b;
2677: // Do swap in place.
2678: for (i = 0; i < length; i += 4) {
2679: a = srcBuffer[i];
2680: b = srcBuffer[i + 1];
2681: srcBuffer[i] = srcBuffer[i + 3];
2682: srcBuffer[i + 1] = srcBuffer[i + 2];
2683: srcBuffer[i + 2] = b;
2684: srcBuffer[i + 3] = a;
2685: }
2686: }
2687: } else if (imageDataType == ImageComponentRetained.ImageDataType.TYPE_BYTE_BUFFER) {
2688:
2689: assert dataIsByRef;
2690: ByteBuffer srcBuffer, dstBuffer;
2691:
2692: srcBuffer = getAsByteBuffer();
2693: srcBuffer.rewind();
2694:
2695: ByteOrder order = ByteOrder.nativeOrder();
2696: dstBuffer = ByteBuffer.allocateDirect(length).order(
2697: order);
2698: dstBuffer.rewind();
2699:
2700: // Do copy and swap.
2701: for (i = 0; i < length; i += 4) {
2702: dstBuffer.put(i, srcBuffer.get(i + 3));
2703: dstBuffer.put(i + 1, srcBuffer.get(i + 2));
2704: dstBuffer.put(i + 2, srcBuffer.get(i + 1));
2705: dstBuffer.put(i + 3, srcBuffer.get(i));
2706: }
2707:
2708: dataIsByRef = false;
2709:
2710: }
2711: }
2712: }
2713: }
|