use of com.jme3.texture.Image.Format in project jmonkeyengine by jMonkeyEngine.
the class EnvMapUtils method makeCubeMap.
/**
* Creates a cube map from 6 images
*
* @param leftImg the west side image, also called negative x (negX) or left
* image
* @param rightImg the east side image, also called positive x (posX) or
* right image
* @param downImg the bottom side image, also called negative y (negY) or
* down image
* @param upImg the up side image, also called positive y (posY) or up image
* @param backImg the south side image, also called positive z (posZ) or
* back image
* @param frontImg the north side image, also called negative z (negZ) or
* front image
* @param format the format of the image
* @return a cube map
*/
public static TextureCubeMap makeCubeMap(Image rightImg, Image leftImg, Image upImg, Image downImg, Image backImg, Image frontImg, Image.Format format) {
Image cubeImage = new Image(format, leftImg.getWidth(), leftImg.getHeight(), null, ColorSpace.Linear);
cubeImage.addData(rightImg.getData(0));
cubeImage.addData(leftImg.getData(0));
cubeImage.addData(upImg.getData(0));
cubeImage.addData(downImg.getData(0));
cubeImage.addData(backImg.getData(0));
cubeImage.addData(frontImg.getData(0));
if (leftImg.getEfficentData() != null) {
// also consilidate efficient data
ArrayList<Object> efficientData = new ArrayList<Object>(6);
efficientData.add(rightImg.getEfficentData());
efficientData.add(leftImg.getEfficentData());
efficientData.add(upImg.getEfficentData());
efficientData.add(downImg.getEfficentData());
efficientData.add(backImg.getEfficentData());
efficientData.add(frontImg.getEfficentData());
cubeImage.setEfficentData(efficientData);
}
TextureCubeMap cubeMap = new TextureCubeMap(cubeImage);
cubeMap.setAnisotropicFilter(0);
cubeMap.setMagFilter(Texture.MagFilter.Bilinear);
cubeMap.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
cubeMap.setWrap(Texture.WrapMode.EdgeClamp);
return cubeMap;
}
use of com.jme3.texture.Image.Format in project jmonkeyengine by jMonkeyEngine.
the class PrefilteredEnvMapFaceGenerator method generatePrefilteredEnvMap.
/**
* Generates the prefiltered env map (used for image based specular
* lighting) With the GGX/Shlick brdf
* {@link EnvMapUtils#getSphericalHarmonicsCoefficents(com.jme3.texture.TextureCubeMap)}
* Note that the output cube map is in RGBA8 format.
*
* @param sourceEnvMap
* @param targetMapSize the size of the irradiance map to generate
* @param store
* @param fixSeamsMethod the method to fix seams
* @return The irradiance cube map for the given coefficients
*/
private TextureCubeMap generatePrefilteredEnvMap(TextureCubeMap sourceEnvMap, int targetMapSize, EnvMapUtils.FixSeamsMethod fixSeamsMethod, TextureCubeMap store) {
TextureCubeMap pem = store;
int nbMipMap = (int) (Math.log(targetMapSize) / Math.log(2) - 1);
setEnd(nbMipMap);
CubeMapWrapper sourceWrapper = new CubeMapWrapper(sourceEnvMap);
CubeMapWrapper targetWrapper = new CubeMapWrapper(pem);
Vector3f texelVect = new Vector3f();
Vector3f color = new Vector3f();
ColorRGBA outColor = new ColorRGBA();
for (int mipLevel = 0; mipLevel < nbMipMap; mipLevel++) {
float roughness = getRoughnessFromMip(mipLevel, nbMipMap);
int nbSamples = getSampleFromMip(mipLevel, nbMipMap);
int targetMipMapSize = (int) pow(2, nbMipMap + 1 - mipLevel);
for (int y = 0; y < targetMipMapSize; y++) {
for (int x = 0; x < targetMipMapSize; x++) {
color.set(0, 0, 0);
getVectorFromCubemapFaceTexCoord(x, y, targetMipMapSize, face, texelVect, EnvMapUtils.FixSeamsMethod.Wrap);
prefilterEnvMapTexel(sourceWrapper, roughness, texelVect, nbSamples, color);
outColor.set(Math.max(color.x, 0.0001f), Math.max(color.y, 0.0001f), Math.max(color.z, 0.0001f), 1);
log.log(Level.FINE, "coords {0},{1}", new Object[] { x, y });
targetWrapper.setPixel(x, y, face, mipLevel, outColor);
}
}
progress();
}
return pem;
}
use of com.jme3.texture.Image.Format in project jmonkeyengine by jMonkeyEngine.
the class Image method write.
public void write(JmeExporter e) throws IOException {
OutputCapsule capsule = e.getCapsule(this);
capsule.write(format, "format", Format.RGBA8);
capsule.write(width, "width", 0);
capsule.write(height, "height", 0);
capsule.write(depth, "depth", 0);
capsule.write(mipMapSizes, "mipMapSizes", null);
capsule.write(multiSamples, "multiSamples", 1);
capsule.writeByteBufferArrayList(data, "data", null);
capsule.write(colorSpace, "colorSpace", null);
}
use of com.jme3.texture.Image.Format in project jmonkeyengine by jMonkeyEngine.
the class HDRLoader method load.
public Image load(InputStream in, boolean flipY) throws IOException {
float gamma = -1f;
float exposure = -1f;
float[] colorcorr = new float[] { -1f, -1f, -1f };
int width = -1, height = -1;
boolean verifiedFormat = false;
while (true) {
String ln = readString(in);
ln = ln.trim();
if (ln.startsWith("#") || ln.equals("")) {
if (ln.equals("#?RADIANCE") || ln.equals("#?RGBE"))
verifiedFormat = true;
// comment or empty statement
continue;
} else if (ln.startsWith("+") || ln.startsWith("-")) {
// + or - mark image resolution and start of data
String[] resData = ln.split("\\s");
if (resData.length != 4) {
throw new IOException("Invalid resolution string in HDR file");
}
if (!resData[0].equals("-Y") || !resData[2].equals("+X")) {
logger.warning("Flipping/Rotating attributes ignored!");
}
//if (resData[0].endsWith("X")){
// first width then height
// width = Integer.parseInt(resData[1]);
// height = Integer.parseInt(resData[3]);
//}else{
width = Integer.parseInt(resData[3]);
height = Integer.parseInt(resData[1]);
break;
} else {
// regular command
int index = ln.indexOf("=");
if (index < 1) {
logger.log(Level.FINE, "Ignored string: {0}", ln);
continue;
}
String var = ln.substring(0, index).trim().toLowerCase();
String value = ln.substring(index + 1).trim().toLowerCase();
if (var.equals("format")) {
if (!value.equals("32-bit_rle_rgbe") && !value.equals("32-bit_rle_xyze")) {
throw new IOException("Unsupported format in HDR picture");
}
} else if (var.equals("exposure")) {
exposure = Float.parseFloat(value);
} else if (var.equals("gamma")) {
gamma = Float.parseFloat(value);
} else {
logger.log(Level.WARNING, "HDR Command ignored: {0}", ln);
}
}
}
assert width != -1 && height != -1;
if (!verifiedFormat)
logger.warning("Unsure if specified image is Radiance HDR");
// some HDR images can get pretty big
System.gc();
// each pixel times size of component times # of components
Format pixelFormat;
if (writeRGBE) {
pixelFormat = Format.RGBA8;
} else {
pixelFormat = Format.RGB16F;
}
dataStore = BufferUtils.createByteBuffer(width * height * pixelFormat.getBitsPerPixel());
int bytesPerPixel = pixelFormat.getBitsPerPixel() / 8;
int scanLineBytes = bytesPerPixel * width;
for (int y = height - 1; y >= 0; y--) {
if (flipY)
dataStore.position(scanLineBytes * y);
decodeScanline(in, width);
}
in.close();
dataStore.rewind();
//HDR files color data is actually stored in linear space.
return new Image(pixelFormat, width, height, dataStore, ColorSpace.Linear);
}
use of com.jme3.texture.Image.Format in project jmonkeyengine by jMonkeyEngine.
the class TGALoader method load.
/**
* <code>loadImage</code> is a manual image loader which is entirely
* independent of AWT. OUT: RGB888 or RGBA8888 Image object
*
*
* @param in
* InputStream of an uncompressed 24b RGB or 32b RGBA TGA
* @param flip
* Flip the image vertically
* @return <code>Image</code> object that contains the
* image, either as a RGB888 or RGBA8888
* @throws java.io.IOException
*/
public static Image load(InputStream in, boolean flip) throws IOException {
boolean flipH = false;
// open a stream to the file
DataInputStream dis = new DataInputStream(new BufferedInputStream(in));
// ---------- Start Reading the TGA header ---------- //
// length of the image id (1 byte)
int idLength = dis.readUnsignedByte();
// Type of color map (if any) included with the image
// 0 - no color map data is included
// 1 - a color map is included
int colorMapType = dis.readUnsignedByte();
// Type of image being read:
int imageType = dis.readUnsignedByte();
// Read Color Map Specification (5 bytes)
// Index of first color map entry (if we want to use it, uncomment and remove extra read.)
// short cMapStart = flipEndian(dis.readShort());
dis.readShort();
// number of entries in the color map
short cMapLength = flipEndian(dis.readShort());
// number of bits per color map entry
int cMapDepth = dis.readUnsignedByte();
// Read Image Specification (10 bytes)
// horizontal coordinate of lower left corner of image. (if we want to use it, uncomment and remove extra read.)
// int xOffset = flipEndian(dis.readShort());
dis.readShort();
// vertical coordinate of lower left corner of image. (if we want to use it, uncomment and remove extra read.)
// int yOffset = flipEndian(dis.readShort());
dis.readShort();
// width of image - in pixels
int width = flipEndian(dis.readShort());
// height of image - in pixels
int height = flipEndian(dis.readShort());
// bits per pixel in image.
int pixelDepth = dis.readUnsignedByte();
int imageDescriptor = dis.readUnsignedByte();
if (// bit 5 : if 1, flip top/bottom ordering
(imageDescriptor & 32) != 0) {
flip = !flip;
}
if (// bit 4 : if 1, flip left/right ordering
(imageDescriptor & 16) != 0) {
flipH = !flipH;
}
// Skip image ID
if (idLength > 0) {
dis.skip(idLength);
}
ColorMapEntry[] cMapEntries = null;
if (colorMapType != 0) {
// read the color map.
int bytesInColorMap = (cMapDepth * cMapLength) >> 3;
int bitsPerColor = Math.min(cMapDepth / 3, 8);
byte[] cMapData = new byte[bytesInColorMap];
dis.read(cMapData);
// table if this is declared a color mapped image.
if (imageType == TYPE_COLORMAPPED || imageType == TYPE_COLORMAPPED_RLE) {
cMapEntries = new ColorMapEntry[cMapLength];
int alphaSize = cMapDepth - (3 * bitsPerColor);
float scalar = 255f / (FastMath.pow(2, bitsPerColor) - 1);
float alphaScalar = 255f / (FastMath.pow(2, alphaSize) - 1);
for (int i = 0; i < cMapLength; i++) {
ColorMapEntry entry = new ColorMapEntry();
int offset = cMapDepth * i;
entry.red = (byte) (int) (getBitsAsByte(cMapData, offset, bitsPerColor) * scalar);
entry.green = (byte) (int) (getBitsAsByte(cMapData, offset + bitsPerColor, bitsPerColor) * scalar);
entry.blue = (byte) (int) (getBitsAsByte(cMapData, offset + (2 * bitsPerColor), bitsPerColor) * scalar);
if (alphaSize <= 0) {
entry.alpha = (byte) 255;
} else {
entry.alpha = (byte) (int) (getBitsAsByte(cMapData, offset + (3 * bitsPerColor), alphaSize) * alphaScalar);
}
cMapEntries[i] = entry;
}
}
}
// Allocate image data array
Format format;
byte[] rawData = null;
int dl;
if (pixelDepth == 32) {
rawData = new byte[width * height * 4];
dl = 4;
} else {
rawData = new byte[width * height * 3];
dl = 3;
}
int rawDataIndex = 0;
if (imageType == TYPE_TRUECOLOR) {
byte red = 0;
byte green = 0;
byte blue = 0;
byte alpha = 0;
// just make a seperate loop for each.
if (pixelDepth == 16) {
byte[] data = new byte[2];
float scalar = 255f / 31f;
for (int i = 0; i <= (height - 1); i++) {
if (!flip) {
rawDataIndex = (height - 1 - i) * width * dl;
}
for (int j = 0; j < width; j++) {
data[1] = dis.readByte();
data[0] = dis.readByte();
rawData[rawDataIndex++] = (byte) (int) (getBitsAsByte(data, 1, 5) * scalar);
rawData[rawDataIndex++] = (byte) (int) (getBitsAsByte(data, 6, 5) * scalar);
rawData[rawDataIndex++] = (byte) (int) (getBitsAsByte(data, 11, 5) * scalar);
if (dl == 4) {
// create an alpha channel
alpha = getBitsAsByte(data, 0, 1);
if (alpha == 1) {
alpha = (byte) 255;
}
rawData[rawDataIndex++] = alpha;
}
}
}
format = dl == 4 ? Format.RGBA8 : Format.RGB8;
} else if (pixelDepth == 24) {
for (int y = 0; y < height; y++) {
if (!flip) {
rawDataIndex = (height - 1 - y) * width * dl;
} else {
rawDataIndex = y * width * dl;
}
dis.readFully(rawData, rawDataIndex, width * dl);
// for (int x = 0; x < width; x++) {
//read scanline
// blue = dis.readByte();
// green = dis.readByte();
// red = dis.readByte();
// rawData[rawDataIndex++] = red;
// rawData[rawDataIndex++] = green;
// rawData[rawDataIndex++] = blue;
// }
}
format = Format.BGR8;
} else if (pixelDepth == 32) {
for (int i = 0; i <= (height - 1); i++) {
if (!flip) {
rawDataIndex = (height - 1 - i) * width * dl;
}
for (int j = 0; j < width; j++) {
blue = dis.readByte();
green = dis.readByte();
red = dis.readByte();
alpha = dis.readByte();
rawData[rawDataIndex++] = red;
rawData[rawDataIndex++] = green;
rawData[rawDataIndex++] = blue;
rawData[rawDataIndex++] = alpha;
}
}
format = Format.RGBA8;
} else {
throw new IOException("Unsupported TGA true color depth: " + pixelDepth);
}
} else if (imageType == TYPE_TRUECOLOR_RLE) {
byte red = 0;
byte green = 0;
byte blue = 0;
byte alpha = 0;
// just make a seperate loop for each.
if (pixelDepth == 32) {
for (int i = 0; i <= (height - 1); ++i) {
if (!flip) {
rawDataIndex = (height - 1 - i) * width * dl;
}
for (int j = 0; j < width; ++j) {
// Get the number of pixels the next chunk covers (either packed or unpacked)
int count = dis.readByte();
if ((count & 0x80) != 0) {
// Its an RLE packed block - use the following 1 pixel for the next <count> pixels
count &= 0x07f;
j += count;
blue = dis.readByte();
green = dis.readByte();
red = dis.readByte();
alpha = dis.readByte();
while (count-- >= 0) {
rawData[rawDataIndex++] = red;
rawData[rawDataIndex++] = green;
rawData[rawDataIndex++] = blue;
rawData[rawDataIndex++] = alpha;
}
} else {
// Its not RLE packed, but the next <count> pixels are raw.
j += count;
while (count-- >= 0) {
blue = dis.readByte();
green = dis.readByte();
red = dis.readByte();
alpha = dis.readByte();
rawData[rawDataIndex++] = red;
rawData[rawDataIndex++] = green;
rawData[rawDataIndex++] = blue;
rawData[rawDataIndex++] = alpha;
}
}
}
}
format = Format.RGBA8;
} else if (pixelDepth == 24) {
for (int i = 0; i <= (height - 1); i++) {
if (!flip) {
rawDataIndex = (height - 1 - i) * width * dl;
}
for (int j = 0; j < width; ++j) {
// Get the number of pixels the next chunk covers (either packed or unpacked)
int count = dis.readByte();
if ((count & 0x80) != 0) {
// Its an RLE packed block - use the following 1 pixel for the next <count> pixels
count &= 0x07f;
j += count;
blue = dis.readByte();
green = dis.readByte();
red = dis.readByte();
while (count-- >= 0) {
rawData[rawDataIndex++] = red;
rawData[rawDataIndex++] = green;
rawData[rawDataIndex++] = blue;
}
} else {
// Its not RLE packed, but the next <count> pixels are raw.
j += count;
while (count-- >= 0) {
blue = dis.readByte();
green = dis.readByte();
red = dis.readByte();
rawData[rawDataIndex++] = red;
rawData[rawDataIndex++] = green;
rawData[rawDataIndex++] = blue;
}
}
}
}
format = Format.RGB8;
} else if (pixelDepth == 16) {
byte[] data = new byte[2];
float scalar = 255f / 31f;
for (int i = 0; i <= (height - 1); i++) {
if (!flip) {
rawDataIndex = (height - 1 - i) * width * dl;
}
for (int j = 0; j < width; j++) {
// Get the number of pixels the next chunk covers (either packed or unpacked)
int count = dis.readByte();
if ((count & 0x80) != 0) {
// Its an RLE packed block - use the following 1 pixel for the next <count> pixels
count &= 0x07f;
j += count;
data[1] = dis.readByte();
data[0] = dis.readByte();
blue = (byte) (int) (getBitsAsByte(data, 1, 5) * scalar);
green = (byte) (int) (getBitsAsByte(data, 6, 5) * scalar);
red = (byte) (int) (getBitsAsByte(data, 11, 5) * scalar);
while (count-- >= 0) {
rawData[rawDataIndex++] = red;
rawData[rawDataIndex++] = green;
rawData[rawDataIndex++] = blue;
}
} else {
// Its not RLE packed, but the next <count> pixels are raw.
j += count;
while (count-- >= 0) {
data[1] = dis.readByte();
data[0] = dis.readByte();
blue = (byte) (int) (getBitsAsByte(data, 1, 5) * scalar);
green = (byte) (int) (getBitsAsByte(data, 6, 5) * scalar);
red = (byte) (int) (getBitsAsByte(data, 11, 5) * scalar);
rawData[rawDataIndex++] = red;
rawData[rawDataIndex++] = green;
rawData[rawDataIndex++] = blue;
}
}
}
}
format = Format.RGB8;
} else {
throw new IOException("Unsupported TGA true color depth: " + pixelDepth);
}
} else if (imageType == TYPE_COLORMAPPED) {
int bytesPerIndex = pixelDepth / 8;
if (bytesPerIndex == 1) {
for (int i = 0; i <= (height - 1); i++) {
if (!flip) {
rawDataIndex = (height - 1 - i) * width * dl;
}
for (int j = 0; j < width; j++) {
int index = dis.readUnsignedByte();
if (index >= cMapEntries.length || index < 0) {
throw new IOException("TGA: Invalid color map entry referenced: " + index);
}
ColorMapEntry entry = cMapEntries[index];
rawData[rawDataIndex++] = entry.blue;
rawData[rawDataIndex++] = entry.green;
rawData[rawDataIndex++] = entry.red;
if (dl == 4) {
rawData[rawDataIndex++] = entry.alpha;
}
}
}
} else if (bytesPerIndex == 2) {
for (int i = 0; i <= (height - 1); i++) {
if (!flip) {
rawDataIndex = (height - 1 - i) * width * dl;
}
for (int j = 0; j < width; j++) {
int index = flipEndian(dis.readShort());
if (index >= cMapEntries.length || index < 0) {
throw new IOException("TGA: Invalid color map entry referenced: " + index);
}
ColorMapEntry entry = cMapEntries[index];
rawData[rawDataIndex++] = entry.blue;
rawData[rawDataIndex++] = entry.green;
rawData[rawDataIndex++] = entry.red;
if (dl == 4) {
rawData[rawDataIndex++] = entry.alpha;
}
}
}
} else {
throw new IOException("TGA: unknown colormap indexing size used: " + bytesPerIndex);
}
format = dl == 4 ? Format.RGBA8 : Format.RGB8;
} else {
throw new IOException("Monochrome and RLE colormapped images are not supported");
}
in.close();
// Get a pointer to the image memory
ByteBuffer scratch = BufferUtils.createByteBuffer(rawData.length);
scratch.clear();
scratch.put(rawData);
scratch.rewind();
// Create the Image object
Image textureImage = new Image();
textureImage.setFormat(format);
textureImage.setWidth(width);
textureImage.setHeight(height);
textureImage.setData(scratch);
return textureImage;
}
Aggregations