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