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 Bartapackage com.jme3.texture.plugins; 3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.AssetInfo; 3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.AssetLoader; 3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.TextureKey; 3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Image; 3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Image.Format; 3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Texture.Type; 4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.BufferUtils; 4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.LittleEndien; 4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.DataInput; 4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.IOException; 4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.InputStream; 4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.ByteBuffer; 4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.ArrayList; 4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Level; 4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Logger; 4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/** 5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>DDSLoader</code> is an image loader that reads in a DirectX DDS file. 5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Supports DXT1, DXT3, DXT5, RGB, RGBA, Grayscale, Alpha pixel formats. 5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 2D images, mipmapped 2D images, and cubemaps. 5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Gareth Jenkins-Jones 5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Kirill Vainer 5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @version $Id: DDSLoader.java,v 2.0 2008/8/15 5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class DDSLoader implements AssetLoader { 6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final Logger logger = Logger.getLogger(DDSLoader.class.getName()); 6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final boolean forceRGBA = false; 6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDSD_MANDATORY = 0x1007; 6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDSD_MANDATORY_DX10 = 0x6; 6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDSD_MIPMAPCOUNT = 0x20000; 6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDSD_LINEARSIZE = 0x80000; 6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDSD_DEPTH = 0x800000; 6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDPF_ALPHAPIXELS = 0x1; 7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDPF_FOURCC = 0x4; 7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDPF_RGB = 0x40; 7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // used by compressonator to mark grayscale images, red channel mask is used for data and bitcount is 8 7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDPF_GRAYSCALE = 0x20000; 7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // used by compressonator to mark alpha images, alpha channel mask is used for data and bitcount is 8 7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDPF_ALPHA = 0x2; 7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // used by NVTextureTools to mark normal images. 7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDPF_NORMAL = 0x80000000; 7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int SWIZZLE_xGxR = 0x78477852; 7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDSCAPS_COMPLEX = 0x8; 8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDSCAPS_TEXTURE = 0x1000; 8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDSCAPS_MIPMAP = 0x400000; 8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDSCAPS2_CUBEMAP = 0x200; 8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DDSCAPS2_VOLUME = 0x200000; 8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int PF_DXT1 = 0x31545844; 8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int PF_DXT3 = 0x33545844; 8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int PF_DXT5 = 0x35545844; 8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int PF_ATI1 = 0x31495441; 8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int PF_ATI2 = 0x32495441; // 0x41544932; 8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int PF_DX10 = 0x30315844; // a DX10 format 9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DX10DIM_BUFFER = 0x1, 9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta DX10DIM_TEXTURE1D = 0x2, 9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta DX10DIM_TEXTURE2D = 0x3, 9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta DX10DIM_TEXTURE3D = 0x4; 9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final int DX10MISC_GENERATE_MIPS = 0x1, 9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta DX10MISC_TEXTURECUBE = 0x4; 9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final double LOG2 = Math.log(2); 9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int width; 9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int height; 9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int depth; 10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int flags; 10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int pitchOrSize; 10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int mipMapCount; 10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int caps1; 10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int caps2; 10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private boolean directx10; 10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private boolean compressed; 10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private boolean texture3D; 10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private boolean grayscaleOrAlpha; 10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private boolean normal; 11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Format pixelFormat; 11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int bpp; 11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int[] sizes; 11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int redMask, greenMask, blueMask, alphaMask; 11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private DataInput in; 11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public DDSLoader() { 11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Object load(AssetInfo info) throws IOException { 12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!(info.getKey() instanceof TextureKey)) { 12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalArgumentException("Texture assets must be loaded using a TextureKey"); 12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta InputStream stream = null; 12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta try { 12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta stream = info.openStream(); 12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in = new LittleEndien(stream); 12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta loadHeader(); 12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (texture3D) { 13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ((TextureKey) info.getKey()).setTextureTypeHint(Type.ThreeDimensional); 13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (depth > 1) { 13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ((TextureKey) info.getKey()).setTextureTypeHint(Type.CubeMap); 13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ArrayList<ByteBuffer> data = readData(((TextureKey) info.getKey()).isFlipY()); 13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return new Image(pixelFormat, width, height, depth, data, sizes); 13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } finally { 13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (stream != null){ 13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta stream.close(); 13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Image load(InputStream stream) throws IOException { 14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in = new LittleEndien(stream); 14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta loadHeader(); 14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ArrayList<ByteBuffer> data = readData(false); 14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return new Image(pixelFormat, width, height, depth, data, sizes); 14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private void loadDX10Header() throws IOException { 15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int dxgiFormat = in.readInt(); 15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (dxgiFormat != 83) { 15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Only DXGI_FORMAT_BC5_UNORM " 15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta + "is supported for DirectX10 DDS! Got: " + dxgiFormat); 15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Format.LATC; 15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bpp = 8; 15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta compressed = true; 15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int resDim = in.readInt(); 16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (resDim == DX10DIM_TEXTURE3D) { 16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta texture3D = true; 16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int miscFlag = in.readInt(); 16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int arraySize = in.readInt(); 16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (is(miscFlag, DX10MISC_TEXTURECUBE)) { 16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // mark texture as cube 16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (arraySize != 6) { 16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Cubemaps should consist of 6 images!"); 17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.skipBytes(4); // skip reserved value 17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Reads the header (first 128 bytes) of a DDS File 17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private void loadHeader() throws IOException { 18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (in.readInt() != 0x20534444 || in.readInt() != 124) { 18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Not a DDS file"); 18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta flags = in.readInt(); 18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!is(flags, DDSD_MANDATORY) && !is(flags, DDSD_MANDATORY_DX10)) { 18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Mandatory flags missing"); 18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta height = in.readInt(); 19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta width = in.readInt(); 19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pitchOrSize = in.readInt(); 19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta depth = in.readInt(); 19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipMapCount = in.readInt(); 19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.skipBytes(44); 19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = null; 19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta directx10 = false; 19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta readPixelFormat(); 19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta caps1 = in.readInt(); 20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta caps2 = in.readInt(); 20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.skipBytes(12); 20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta texture3D = false; 20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!directx10) { 20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!is(caps1, DDSCAPS_TEXTURE)) { 20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("File is not a texture"); 20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (depth <= 0) { 21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta depth = 1; 21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (is(caps2, DDSCAPS2_CUBEMAP)) { 21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta depth = 6; // somewhat of a hack, force loading 6 textures if a cubemap 21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (is(caps2, DDSCAPS2_VOLUME)) { 21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta texture3D = true; 21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int expectedMipmaps = 1 + (int) Math.ceil(Math.log(Math.max(height, width)) / LOG2); 22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (is(caps1, DDSCAPS_MIPMAP)) { 22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!is(flags, DDSD_MIPMAPCOUNT)) { 22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipMapCount = expectedMipmaps; 22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (mipMapCount != expectedMipmaps) { 22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // changed to warning- images often do not have the required amount, 22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // or specify that they have mipmaps but include only the top level.. 23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.log(Level.WARNING, "Got {0} mipmaps, expected {1}", 23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta new Object[]{mipMapCount, expectedMipmaps}); 23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipMapCount = 1; 23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (directx10) { 23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta loadDX10Header(); 23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta loadSizes(); 24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Reads the PixelFormat structure in a DDS file 24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private void readPixelFormat() throws IOException { 24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int pfSize = in.readInt(); 24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pfSize != 32) { 25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Pixel format size is " + pfSize + ", not 32"); 25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int pfFlags = in.readInt(); 25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normal = is(pfFlags, DDPF_NORMAL); 25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (is(pfFlags, DDPF_FOURCC)) { 25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta compressed = true; 25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int fourcc = in.readInt(); 25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int swizzle = in.readInt(); 26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.skipBytes(16); 26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta switch (fourcc) { 26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case PF_DXT1: 26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bpp = 4; 26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (is(pfFlags, DDPF_ALPHAPIXELS)) { 26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Image.Format.DXT1A; 26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Image.Format.DXT1; 26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case PF_DXT3: 27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bpp = 8; 27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Image.Format.DXT3; 27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case PF_DXT5: 27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bpp = 8; 27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Image.Format.DXT5; 27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (swizzle == SWIZZLE_xGxR) { 27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normal = true; 28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case PF_ATI1: 28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bpp = 4; 28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Image.Format.LTC; 28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case PF_ATI2: 28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bpp = 8; 28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Image.Format.LATC; 28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case PF_DX10: 29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta compressed = false; 29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta directx10 = true; 29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // exit here, the rest of the structure is not valid 29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // the real format will be available in the DX10 header 29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return; 29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta default: 29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Unknown fourcc: " + string(fourcc) + ", " + Integer.toHexString(fourcc)); 29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int size = ((width + 3) / 4) * ((height + 3) / 4) * bpp * 2; 30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (is(flags, DDSD_LINEARSIZE)) { 30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pitchOrSize == 0) { 30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.warning("Must use linear size with fourcc"); 30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pitchOrSize = size; 30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (pitchOrSize != size) { 30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.log(Level.WARNING, "Expected size = {0}, real = {1}", 30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta new Object[]{size, pitchOrSize}); 30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pitchOrSize = size; 31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta compressed = false; 31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // skip fourCC 31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.readInt(); 31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bpp = in.readInt(); 32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta redMask = in.readInt(); 32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta greenMask = in.readInt(); 32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta blueMask = in.readInt(); 32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta alphaMask = in.readInt(); 32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (is(pfFlags, DDPF_RGB)) { 32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (is(pfFlags, DDPF_ALPHAPIXELS)) { 32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Format.RGBA8; 32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Format.RGB8; 33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (is(pfFlags, DDPF_GRAYSCALE) && is(pfFlags, DDPF_ALPHAPIXELS)) { 33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta switch (bpp) { 33359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case 16: 33459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Format.Luminance8Alpha8; 33559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case 32: 33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Format.Luminance16Alpha16; 33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta default: 34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Unsupported GrayscaleAlpha BPP: " + bpp); 34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta grayscaleOrAlpha = true; 34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (is(pfFlags, DDPF_GRAYSCALE)) { 34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta switch (bpp) { 34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case 8: 34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Format.Luminance8; 34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case 16: 34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Format.Luminance16; 35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta default: 35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Unsupported Grayscale BPP: " + bpp); 35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta grayscaleOrAlpha = true; 35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (is(pfFlags, DDPF_ALPHA)) { 35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta switch (bpp) { 35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case 8: 35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Format.Alpha8; 35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta case 16: 36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pixelFormat = Format.Alpha16; 36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta break; 36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta default: 36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Unsupported Alpha BPP: " + bpp); 36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta grayscaleOrAlpha = true; 36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IOException("Unknown PixelFormat in DDS file"); 36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int size = (bpp / 8 * width); 37259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (is(flags, DDSD_LINEARSIZE)) { 37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pitchOrSize == 0) { 37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.warning("Linear size said to contain valid value but does not"); 37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pitchOrSize = size; 37759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (pitchOrSize != size) { 37859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.log(Level.WARNING, "Expected size = {0}, real = {1}", 37959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta new Object[]{size, pitchOrSize}); 38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 38259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pitchOrSize = size; 38359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 38559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 38659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 38759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Computes the sizes of each mipmap level in bytes, and stores it in sizes_[]. 38959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private void loadSizes() { 39159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipWidth = width; 39259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipHeight = height; 39359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 39459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta sizes = new int[mipMapCount]; 39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int outBpp = pixelFormat.getBitsPerPixel(); 39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < mipMapCount; i++) { 39759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int size; 39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (compressed) { 39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta size = ((mipWidth + 3) / 4) * ((mipHeight + 3) / 4) * outBpp * 2; 40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 40159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta size = mipWidth * mipHeight * outBpp / 8; 40259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 40359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 40459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta sizes[i] = ((size + 3) / 4) * 4; 40559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 40659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipWidth = Math.max(mipWidth / 2, 1); 40759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipHeight = Math.max(mipHeight / 2, 1); 40859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 40959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 41059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 41159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 41259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Flips the given image data on the Y axis. 41359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param data Data array containing image data (without mipmaps) 41459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param scanlineSize Size of a single scanline = width * bytesPerPixel 41559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param height Height of the image in pixels 41659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return The new data flipped by the Y axis 41759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 41859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public byte[] flipData(byte[] data, int scanlineSize, int height) { 41959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] newData = new byte[data.length]; 42059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 42159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int y = 0; y < height; y++) { 42259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta System.arraycopy(data, y * scanlineSize, 42359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta newData, (height - y - 1) * scanlineSize, 42459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta scanlineSize); 42559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 42659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 42759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return newData; 42859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 42959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 43059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 43159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Reads a grayscale image with mipmaps from the InputStream 43259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param flip Flip the loaded image by Y axis 43359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param totalSize Total size of the image in bytes including the mipmaps 43459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return A ByteBuffer containing the grayscale image data with mips. 43559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws java.io.IOException If an error occured while reading from InputStream 43659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 43759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public ByteBuffer readGrayscale2D(boolean flip, int totalSize) throws IOException { 43859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer buffer = BufferUtils.createByteBuffer(totalSize); 43959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 44059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bpp == 8) { 44159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.finest("Source image format: R8"); 44259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 44359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 44459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta assert bpp == pixelFormat.getBitsPerPixel(); 44559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 44659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipWidth = width; 44759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipHeight = height; 44859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 44959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int mip = 0; mip < mipMapCount; mip++) { 45059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] data = new byte[sizes[mip]]; 45159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.readFully(data); 45259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (flip) { 45359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta data = flipData(data, mipWidth * bpp / 8, mipHeight); 45459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 45559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buffer.put(data); 45659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 45759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipWidth = Math.max(mipWidth / 2, 1); 45859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipHeight = Math.max(mipHeight / 2, 1); 45959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 46059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 46159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return buffer; 46259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 46359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 46459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 46559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Reads an uncompressed RGB or RGBA image. 46659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 46759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param flip Flip the image on the Y axis 46859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param totalSize Size of the image in bytes including mipmaps 46959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return ByteBuffer containing image data with mipmaps in the format specified by pixelFormat_ 47059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws java.io.IOException If an error occured while reading from InputStream 47159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 47259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public ByteBuffer readRGB2D(boolean flip, int totalSize) throws IOException { 47359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int redCount = count(redMask), 47459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta blueCount = count(blueMask), 47559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta greenCount = count(greenMask), 47659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta alphaCount = count(alphaMask); 47759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 47859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (redMask == 0x00FF0000 && greenMask == 0x0000FF00 && blueMask == 0x000000FF) { 47959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (alphaMask == 0xFF000000 && bpp == 32) { 48059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.finest("Data source format: BGRA8"); 48159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (bpp == 24) { 48259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.finest("Data source format: BGR8"); 48359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 48459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 48559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 48659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int sourcebytesPP = bpp / 8; 48759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int targetBytesPP = pixelFormat.getBitsPerPixel() / 8; 48859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 48959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer dataBuffer = BufferUtils.createByteBuffer(totalSize); 49059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 49159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipWidth = width; 49259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipHeight = height; 49359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 49459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int offset = 0; 49559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] b = new byte[sourcebytesPP]; 49659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int mip = 0; mip < mipMapCount; mip++) { 49759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int y = 0; y < mipHeight; y++) { 49859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int x = 0; x < mipWidth; x++) { 49959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.readFully(b); 50059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 50159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int i = byte2int(b); 50259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 50359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte red = (byte) (((i & redMask) >> redCount)); 50459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte green = (byte) (((i & greenMask) >> greenCount)); 50559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte blue = (byte) (((i & blueMask) >> blueCount)); 50659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte alpha = (byte) (((i & alphaMask) >> alphaCount)); 50759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 50859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (flip) { 50959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataBuffer.position(offset + ((mipHeight - y - 1) * mipWidth + x) * targetBytesPP); 51059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 51159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //else 51259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // dataBuffer.position(offset + (y * width + x) * targetBytesPP); 51359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 51459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (alphaMask == 0) { 51559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataBuffer.put(red).put(green).put(blue); 51659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 51759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataBuffer.put(red).put(green).put(blue).put(alpha); 51859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 51959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 52059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 52159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta offset += mipWidth * mipHeight * targetBytesPP; 52359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipWidth = Math.max(mipWidth / 2, 1); 52559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipHeight = Math.max(mipHeight / 2, 1); 52659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 52759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return dataBuffer; 52959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 53059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 53159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 53259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Reads a DXT compressed image from the InputStream 53359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 53459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param totalSize Total size of the image in bytes, including mipmaps 53559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return ByteBuffer containing compressed DXT image in the format specified by pixelFormat_ 53659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws java.io.IOException If an error occured while reading from InputStream 53759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 53859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public ByteBuffer readDXT2D(boolean flip, int totalSize) throws IOException { 53959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.finest("Source image format: DXT"); 54059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 54159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer buffer = BufferUtils.createByteBuffer(totalSize); 54259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 54359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipWidth = width; 54459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipHeight = height; 54559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 54659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int mip = 0; mip < mipMapCount; mip++) { 54759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (flip) { 54859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] data = new byte[sizes[mip]]; 54959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.readFully(data); 55059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer wrapped = ByteBuffer.wrap(data); 55159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta wrapped.rewind(); 55259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer flipped = DXTFlipper.flipDXT(wrapped, mipWidth, mipHeight, pixelFormat); 55359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buffer.put(flipped); 55459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 55559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] data = new byte[sizes[mip]]; 55659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.readFully(data); 55759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buffer.put(data); 55859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 55959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 56059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipWidth = Math.max(mipWidth / 2, 1); 56159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipHeight = Math.max(mipHeight / 2, 1); 56259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 56359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buffer.rewind(); 56459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 56559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return buffer; 56659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 56759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 56859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 56959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Reads a grayscale image with mipmaps from the InputStream 57059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param flip Flip the loaded image by Y axis 57159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param totalSize Total size of the image in bytes including the mipmaps 57259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return A ByteBuffer containing the grayscale image data with mips. 57359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws java.io.IOException If an error occured while reading from InputStream 57459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 57559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public ByteBuffer readGrayscale3D(boolean flip, int totalSize) throws IOException { 57659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer buffer = BufferUtils.createByteBuffer(totalSize * depth); 57759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 57859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bpp == 8) { 57959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.finest("Source image format: R8"); 58059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 58159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 58259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta assert bpp == pixelFormat.getBitsPerPixel(); 58359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 58459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 58559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < depth; i++) { 58659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipWidth = width; 58759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipHeight = height; 58859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 58959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int mip = 0; mip < mipMapCount; mip++) { 59059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] data = new byte[sizes[mip]]; 59159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.readFully(data); 59259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (flip) { 59359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta data = flipData(data, mipWidth * bpp / 8, mipHeight); 59459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 59559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buffer.put(data); 59659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 59759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipWidth = Math.max(mipWidth / 2, 1); 59859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipHeight = Math.max(mipHeight / 2, 1); 59959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 60059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 60159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buffer.rewind(); 60259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return buffer; 60359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 60459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 60559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 60659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Reads an uncompressed RGB or RGBA image. 60759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 60859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param flip Flip the image on the Y axis 60959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param totalSize Size of the image in bytes including mipmaps 61059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return ByteBuffer containing image data with mipmaps in the format specified by pixelFormat_ 61159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws java.io.IOException If an error occured while reading from InputStream 61259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 61359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public ByteBuffer readRGB3D(boolean flip, int totalSize) throws IOException { 61459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int redCount = count(redMask), 61559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta blueCount = count(blueMask), 61659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta greenCount = count(greenMask), 61759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta alphaCount = count(alphaMask); 61859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 61959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (redMask == 0x00FF0000 && greenMask == 0x0000FF00 && blueMask == 0x000000FF) { 62059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (alphaMask == 0xFF000000 && bpp == 32) { 62159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.finest("Data source format: BGRA8"); 62259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (bpp == 24) { 62359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.finest("Data source format: BGR8"); 62459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 62559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 62659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 62759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int sourcebytesPP = bpp / 8; 62859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int targetBytesPP = pixelFormat.getBitsPerPixel() / 8; 62959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 63059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer dataBuffer = BufferUtils.createByteBuffer(totalSize * depth); 63159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 63259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int k = 0; k < depth; k++) { 63359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // ByteBuffer dataBuffer = BufferUtils.createByteBuffer(totalSize); 63459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipWidth = width; 63559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipHeight = height; 63659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int offset = k * totalSize; 63759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] b = new byte[sourcebytesPP]; 63859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int mip = 0; mip < mipMapCount; mip++) { 63959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int y = 0; y < mipHeight; y++) { 64059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int x = 0; x < mipWidth; x++) { 64159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.readFully(b); 64259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 64359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int i = byte2int(b); 64459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 64559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte red = (byte) (((i & redMask) >> redCount)); 64659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte green = (byte) (((i & greenMask) >> greenCount)); 64759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte blue = (byte) (((i & blueMask) >> blueCount)); 64859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte alpha = (byte) (((i & alphaMask) >> alphaCount)); 64959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 65059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (flip) { 65159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataBuffer.position(offset + ((mipHeight - y - 1) * mipWidth + x) * targetBytesPP); 65259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 65359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //else 65459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // dataBuffer.position(offset + (y * width + x) * targetBytesPP); 65559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 65659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (alphaMask == 0) { 65759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataBuffer.put(red).put(green).put(blue); 65859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 65959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataBuffer.put(red).put(green).put(blue).put(alpha); 66059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 66159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 66259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 66359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 66459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta offset += (mipWidth * mipHeight * targetBytesPP); 66559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 66659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipWidth = Math.max(mipWidth / 2, 1); 66759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipHeight = Math.max(mipHeight / 2, 1); 66859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 66959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 67059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta dataBuffer.rewind(); 67159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return dataBuffer; 67259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 67359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 67459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 67559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Reads a DXT compressed image from the InputStream 67659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 67759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param totalSize Total size of the image in bytes, including mipmaps 67859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return ByteBuffer containing compressed DXT image in the format specified by pixelFormat_ 67959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws java.io.IOException If an error occured while reading from InputStream 68059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 68159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public ByteBuffer readDXT3D(boolean flip, int totalSize) throws IOException { 68259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.finest("Source image format: DXT"); 68359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 68459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer bufferAll = BufferUtils.createByteBuffer(totalSize * depth); 68559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 68659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < depth; i++) { 68759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer buffer = BufferUtils.createByteBuffer(totalSize); 68859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipWidth = width; 68959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int mipHeight = height; 69059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int mip = 0; mip < mipMapCount; mip++) { 69159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (flip) { 69259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] data = new byte[sizes[mip]]; 69359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.readFully(data); 69459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer wrapped = ByteBuffer.wrap(data); 69559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta wrapped.rewind(); 69659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer flipped = DXTFlipper.flipDXT(wrapped, mipWidth, mipHeight, pixelFormat); 69759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta flipped.rewind(); 69859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buffer.put(flipped); 69959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 70059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] data = new byte[sizes[mip]]; 70159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta in.readFully(data); 70259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buffer.put(data); 70359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 70459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 70559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipWidth = Math.max(mipWidth / 2, 1); 70659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mipHeight = Math.max(mipHeight / 2, 1); 70759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 70859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buffer.rewind(); 70959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bufferAll.put(buffer); 71059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 71159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 71259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return bufferAll; 71359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 71459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 71559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 71659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Reads the image data from the InputStream in the required format. 71759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * If the file contains a cubemap image, it is loaded as 6 ByteBuffers 71859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * (potentially containing mipmaps if they were specified), otherwise 71959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * a single ByteBuffer is returned for a 2D image. 72059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 72159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param flip Flip the image data or not. 72259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * For cubemaps, each of the cubemap faces is flipped individually. 72359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * If the image is DXT compressed, no flipping is done. 72459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return An ArrayList containing a single ByteBuffer for a 2D image, or 6 ByteBuffers for a cubemap. 72559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The cubemap ByteBuffer order is PositiveX, NegativeX, PositiveY, NegativeY, PositiveZ, NegativeZ. 72659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 72759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws java.io.IOException If an error occured while reading from the stream. 72859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 72959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public ArrayList<ByteBuffer> readData(boolean flip) throws IOException { 73059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int totalSize = 0; 73159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 73259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < sizes.length; i++) { 73359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta totalSize += sizes[i]; 73459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 73559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 73659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ArrayList<ByteBuffer> allMaps = new ArrayList<ByteBuffer>(); 73759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (depth > 1 && !texture3D) { 73859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < depth; i++) { 73959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (compressed) { 74059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta allMaps.add(readDXT2D(flip, totalSize)); 74159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (grayscaleOrAlpha) { 74259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta allMaps.add(readGrayscale2D(flip, totalSize)); 74359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 74459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta allMaps.add(readRGB2D(flip, totalSize)); 74559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 74659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 74759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (texture3D) { 74859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (compressed) { 74959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta allMaps.add(readDXT3D(flip, totalSize)); 75059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (grayscaleOrAlpha) { 75159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta allMaps.add(readGrayscale3D(flip, totalSize)); 75259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 75359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta allMaps.add(readRGB3D(flip, totalSize)); 75459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 75559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 75659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 75759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (compressed) { 75859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta allMaps.add(readDXT2D(flip, totalSize)); 75959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (grayscaleOrAlpha) { 76059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta allMaps.add(readGrayscale2D(flip, totalSize)); 76159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 76259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta allMaps.add(readRGB2D(flip, totalSize)); 76359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 76459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 76559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 76659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return allMaps; 76759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 76859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 76959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 77059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Checks if flags contains the specified mask 77159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 77259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static boolean is(int flags, int mask) { 77359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return (flags & mask) == mask; 77459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 77559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 77659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 77759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Counts the amount of bits needed to shift till bitmask n is at zero 77859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param n Bitmask to test 77959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 78059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static int count(int n) { 78159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (n == 0) { 78259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 0; 78359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 78459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 78559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int i = 0; 78659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta while ((n & 0x1) == 0) { 78759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta n = n >> 1; 78859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta i++; 78959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (i > 32) { 79059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new RuntimeException(Integer.toHexString(n)); 79159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 79259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 79359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 79459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return i; 79559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 79659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 79759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 79859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Converts a 1 to 4 sized byte array to an integer 79959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 80059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static int byte2int(byte[] b) { 80159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (b.length == 1) { 80259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return b[0] & 0xFF; 80359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (b.length == 2) { 80459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return (b[0] & 0xFF) | ((b[1] & 0xFF) << 8); 80559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (b.length == 3) { 80659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return (b[0] & 0xFF) | ((b[1] & 0xFF) << 8) | ((b[2] & 0xFF) << 16); 80759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (b.length == 4) { 80859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return (b[0] & 0xFF) | ((b[1] & 0xFF) << 8) | ((b[2] & 0xFF) << 16) | ((b[3] & 0xFF) << 24); 80959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 81059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return 0; 81159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 81259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 81359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 81459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 81559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Converts a int representing a FourCC into a String 81659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 81759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static String string(int value) { 81859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta StringBuilder buf = new StringBuilder(); 81959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 82059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buf.append((char) (value & 0xFF)); 82159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buf.append((char) ((value & 0xFF00) >> 8)); 82259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buf.append((char) ((value & 0xFF0000) >> 16)); 82359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta buf.append((char) ((value & 0xFF00000) >> 24)); 82459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 82559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return buf.toString(); 82659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 82759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta} 828