diff options
Diffstat (limited to 'src/demos/hdr/HDRTexture.java')
-rwxr-xr-x | src/demos/hdr/HDRTexture.java | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/src/demos/hdr/HDRTexture.java b/src/demos/hdr/HDRTexture.java new file mode 100755 index 0000000..e21c898 --- /dev/null +++ b/src/demos/hdr/HDRTexture.java @@ -0,0 +1,495 @@ +package demos.hdr; + +import java.io.*; +import java.nio.*; + +import javax.media.opengl.*; + +public class HDRTexture { + private RGBE.Header header; + private byte[] m_data; + private float[] m_floatdata; + private int m_width, m_height; + private float m_max_r, m_max_g, m_max_b; + private float m_min_r, m_min_g, m_min_b; + private float m_max; + private int m_target; + + public HDRTexture(String filename) throws IOException { + this(new FileInputStream(filename)); + } + + public HDRTexture(InputStream in) throws IOException { + DataInputStream datain = new DataInputStream(new BufferedInputStream(in)); + header = RGBE.readHeader(datain); + m_width = header.getWidth(); + m_height = header.getHeight(); + m_data = new byte[m_width * m_height * 4]; + RGBE.readPixelsRawRLE(datain, m_data, 0, m_width, m_height); + System.err.println("Loaded HDR image " + m_width + " x " + m_height); + } + + public byte[] getData() { return m_data; } + public int getPixelIndex(int x, int y) { + return ((m_width * (m_height - 1 - y)) + x) * 4; + } + public float[] getFloatData() { return m_floatdata; } + public int getPixelFloatIndex(int x, int y) { + return ((m_width * (m_height - 1 - y)) + x) * 3; + } + + public void analyze() { + m_max_r = m_max_g = m_max_b = 0.0f; + m_min_r = m_min_g = m_min_b = 1e10f; + int mine = 255; + int maxe = 0; + + int ptr = 0; + float[] rgb = new float[3]; + for(int i=0; i<m_width*m_height; i++) { + int e = m_data[ptr+3] & 0xFF; + if (e < mine) mine = e; + if (e > maxe) maxe = e; + + RGBE.rgbe2float(rgb, m_data, ptr); + float r = rgb[0]; + float g = rgb[1]; + float b = rgb[2]; + if (r > m_max_r) m_max_r = r; + if (g > m_max_g) m_max_g = g; + if (b > m_max_b) m_max_b = b; + if (r < m_min_r) m_min_r = r; + if (g < m_min_g) m_min_g = g; + if (b < m_min_b) m_min_b = b; + ptr += 4; + } + System.err.println("max intensity: " + m_max_r + " " + m_max_g + " " + m_max_b); + System.err.println("min intensity: " + m_min_r + " " + m_min_g + " " + m_min_b); + System.err.println("max e: " + maxe + " = " + RGBE.ldexp(1.0, maxe-128)); + System.err.println("min e: " + mine + " = " + RGBE.ldexp(1.0, mine-128)); + + m_max = m_max_r; + if (m_max_g > m_max) m_max = m_max_g; + if (m_max_b > m_max) m_max = m_max_b; + System.err.println("max: " + m_max); + } + + /** Converts from RGBE to floating-point RGB data. */ + public void convert() { + m_floatdata = new float [m_width*m_height*3]; + + int src = 0; + int dest = 0; + float[] rgb = new float[3]; + for(int i=0; i<m_width*m_height; i++) { + RGBE.rgbe2float(rgb, m_data, src); + + m_floatdata[dest++] = remap(rgb[0], m_max); + m_floatdata[dest++] = remap(rgb[1], m_max); + m_floatdata[dest++] = remap(rgb[2], m_max); + + src += 4; + } + } + + public int create2DTextureRGBE(GL gl, int targetTextureType) { + m_target = targetTextureType; + int[] tmp = new int[1]; + gl.glGenTextures(1, tmp, 0); + int texid = tmp[1]; + + gl.glBindTexture(m_target, texid); + + gl.glTexParameteri(m_target, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); + + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + gl.glTexParameteri(m_target, GL2ES1.GL_GENERATE_MIPMAP, GL.GL_TRUE); + gl.glTexImage2D(m_target, 0, GL.GL_RGBA, m_width, m_height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap(m_data)); + + return texid; + } + + public int create2DTextureHILO(GL gl, int targetTextureType, boolean rg) { + m_target = targetTextureType; + int[] tmp = new int[1]; + gl.glGenTextures(1, tmp, 0); + int texid = tmp[0]; + + gl.glBindTexture(m_target, texid); + + gl.glTexParameteri(m_target, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); + + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + gl.glTexParameteri(m_target, GL2ES1.GL_GENERATE_MIPMAP, GL.GL_TRUE); + + float[] img = new float [m_width * m_height * 2]; + int src = 0; + int dest = 0; + for (int j=0; j<m_height; j++) { + for (int i=0; i<m_width; i++) { + if (rg) { + img[dest++] = m_floatdata[src + 0]; + img[dest++] = m_floatdata[src + 1]; + } else { + img[dest++] = m_floatdata[src + 2]; + img[dest++] = 0; + } + src+=3; + } + } + + gl.glTexImage2D(m_target, 0, GL2.GL_HILO16_NV, m_width, m_height, 0, GL2.GL_HILO_NV, GL.GL_FLOAT, FloatBuffer.wrap(img)); + + return texid; + } + + // create a cubemap texture from a 2D image in cross format (thanks to Jonathon McGee) + public int createCubemapRGBE(GL gl) { + // cross is 3 faces wide, 4 faces high + int face_width = m_width / 3; + int face_height = m_height / 4; + byte[] face = new byte[face_width * face_height * 4]; + + m_target = GL.GL_TEXTURE_CUBE_MAP; + int[] tmp = new int[1]; + gl.glGenTextures(1, tmp, 0); + int texid = tmp[0]; + gl.glBindTexture(m_target, texid); + + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + gl.glTexParameteri(m_target, GL2ES1.GL_GENERATE_MIPMAP, GL.GL_TRUE); + + // gl.glTexParameteri(m_target, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + // gl.glTexParameteri(m_target, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); + + // extract 6 faces + + // positive Y + int ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelIndex(2 * face_width - (i + 1), 3 * face_height + j); + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL.GL_RGBA, face_width, face_height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap(face)); + + // positive X + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelIndex(i, m_height - (face_height + j + 1)); + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL.GL_RGBA, face_width, face_height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap(face)); + + // negative Z + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelIndex(face_width + i, m_height - (face_height + j + 1)); + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL.GL_RGBA, face_width, face_height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap(face)); + + // negative X + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelIndex(2 * face_width + i, m_height - (face_height + j + 1)); + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL.GL_RGBA, face_width, face_height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap(face)); + + // negative Y + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelIndex(2 * face_width - (i + 1), face_height + j); + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL.GL_RGBA, face_width, face_height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap(face)); + + // positive Z + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelIndex(2 * face_width - (i + 1), j); + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + face[ptr++] = m_data[src++]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL.GL_RGBA, face_width, face_height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap(face)); + + return texid; + } + + public int createCubemapHILO(GL gl, boolean rg) { + // cross is 3 faces wide, 4 faces high + int face_width = m_width / 3; + int face_height = m_height / 4; + float[] face = new float [face_width * face_height * 2]; + + m_target = GL.GL_TEXTURE_CUBE_MAP; + int[] tmp = new int[1]; + gl.glGenTextures(1, tmp, 0); + int texid = tmp[0]; + gl.glBindTexture(m_target, texid); + + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + gl.glTexParameteri(m_target, GL2ES1.GL_GENERATE_MIPMAP, GL.GL_TRUE); + + gl.glTexParameteri(m_target, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); + + // extract 6 faces + + // positive Y + int ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(2 * face_width - (i + 1), 3 * face_height + j); + if (rg) { + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + } else { + face[ptr++] = m_floatdata[src + 2]; + face[ptr++] = 0; + } + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL2.GL_HILO16_NV, face_width, face_height, 0, GL2.GL_HILO_NV, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + // positive X + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(i, m_height - (face_height + j + 1)); + if (rg) { + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + } else { + face[ptr++] = m_floatdata[src + 2]; + face[ptr++] = 0; + } + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL2.GL_HILO16_NV, face_width, face_height, 0, GL2.GL_HILO_NV, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + // negative Z + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(face_width + i, m_height - (face_height + j + 1)); + if (rg) { + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + } else { + face[ptr++] = m_floatdata[src + 2]; + face[ptr++] = 0; + } + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL2.GL_HILO16_NV, face_width, face_height, 0, GL2.GL_HILO_NV, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + // negative X + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(2 * face_width + i, m_height - (face_height + j + 1)); + if (rg) { + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + } else { + face[ptr++] = m_floatdata[src + 2]; + face[ptr++] = 0; + } + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL2.GL_HILO16_NV, face_width, face_height, 0, GL2.GL_HILO_NV, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + // negative Y + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(2 * face_width - (i + 1), face_height + j); + if (rg) { + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + } else { + face[ptr++] = m_floatdata[src + 2]; + face[ptr++] = 0; + } + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL2.GL_HILO16_NV, face_width, face_height, 0, GL2.GL_HILO_NV, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + // positive Z + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(2 * face_width - (i + 1), j); + if (rg) { + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + } else { + face[ptr++] = m_floatdata[src + 2]; + face[ptr++] = 0; + } + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL2.GL_HILO16_NV, face_width, face_height, 0, GL2.GL_HILO_NV, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + return texid; + } + + public int createCubemap(GL gl, int format) { + // cross is 3 faces wide, 4 faces high + int face_width = m_width / 3; + int face_height = m_height / 4; + float[] face = new float [face_width * face_height * 3]; + + m_target = GL.GL_TEXTURE_CUBE_MAP; + int[] tmp = new int[1]; + gl.glGenTextures(1, tmp, 0); + int texid = tmp[0]; + gl.glBindTexture(m_target, texid); + + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + gl.glTexParameteri(m_target, GL2ES1.GL_GENERATE_MIPMAP, GL.GL_TRUE); + + gl.glTexParameteri(m_target, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); + gl.glTexParameteri(m_target, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); + + // extract 6 faces + + // positive Y + int ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(2 * face_width - (i + 1), 3 * face_height + j); + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + face[ptr++] = m_floatdata[src + 2]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, format, face_width, face_height, 0, GL.GL_RGB, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + // positive X + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(i, m_height - (face_height + j + 1)); + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + face[ptr++] = m_floatdata[src + 2]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, format, face_width, face_height, 0, GL.GL_RGB, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + // negative Z + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(face_width + i, m_height - (face_height + j + 1)); + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + face[ptr++] = m_floatdata[src + 2]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, format, face_width, face_height, 0, GL.GL_RGB, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + // negative X + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(2 * face_width + i, m_height - (face_height + j + 1)); + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + face[ptr++] = m_floatdata[src + 2]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, format, face_width, face_height, 0, GL.GL_RGB, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + // negative Y + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(2 * face_width - (i + 1), face_height + j); + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + face[ptr++] = m_floatdata[src + 2]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, format, face_width, face_height, 0, GL.GL_RGB, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + // positive Z + ptr = 0; + for (int j=0; j<face_height; j++) { + for (int i=0; i<face_width; i++) { + int src = getPixelFloatIndex(2 * face_width - (i + 1), j); + face[ptr++] = m_floatdata[src + 0]; + face[ptr++] = m_floatdata[src + 1]; + face[ptr++] = m_floatdata[src + 2]; + } + } + gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, format, face_width, face_height, 0, GL.GL_RGB, GL.GL_FLOAT, FloatBuffer.wrap(face)); + + return texid; + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private static float remap(float x, float max) { + if (x > max) x = max; + return (float) Math.sqrt(x / max); + } + + public static void main(String[] args) { + for (int i = 0; i < args.length; i++) { + try { + HDRTexture tex = new HDRTexture(args[i]); + tex.analyze(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} |