/* * Copyright (c) 2009-2012 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'jMonkeyEngine' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.jme3.texture.plugins; import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetLoader; import com.jme3.asset.TextureKey; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.logging.Logger; public class PFMLoader implements AssetLoader { private static final Logger logger = Logger.getLogger(PFMLoader.class.getName()); private String readString(InputStream is) throws IOException{ StringBuilder sb = new StringBuilder(); while (true){ int i = is.read(); if (i == 0x0a || i == -1) // new line or EOF return sb.toString(); sb.append((char)i); } } private void flipScanline(byte[] scanline){ for (int i = 0; i < scanline.length; i+=4){ // flip first and fourth bytes byte tmp = scanline[i+3]; scanline[i+3] = scanline[i+0]; scanline[i+0] = tmp; // flip second and third bytes tmp = scanline[i+2]; scanline[i+2] = scanline[i+1]; scanline[i+1] = tmp; } } private Image load(InputStream in, boolean needYFlip) throws IOException{ Format format = null; String fmtStr = readString(in); if (fmtStr.equals("PF")){ format = Format.RGB32F; }else if (fmtStr.equals("Pf")){ format = Format.Luminance32F; }else{ throw new IOException("File is not PFM format"); } String sizeStr = readString(in); int spaceIdx = sizeStr.indexOf(" "); if (spaceIdx <= 0 || spaceIdx >= sizeStr.length() - 1) throw new IOException("Invalid size syntax in PFM file"); int width = Integer.parseInt(sizeStr.substring(0,spaceIdx)); int height = Integer.parseInt(sizeStr.substring(spaceIdx+1)); if (width <= 0 || height <= 0) throw new IOException("Invalid size specified in PFM file"); String scaleStr = readString(in); float scale = Float.parseFloat(scaleStr); ByteOrder order = scale < 0 ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN; boolean needEndienFlip = order != ByteOrder.nativeOrder(); // make sure all unneccessary stuff gets deleted from heap // before allocating large amount of memory System.gc(); int bytesPerPixel = format.getBitsPerPixel() / 8; int scanLineBytes = bytesPerPixel * width; ByteBuffer imageData = BufferUtils.createByteBuffer(width * height * bytesPerPixel); byte[] scanline = new byte[width * bytesPerPixel]; for (int y = height - 1; y >= 0; y--) { if (!needYFlip) imageData.position(scanLineBytes * y); int read = 0; int off = 0; do { read = in.read(scanline, off, scanline.length - off); off += read; } while (read > 0); if (needEndienFlip){ flipScanline(scanline); } imageData.put(scanline); } imageData.rewind(); return new Image(format, width, height, imageData, null, ColorSpace.Linear); } public Object load(AssetInfo info) throws IOException { if (!(info.getKey() instanceof TextureKey)) throw new IllegalArgumentException("Texture assets must be loaded using a TextureKey"); InputStream in = null; try { in = info.openStream(); return load(in, ((TextureKey)info.getKey()).isFlipY()); } finally { if (in != null){ in.close(); } } } }