1 /* 2 * Copyright (c) 2009-2010 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 package com.jme3.texture.plugins; 34 35 import com.jme3.asset.AssetInfo; 36 import com.jme3.asset.AssetLoader; 37 import com.jme3.asset.TextureKey; 38 import com.jme3.texture.Image; 39 import com.jme3.texture.Image.Format; 40 import com.jme3.util.BufferUtils; 41 import java.io.IOException; 42 import java.io.InputStream; 43 import java.nio.ByteBuffer; 44 import java.nio.ByteOrder; 45 import java.util.logging.Logger; 46 47 public class PFMLoader implements AssetLoader { 48 49 private static final Logger logger = Logger.getLogger(PFMLoader.class.getName()); 50 readString(InputStream is)51 private String readString(InputStream is) throws IOException{ 52 StringBuilder sb = new StringBuilder(); 53 while (true){ 54 int i = is.read(); 55 if (i == 0x0a || i == -1) // new line or EOF 56 return sb.toString(); 57 58 sb.append((char)i); 59 } 60 } 61 flipScanline(byte[] scanline)62 private void flipScanline(byte[] scanline){ 63 for (int i = 0; i < scanline.length; i+=4){ 64 // flip first and fourth bytes 65 byte tmp = scanline[i+3]; 66 scanline[i+3] = scanline[i+0]; 67 scanline[i+0] = tmp; 68 69 // flip second and third bytes 70 tmp = scanline[i+2]; 71 scanline[i+2] = scanline[i+1]; 72 scanline[i+1] = tmp; 73 } 74 } 75 load(InputStream in, boolean needYFlip)76 private Image load(InputStream in, boolean needYFlip) throws IOException{ 77 Format format = null; 78 79 String fmtStr = readString(in); 80 if (fmtStr.equals("PF")){ 81 format = Format.RGB32F; 82 }else if (fmtStr.equals("Pf")){ 83 format = Format.Luminance32F; 84 }else{ 85 throw new IOException("File is not PFM format"); 86 } 87 88 String sizeStr = readString(in); 89 int spaceIdx = sizeStr.indexOf(" "); 90 if (spaceIdx <= 0 || spaceIdx >= sizeStr.length() - 1) 91 throw new IOException("Invalid size syntax in PFM file"); 92 93 int width = Integer.parseInt(sizeStr.substring(0,spaceIdx)); 94 int height = Integer.parseInt(sizeStr.substring(spaceIdx+1)); 95 96 if (width <= 0 || height <= 0) 97 throw new IOException("Invalid size specified in PFM file"); 98 99 String scaleStr = readString(in); 100 float scale = Float.parseFloat(scaleStr); 101 ByteOrder order = scale < 0 ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN; 102 boolean needEndienFlip = order != ByteOrder.nativeOrder(); 103 104 // make sure all unneccessary stuff gets deleted from heap 105 // before allocating large amount of memory 106 System.gc(); 107 108 int bytesPerPixel = format.getBitsPerPixel() / 8; 109 int scanLineBytes = bytesPerPixel * width; 110 111 ByteBuffer imageData = BufferUtils.createByteBuffer(width * height * bytesPerPixel); 112 byte[] scanline = new byte[width * bytesPerPixel]; 113 114 for (int y = height - 1; y >= 0; y--) { 115 if (!needYFlip) 116 imageData.position(scanLineBytes * y); 117 118 int read = 0; 119 int off = 0; 120 do { 121 read = in.read(scanline, off, scanline.length - off); 122 off += read; 123 } while (read > 0); 124 125 if (needEndienFlip){ 126 flipScanline(scanline); 127 } 128 129 imageData.put(scanline); 130 } 131 imageData.rewind(); 132 133 return new Image(format, width, height, imageData); 134 } 135 load(AssetInfo info)136 public Object load(AssetInfo info) throws IOException { 137 if (!(info.getKey() instanceof TextureKey)) 138 throw new IllegalArgumentException("Texture assets must be loaded using a TextureKey"); 139 140 InputStream in = null; 141 try { 142 in = info.openStream(); 143 return load(in, ((TextureKey)info.getKey()).isFlipY()); 144 } finally { 145 if (in != null){ 146 in.close(); 147 } 148 } 149 150 } 151 152 } 153