/*
* Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package javax.media.j3d;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
/**
* The NioImageBuffer class is a container for an image whose DataBuffer
* is specified via a java.nio.Buffer. An an NioImageBuffer can be wrapped by
* an ImageComponent and used for texture mapping, or for rendering Raster
* objects or background images. An NioImageBuffer must not be used as the
* buffer of an off-screen Canvas3D, or for reading back a raster image.
*
* @see ImageComponent2D
* @see ImageComponent3D
*
* @since Java 3D 1.5
*/
public class NioImageBuffer {
/**
* Used to specify the type of the image.
*/
public enum ImageType {
/**
* Represents an image with 8-bit RGB color components,
* corresponding to a Windows-style BGR color model, with the
* colors Blue, Green, and Red stored in 3 consecutive
* bytes for each pixel.
* The data buffer must be a ByteBuffer when using this imageType.
*/
TYPE_3BYTE_BGR,
/**
* Represents an image with 8-bit RGB color components with
* Red, Green, and Blue, stored in 3 consecutive
* bytes for each pixel.
* The data buffer must be a ByteBuffer when using this imageType.
*/
TYPE_3BYTE_RGB,
/**
* Represents an image with 8-bit RGBA color components with
* Alpha, Blue, Green, and Red stored in 4 consecutive
* bytes for each pixel.
* The data buffer must be a ByteBuffer when using this imageType.
*/
TYPE_4BYTE_ABGR,
/**
* Represents an image with 8-bit RGBA color components with
* Red, Green, Blue, and Alpha stored in 4 consecutive
* bytes for each pixel.
* The data buffer must be a ByteBuffer when using this imageType.
*/
TYPE_4BYTE_RGBA,
/**
* Represents a unsigned byte grayscale image, non-indexed.
* The data buffer must be a ByteBuffer when using this imageType.
*/
TYPE_BYTE_GRAY,
/**
* Represents an image with 8-bit RGBA color components packed
* into integer pixels.
* The data buffer must be an IntBuffer when using this imageType.
*/
TYPE_INT_ARGB,
/**
* Represents an image with 8-bit RGB color components,
* corresponding to a Windows- or Solaris- style BGR color model,
* with the colors Blue, Green, and Red packed into integer
* pixels.
* The data buffer must be an IntBuffer when using this imageType.
*/
TYPE_INT_BGR,
/**
* Represents an image with 8-bit RGB color components packed into
* integer pixels.
* The data buffer must be an IntBuffer when using this imageType.
*/
TYPE_INT_RGB,
}
/**
* Enum for type of buffer
*/
enum BufferType {
BYTE_BUFFER,
INT_BUFFER,
}
// Width and height of image
int width;
int height;
// TYpe of image
ImageType imageType;
// Cached buffer
Buffer buffer;
// Type of NIO Buffer: byte or int
BufferType bufferType;
// Number of bytes allocated per pixel
int bytesPerPixel;
// Number of byte or int elements per pixel
int elementsPerPixel;
/**
* Constructs an NIO image buffer of the specified size and type.
* A direct NIO buffer of the correct type (ByteBuffer or IntBuffer)
* and size to match the input parameters
* is allocated.
*
* @param width width of the image
* @param height height of the image
* @param imageType type of the image.
*
* @exception IllegalArgumentException if width < 1 or height < 1
* @exception NullPointerException if imageType is null
*/
public NioImageBuffer(int width, int height, ImageType imageType) {
processParams(width, height, imageType);
ByteBuffer tmpBuffer = ByteBuffer.allocateDirect(width * height * bytesPerPixel);
switch (bufferType) {
case BYTE_BUFFER:
buffer = tmpBuffer;
break;
case INT_BUFFER:
buffer = tmpBuffer.order(ByteOrder.nativeOrder()).asIntBuffer();
break;
default:
// We should never get here
throw new AssertionError("missing case statement");
}
}
/**
* Constructs an NIO image buffer of the specified size and type, using
* the specified dataBuffer.
* The the byte order of the specified dataBuffer must match the native
* byte order of the underlying platform.
* For best performance, the NIO buffer should be a direct buffer.
*
* @param width width of the image
* @param height height of the image
* @param imageType type of the image.
* @param dataBuffer an NIO buffer of the correct type (ByteBuffer or
* IntBuffer) to match the specified imageType.
* This constructor will create a new view of
* the buffer, and will call rewind
on that view,
* such that elements 0 through dataBuffer.limit()-1
* will be available internally. The number of elements in
* the buffer must be exactly width*height*numElementsPerPixel
,
* where numElementsPerPixel
is
* 3 for TYPE_3BYTE_BGR and TYPE_3BYTE_RGB,
* 4 for TYPE_4BYTE_ABGR and TYPE_4BYTE_RGBA,
* and 1 for all other types.
*
* @exception IllegalArgumentException if width < 1 or height < 1
* @exception NullPointerException if imageType or dataBuffer is null
* @exception IllegalArgumentException if the type of the dataBuffer does
* not match the imageType
* @exception IllegalArgumentException if dataBuffer.limit() !=
* width*height*numElementsPerPixel
* @exception IllegalArgumentException if the byte order of the specified
* dataBuffer does not match the native byte order of the underlying
* platform.
*/
public NioImageBuffer(int width, int height, ImageType imageType,
Buffer dataBuffer) {
processParams(width, height, imageType);
setDataBuffer(dataBuffer);
}
/**
* Gets the width of this data buffer.
*
* @return the width of this data buffer.
*/
public int getWidth() {
return width;
}
/**
* Gets the height of this data buffer.
*
* @return the width of this data buffer.
*/
public int getHeight() {
return height;
}
/**
* Gets the image type of this data buffer.
*
* @return the image type of this data buffer.
*/
public ImageType getImageType() {
return imageType;
}
/**
* Sets the data buffer to the specified input data buffer.
* The the byte order of the specified dataBuffer must match the native
* byte order of the underlying platform.
* For best performance, the NIO buffer should be a direct buffer.
*
* @param dataBuffer an NIO buffer of the correct type (ByteBuffer or
* IntBuffer) to match the imageType of this
* NioImageBuffer. This method will create a new view of
* the buffer, and will call rewind
on that view,
* such that elements 0 through dataBuffer.limit()-1
* will be available internally. The number of elements in
* the buffer must be exactly width*height*numElementsPerPixel
,
* where numElementsPerPixel
is
* 3 for TYPE_3BYTE_BGR and TYPE_3BYTE_RGB,
* 4 for TYPE_4BYTE_ABGR and TYPE_4BYTE_RGBA,
* and 1 for all other types.
*
* @exception NullPointerException if dataBuffer is null
* @exception IllegalArgumentException if the type of the dataBuffer does
* not match the imageType
* @exception IllegalArgumentException if dataBuffer.limit() !=
* width*height*numElementsPerPixel
* @exception IllegalArgumentException if the byte order of the specified
* dataBuffer does not match the native byte order of the underlying
* platform.
*/
public void setDataBuffer(Buffer dataBuffer) {
if (dataBuffer == null) {
throw new NullPointerException();
}
if (dataBuffer.limit() != width*height*elementsPerPixel) {
throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer3"));
}
switch (bufferType) {
case BYTE_BUFFER:
if (!(dataBuffer instanceof ByteBuffer)) {
throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer4"));
}
buffer = ((ByteBuffer)dataBuffer).duplicate().rewind();
break;
case INT_BUFFER:
if (!(dataBuffer instanceof IntBuffer)) {
throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer4"));
}
if (((IntBuffer)dataBuffer).order() != ByteOrder.nativeOrder()) {
throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer5"));
}
buffer = ((IntBuffer)dataBuffer).duplicate().rewind();
break;
default:
// We should never get here
throw new AssertionError("missing case statement");
}
}
/**
* Gets the data buffer to the specified input data buffer.
*
* @return a view of the current data buffer for this NIO image buffer.
* This view will be rewound such that elements 0
* through dataBuffer.limit()-1
are available.
*/
public Buffer getDataBuffer() {
Buffer tmpBuffer = null;
switch (bufferType) {
case BYTE_BUFFER:
tmpBuffer = ((ByteBuffer)buffer).duplicate();
break;
case INT_BUFFER:
tmpBuffer = ((IntBuffer)buffer).duplicate();
break;
default:
// We should never get here
throw new AssertionError("missing case statement");
}
return tmpBuffer.rewind();
}
// Sanity check the input parameters, calculate the buffer type and
// the number of bytes per pixel
private void processParams(int width, int height, ImageType imageType) {
if (width < 1) {
throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer0"));
}
if (height < 1) {
throw new IllegalArgumentException(J3dI18N.getString("NioImageBuffer1"));
}
switch (imageType) {
case TYPE_3BYTE_BGR:
bufferType = BufferType.BYTE_BUFFER;
bytesPerPixel = 3;
elementsPerPixel = 3;
break;
case TYPE_3BYTE_RGB:
bufferType = BufferType.BYTE_BUFFER;
bytesPerPixel = 3;
elementsPerPixel = 3;
break;
case TYPE_4BYTE_ABGR:
bufferType = BufferType.BYTE_BUFFER;
bytesPerPixel = 4;
elementsPerPixel = 4;
break;
case TYPE_4BYTE_RGBA:
bufferType = BufferType.BYTE_BUFFER;
bytesPerPixel = 4;
elementsPerPixel = 4;
break;
case TYPE_BYTE_GRAY:
bufferType = BufferType.BYTE_BUFFER;
bytesPerPixel = 1;
elementsPerPixel = 1;
break;
case TYPE_INT_ARGB:
case TYPE_INT_BGR:
case TYPE_INT_RGB:
bufferType = BufferType.INT_BUFFER;
bytesPerPixel = 4;
elementsPerPixel = 1;
break;
default:
// We should never get here
throw new AssertionError("missing case statement");
}
this.width = width;
this.height = height;
this.imageType = imageType;
}
}