Home | History | Annotate | Download | only in plugins
      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 
     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 
     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 
     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 
    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