159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/* 259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Copyright (c) 2009-2010 jMonkeyEngine 359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * All rights reserved. 459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Redistribution and use in source and binary forms, with or without 659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * modification, are permitted provided that the following conditions are 759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * met: 859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions of source code must retain the above copyright 1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * notice, this list of conditions and the following disclaimer. 1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions in binary form must reproduce the above copyright 1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * notice, this list of conditions and the following disclaimer in the 1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * documentation and/or other materials provided with the distribution. 1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * may be used to endorse or promote products derived from this software 1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * without specific prior written permission. 1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.texture.plugins; 3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.AssetInfo; 3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.AssetLoader; 3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.TextureKey; 3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.FastMath; 3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Image; 4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Image.Format; 4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.BufferUtils; 4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.IOException; 4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.InputStream; 4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.ByteBuffer; 4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Level; 4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Logger; 4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class HDRLoader implements AssetLoader { 4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final Logger logger = Logger.getLogger(HDRLoader.class.getName()); 5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private boolean writeRGBE = false; 5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private ByteBuffer rleTempBuffer; 5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private ByteBuffer dataStore; 5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private final float[] tempF = new float[3]; 5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public HDRLoader(boolean writeRGBE){ 5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.writeRGBE = writeRGBE; 5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public HDRLoader(){ 6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public static void convertFloatToRGBE(byte[] rgbe, float red, float green, float blue){ 6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta double max = red; 6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (green > max) max = green; 6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (blue > max) max = blue; 6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (max < 1.0e-32){ 6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; 7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }else{ 7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta double exp = Math.ceil( Math.log10(max) / Math.log10(2) ); 7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta double divider = Math.pow(2.0, exp); 7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbe[0] = (byte) ((red / divider) * 255.0); 7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbe[1] = (byte) ((green / divider) * 255.0); 7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbe[2] = (byte) ((blue / divider) * 255.0); 7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbe[3] = (byte) (exp + 128.0); 7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public static void convertRGBEtoFloat(byte[] rgbe, float[] rgbf){ 8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int R = rgbe[0] & 0xFF, 8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta G = rgbe[1] & 0xFF, 8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta B = rgbe[2] & 0xFF, 8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta E = rgbe[3] & 0xFF; 8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float e = (float) Math.pow(2f, E - (128 + 8) ); 8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbf[0] = R * e; 8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbf[1] = G * e; 8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbf[2] = B * e; 9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public static void convertRGBEtoFloat2(byte[] rgbe, float[] rgbf){ 9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int R = rgbe[0] & 0xFF, 9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta G = rgbe[1] & 0xFF, 9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta B = rgbe[2] & 0xFF, 9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta E = rgbe[3] & 0xFF; 9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float e = (float) Math.pow(2f, E - 128); 9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbf[0] = (R / 256.0f) * e; 10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbf[1] = (G / 256.0f) * e; 10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbf[2] = (B / 256.0f) * e; 10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public static void convertRGBEtoFloat3(byte[] rgbe, float[] rgbf){ 10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int R = rgbe[0] & 0xFF, 10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta G = rgbe[1] & 0xFF, 10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta B = rgbe[2] & 0xFF, 10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta E = rgbe[3] & 0xFF; 10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float e = (float) Math.pow(2f, E - (128 + 8) ); 11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbf[0] = R * e; 11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbf[1] = G * e; 11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rgbf[2] = B * e; 11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private short flip(int in){ 11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return (short) ((in << 8 & 0xFF00) | (in >> 8)); 11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private void writeRGBE(byte[] rgbe){ 12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (writeRGBE){ 12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataStore.put(rgbe); 12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }else{ 12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta convertRGBEtoFloat(rgbe, tempF); 12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataStore.putShort(FastMath.convertFloatToHalf(tempF[0])) 12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta .putShort(FastMath.convertFloatToHalf(tempF[1])). 12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta putShort(FastMath.convertFloatToHalf(tempF[2])); 12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private String readString(InputStream is) throws IOException{ 13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta StringBuilder sb = new StringBuilder(); 13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta while (true){ 13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int i = is.read(); 13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (i == 0x0a || i == -1) // new line or EOF 13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return sb.toString(); 13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta sb.append((char)i); 13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private boolean decodeScanlineRLE(InputStream in, int width) throws IOException{ 14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // must deocde RLE data into temp buffer before converting to float 14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (rleTempBuffer == null){ 14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rleTempBuffer = BufferUtils.createByteBuffer(width * 4); 14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }else{ 14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rleTempBuffer.clear(); 14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (rleTempBuffer.remaining() < width * 4) 14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rleTempBuffer = BufferUtils.createByteBuffer(width * 4); 15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // read each component seperately 15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < 4; i++) { 15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // read WIDTH bytes for the channel 15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int j = 0; j < width;) { 15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int code = in.read(); 15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (code > 128) { // run 15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta code -= 128; 15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int val = in.read(); 16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta while ((code--) != 0) { 16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rleTempBuffer.put( (j++) * 4 + i , (byte)val); 16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //scanline[j++][i] = val; 16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { // non-run 16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta while ((code--) != 0) { 16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int val = in.read(); 16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rleTempBuffer.put( (j++) * 4 + i, (byte)val); 16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //scanline[j++][i] = in.read(); 16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rleTempBuffer.rewind(); 17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] rgbe = new byte[4]; 17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta// float[] temp = new float[3]; 17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // decode temp buffer into float data 17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < width; i++){ 18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rleTempBuffer.get(rgbe); 18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta writeRGBE(rgbe); 18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private boolean decodeScanlineUncompressed(InputStream in, int width) throws IOException{ 18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] rgbe = new byte[4]; 18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < width; i+=3){ 19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (in.read(rgbe) < 1) 19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return false; 19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta writeRGBE(rgbe); 19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private void decodeScanline(InputStream in, int width) throws IOException{ 20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (width < 8 || width > 0x7fff){ 20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // too short/long for RLE compression 20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta decodeScanlineUncompressed(in, width); 20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // check format 20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] data = new byte[4]; 20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.read(data); 20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (data[0] != 0x02 || data[1] != 0x02 || (data[2] & 0x80) != 0){ 20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // not RLE data 21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta decodeScanlineUncompressed(in, width-1); 21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }else{ 21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // check scanline width 21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int readWidth = (data[2] & 0xFF) << 8 | (data[3] & 0xFF); 21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (readWidth != width) 21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Illegal scanline width in HDR file: "+width+" != "+readWidth); 21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // RLE data 21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta decodeScanlineRLE(in, width); 21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Image load(InputStream in, boolean flipY) throws IOException{ 22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float gamma = -1f; 22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float exposure = -1f; 22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] colorcorr = new float[]{ -1f, -1f, -1f }; 22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int width = -1, height = -1; 22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean verifiedFormat = false; 22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta while (true){ 23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta String ln = readString(in); 23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ln = ln.trim(); 23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (ln.startsWith("#") || ln.equals("")){ 23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (ln.equals("#?RADIANCE") || ln.equals("#?RGBE")) 23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta verifiedFormat = true; 23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta continue; // comment or empty statement 23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (ln.startsWith("+") || ln.startsWith("-")){ 23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // + or - mark image resolution and start of data 24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta String[] resData = ln.split("\\s"); 24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (resData.length != 4){ 24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Invalid resolution string in HDR file"); 24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!resData[0].equals("-Y") || !resData[2].equals("+X")){ 24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.warning("Flipping/Rotating attributes ignored!"); 24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //if (resData[0].endsWith("X")){ 25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // first width then height 25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // width = Integer.parseInt(resData[1]); 25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // height = Integer.parseInt(resData[3]); 25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //}else{ 25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta width = Integer.parseInt(resData[3]); 25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta height = Integer.parseInt(resData[1]); 25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //} 25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // regular command 26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int index = ln.indexOf("="); 26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (index < 1){ 26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.log(Level.FINE, "Ignored string: {0}", ln); 26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta continue; 26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta String var = ln.substring(0, index).trim().toLowerCase(); 26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta String value = ln.substring(index+1).trim().toLowerCase(); 26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (var.equals("format")){ 27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!value.equals("32-bit_rle_rgbe") && !value.equals("32-bit_rle_xyze")){ 27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Unsupported format in HDR picture"); 27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }else if (var.equals("exposure")){ 27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta exposure = Float.parseFloat(value); 27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }else if (var.equals("gamma")){ 27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta gamma = Float.parseFloat(value); 27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }else{ 27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.log(Level.WARNING, "HDR Command ignored: {0}", ln); 27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta assert width != -1 && height != -1; 28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!verifiedFormat) 28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.warning("Unsure if specified image is Radiance HDR"); 28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // some HDR images can get pretty big 28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta System.gc(); 29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // each pixel times size of component times # of components 29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Format pixelFormat; 29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (writeRGBE){ 29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Format.RGBA8; 29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }else{ 29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Format.RGB16F; 29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataStore = BufferUtils.createByteBuffer(width * height * pixelFormat.getBitsPerPixel()); 30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int bytesPerPixel = pixelFormat.getBitsPerPixel() / 8; 30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int scanLineBytes = bytesPerPixel * width; 30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int y = height - 1; y >= 0; y--) { 30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (flipY) 30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataStore.position(scanLineBytes * y); 30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta decodeScanline(in, width); 30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.close(); 31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataStore.rewind(); 31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return new Image(pixelFormat, width, height, dataStore); 31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Object load(AssetInfo info) throws IOException { 31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!(info.getKey() instanceof TextureKey)) 31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalArgumentException("Texture assets must be loaded using a TextureKey"); 31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean flip = ((TextureKey) info.getKey()).isFlipY(); 32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta InputStream in = null; 32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta try { 32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in = info.openStream(); 32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Image img = load(in, flip); 32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return img; 32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } finally { 32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (in != null){ 32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.close(); 32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta} 333