159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/*
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Copyright (c) 2009-2010 jMonkeyEngine
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * All rights reserved.
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Redistribution and use in source and binary forms, with or without
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * modification, are permitted provided that the following conditions are
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * met:
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions of source code must retain the above copyright
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   notice, this list of conditions and the following disclaimer.
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions in binary form must reproduce the above copyright
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   notice, this list of conditions and the following disclaimer in the
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   documentation and/or other materials provided with the distribution.
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   may be used to endorse or promote products derived from this software
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   without specific prior written permission.
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.texture.plugins;
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.AssetInfo;
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.AssetLoader;
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.TextureKey;
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.FastMath;
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Image;
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Image.Format;
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.BufferUtils;
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.BufferedInputStream;
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.DataInputStream;
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.IOException;
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.InputStream;
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.ByteBuffer;
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/**
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>TextureManager</code> provides static methods for building a
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <code>Texture</code> object. Typically, the information supplied is the
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * filename and the texture properties.
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Mark Powell
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Joshua Slack - cleaned, commented, added ability to read 16bit true color and color-mapped TGAs.
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Kirill Vainer - ported to jME3
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @version $Id: TGALoader.java 4131 2009-03-19 20:15:28Z blaine.dev $
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic final class TGALoader implements AssetLoader {
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // 0 - no image data in file
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public static final int TYPE_NO_IMAGE = 0;
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // 1 - uncompressed, color-mapped image
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public static final int TYPE_COLORMAPPED = 1;
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // 2 - uncompressed, true-color image
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public static final int TYPE_TRUECOLOR = 2;
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // 3 - uncompressed, black and white image
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public static final int TYPE_BLACKANDWHITE = 3;
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // 9 - run-length encoded, color-mapped image
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public static final int TYPE_COLORMAPPED_RLE = 9;
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // 10 - run-length encoded, true-color image
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public static final int TYPE_TRUECOLOR_RLE = 10;
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // 11 - run-length encoded, black and white image
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public static final int TYPE_BLACKANDWHITE_RLE = 11;
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Object load(AssetInfo info) throws IOException{
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (!(info.getKey() instanceof TextureKey))
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new IllegalArgumentException("Texture assets must be loaded using a TextureKey");
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        boolean flip = ((TextureKey)info.getKey()).isFlipY();
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        InputStream in = null;
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        try {
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            in = info.openStream();
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Image img = load(in, flip);
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return img;
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } finally {
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (in != null){
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                in.close();
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * <code>loadImage</code> is a manual image loader which is entirely
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * independent of AWT. OUT: RGB888 or RGBA8888 Image object
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return <code>Image</code> object that contains the
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *         image, either as a RGB888 or RGBA8888
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param flip
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *            Flip the image vertically
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param exp32
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *            Add a dummy Alpha channel to 24b RGB image.
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param fis
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *            InputStream of an uncompressed 24b RGB or 32b RGBA TGA
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @throws java.io.IOException
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public static Image load(InputStream in, boolean flip) throws IOException {
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        boolean flipH = false;
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // open a stream to the file
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        DataInputStream dis = new DataInputStream(new BufferedInputStream(in));
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // ---------- Start Reading the TGA header ---------- //
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // length of the image id (1 byte)
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int idLength = dis.readUnsignedByte();
12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Type of color map (if any) included with the image
12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // 0 - no color map data is included
12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // 1 - a color map is included
12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int colorMapType = dis.readUnsignedByte();
12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Type of image being read:
12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int imageType = dis.readUnsignedByte();
12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Read Color Map Specification (5 bytes)
13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Index of first color map entry (if we want to use it, uncomment and remove extra read.)
13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//        short cMapStart = flipEndian(dis.readShort());
13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        dis.readShort();
13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // number of entries in the color map
13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        short cMapLength = flipEndian(dis.readShort());
13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // number of bits per color map entry
13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int cMapDepth = dis.readUnsignedByte();
13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Read Image Specification (10 bytes)
14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // horizontal coordinate of lower left corner of image. (if we want to use it, uncomment and remove extra read.)
14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//        int xOffset = flipEndian(dis.readShort());
14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        dis.readShort();
14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // vertical coordinate of lower left corner of image. (if we want to use it, uncomment and remove extra read.)
14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//        int yOffset = flipEndian(dis.readShort());
14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        dis.readShort();
14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // width of image - in pixels
14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int width = flipEndian(dis.readShort());
14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // height of image - in pixels
14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int height = flipEndian(dis.readShort());
15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // bits per pixel in image.
15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int pixelDepth = dis.readUnsignedByte();
15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int imageDescriptor = dis.readUnsignedByte();
15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if ((imageDescriptor & 32) != 0) // bit 5 : if 1, flip top/bottom ordering
15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            flip = !flip;
15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if ((imageDescriptor & 16) != 0) // bit 4 : if 1, flip left/right ordering
15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            flipH = !flipH;
15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // ---------- Done Reading the TGA header ---------- //
15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Skip image ID
16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (idLength > 0)
16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            in.skip(idLength);
16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        ColorMapEntry[] cMapEntries = null;
16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (colorMapType != 0) {
16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // read the color map.
16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int bytesInColorMap = (cMapDepth * cMapLength) >> 3;
16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int bitsPerColor = Math.min(cMapDepth/3 , 8);
16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            byte[] cMapData = new byte[bytesInColorMap];
17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            in.read(cMapData);
17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // Only go to the trouble of constructing the color map
17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // table if this is declared a color mapped image.
17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (imageType == TYPE_COLORMAPPED || imageType == TYPE_COLORMAPPED_RLE) {
17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                cMapEntries = new ColorMapEntry[cMapLength];
17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                int alphaSize = cMapDepth - (3*bitsPerColor);
17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                float scalar = 255f / (FastMath.pow(2, bitsPerColor) - 1);
17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                float alphaScalar = 255f / (FastMath.pow(2, alphaSize) - 1);
18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                for (int i = 0; i < cMapLength; i++) {
18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    ColorMapEntry entry = new ColorMapEntry();
18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    int offset = cMapDepth * i;
18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    entry.red = (byte)(int)(getBitsAsByte(cMapData, offset, bitsPerColor) * scalar);
18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    entry.green = (byte)(int)(getBitsAsByte(cMapData, offset+bitsPerColor, bitsPerColor) * scalar);
18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    entry.blue = (byte)(int)(getBitsAsByte(cMapData, offset+(2*bitsPerColor), bitsPerColor) * scalar);
18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    if (alphaSize <= 0)
18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        entry.alpha = (byte)255;
18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    else
18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        entry.alpha = (byte)(int)(getBitsAsByte(cMapData, offset+(3*bitsPerColor), alphaSize) * alphaScalar);
19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    cMapEntries[i] = entry;
19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Allocate image data array
19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Format format;
19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        byte[] rawData = null;
20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int dl;
20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (pixelDepth == 32) {
20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            rawData = new byte[width * height * 4];
20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            dl = 4;
20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else {
20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            rawData = new byte[width * height * 3];
20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            dl = 3;
20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int rawDataIndex = 0;
20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (imageType == TYPE_TRUECOLOR) {
21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            byte red = 0;
21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            byte green = 0;
21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            byte blue = 0;
21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            byte alpha = 0;
21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // Faster than doing a 16-or-24-or-32 check on each individual pixel,
21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // just make a seperate loop for each.
21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (pixelDepth == 16) {
21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                byte[] data = new byte[2];
22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                float scalar = 255f/31f;
22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                for (int i = 0; i <= (height - 1); i++) {
22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    if (!flip)
22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawDataIndex = (height - 1 - i) * width * dl;
22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    for (int j = 0; j < width; j++) {
22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        data[1] = dis.readByte();
22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        data[0] = dis.readByte();
22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = (byte)(int)(getBitsAsByte(data, 1, 5) * scalar);
22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = (byte)(int)(getBitsAsByte(data, 6, 5) * scalar);
22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = (byte)(int)(getBitsAsByte(data, 11, 5) * scalar);
23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        if (dl == 4) {
23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            // create an alpha channel
23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            alpha = getBitsAsByte(data, 0, 1);
23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            if (alpha == 1) alpha = (byte)255;
23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            rawData[rawDataIndex++] = alpha;
23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        }
23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    }
23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                format = dl == 4 ? Format.RGBA8 : Format.RGB8;
24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } else if (pixelDepth == 24){
24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                for (int y = 0; y < height; y++) {
24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    if (!flip)
24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawDataIndex = (height - 1 - y) * width * dl;
24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    else
24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawDataIndex = y * width * dl;
24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    dis.readFully(rawData, rawDataIndex, width * dl);
24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                    for (int x = 0; x < width; x++) {
24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        //read scanline
25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                        blue = dis.readByte();
25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                        green = dis.readByte();
25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                        red = dis.readByte();
25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                        rawData[rawDataIndex++] = red;
25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                        rawData[rawDataIndex++] = green;
25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                        rawData[rawDataIndex++] = blue;
25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                    }
25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                format = Format.BGR8;
25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } else if (pixelDepth == 32){
26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                for (int i = 0; i <= (height - 1); i++) {
26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    if (!flip)
26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawDataIndex = (height - 1 - i) * width * dl;
26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    for (int j = 0; j < width; j++) {
26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        blue = dis.readByte();
26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        green = dis.readByte();
26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        red = dis.readByte();
26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        alpha = dis.readByte();
26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = red;
27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = green;
27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = blue;
27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = alpha;
27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    }
27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                format = Format.RGBA8;
27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }else{
27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                throw new IOException("Unsupported TGA true color depth: "+pixelDepth);
27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else if( imageType == TYPE_TRUECOLOR_RLE ) {
28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            byte red = 0;
28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            byte green = 0;
28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            byte blue = 0;
28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            byte alpha = 0;
28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // Faster than doing a 16-or-24-or-32 check on each individual pixel,
28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // just make a seperate loop for each.
28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if( pixelDepth == 32 ){
28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                for( int i = 0; i <= ( height - 1 ); ++i ){
28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    if( !flip ){
28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawDataIndex = ( height - 1 - i ) * width * dl;
29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    }
29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    for( int j = 0; j < width; ++j ){
29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        // Get the number of pixels the next chunk covers (either packed or unpacked)
29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        int count = dis.readByte();
29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        if( ( count & 0x80 ) != 0 ){
29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            // Its an RLE packed block - use the following 1 pixel for the next <count> pixels
29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            count &= 0x07f;
29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            j += count;
29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            blue = dis.readByte();
30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            green = dis.readByte();
30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            red = dis.readByte();
30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            alpha = dis.readByte();
30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            while( count-- >= 0 ){
30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = red;
30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = green;
30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = blue;
30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = alpha;
30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            }
30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        } else{
31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            // Its not RLE packed, but the next <count> pixels are raw.
31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            j += count;
31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            while( count-- >= 0 ){
31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                blue = dis.readByte();
31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                green = dis.readByte();
31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                red = dis.readByte();
31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                alpha = dis.readByte();
31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = red;
31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = green;
31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = blue;
32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = alpha;
32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            }
32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        }
32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    }
32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                format = Format.RGBA8;
32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } else if( pixelDepth == 24 ){
32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                for( int i = 0; i <= ( height - 1 ); i++ ){
32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    if( !flip ){
32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawDataIndex = ( height - 1 - i ) * width * dl;
33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    }
33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    for( int j = 0; j < width; ++j ){
33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        // Get the number of pixels the next chunk covers (either packed or unpacked)
33359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        int count = dis.readByte();
33459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        if( ( count & 0x80 ) != 0 ){
33559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            // Its an RLE packed block - use the following 1 pixel for the next <count> pixels
33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            count &= 0x07f;
33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            j += count;
33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            blue = dis.readByte();
33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            green = dis.readByte();
34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            red = dis.readByte();
34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            while( count-- >= 0 ){
34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = red;
34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = green;
34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = blue;
34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            }
34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        } else{
34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            // Its not RLE packed, but the next <count> pixels are raw.
34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            j += count;
34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            while( count-- >= 0 ){
35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                blue = dis.readByte();
35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                green = dis.readByte();
35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                red = dis.readByte();
35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = red;
35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = green;
35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = blue;
35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            }
35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        }
35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    }
35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                format = Format.RGB8;
36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } else if( pixelDepth == 16 ){
36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                byte[] data = new byte[ 2 ];
36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                float scalar = 255f / 31f;
36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                for( int i = 0; i <= ( height - 1 ); i++ ){
36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    if( !flip ){
36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawDataIndex = ( height - 1 - i ) * width * dl;
36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    }
36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    for( int j = 0; j < width; j++ ){
36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        // Get the number of pixels the next chunk covers (either packed or unpacked)
37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        int count = dis.readByte();
37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        if( ( count & 0x80 ) != 0 ){
37259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            // Its an RLE packed block - use the following 1 pixel for the next <count> pixels
37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            count &= 0x07f;
37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            j += count;
37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            data[1] = dis.readByte();
37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            data[0] = dis.readByte();
37759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            blue = (byte) (int) ( getBitsAsByte( data, 1, 5 ) * scalar );
37859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            green = (byte) (int) ( getBitsAsByte( data, 6, 5 ) * scalar );
37959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            red = (byte) (int) ( getBitsAsByte( data, 11, 5 ) * scalar );
38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            while( count-- >= 0 ){
38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = red;
38259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = green;
38359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = blue;
38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            }
38559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        } else{
38659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            // Its not RLE packed, but the next <count> pixels are raw.
38759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            j += count;
38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            while( count-- >= 0 ){
38959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                data[1] = dis.readByte();
39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                data[0] = dis.readByte();
39159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                blue = (byte) (int) ( getBitsAsByte( data, 1, 5 ) * scalar );
39259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                green = (byte) (int) ( getBitsAsByte( data, 6, 5 ) * scalar );
39359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                red = (byte) (int) ( getBitsAsByte( data, 11, 5 ) * scalar );
39459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = red;
39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = green;
39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                rawData[rawDataIndex++] = blue;
39759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            }
39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        }
39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    }
40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
40159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                format = Format.RGB8;
40259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } else{
40359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                throw new IOException( "Unsupported TGA true color depth: " + pixelDepth );
40459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
40559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
40659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else if( imageType == TYPE_COLORMAPPED ){
40759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int bytesPerIndex = pixelDepth / 8;
40859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
40959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (bytesPerIndex == 1) {
41059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                for (int i = 0; i <= (height - 1); i++) {
41159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    if (!flip)
41259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawDataIndex = (height - 1 - i) * width * dl;
41359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    for (int j = 0; j < width; j++) {
41459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        int index = dis.readUnsignedByte();
41559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        if (index >= cMapEntries.length || index < 0)
41659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            throw new IOException("TGA: Invalid color map entry referenced: "+index);
41759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
41859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        ColorMapEntry entry = cMapEntries[index];
41959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = entry.red;
42059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = entry.green;
42159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = entry.blue;
42259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        if (dl == 4) {
42359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            rawData[rawDataIndex++] = entry.alpha;
42459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        }
42559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
42659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    }
42759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
42859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } else if (bytesPerIndex == 2) {
42959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                for (int i = 0; i <= (height - 1); i++) {
43059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    if (!flip)
43159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawDataIndex = (height - 1 - i) * width * dl;
43259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    for (int j = 0; j < width; j++) {
43359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        int index = flipEndian(dis.readShort());
43459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        if (index >= cMapEntries.length || index < 0)
43559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            throw new IOException("TGA: Invalid color map entry referenced: "+index);
43659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
43759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        ColorMapEntry entry = cMapEntries[index];
43859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = entry.red;
43959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = entry.green;
44059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        rawData[rawDataIndex++] = entry.blue;
44159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        if (dl == 4) {
44259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                            rawData[rawDataIndex++] = entry.alpha;
44359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        }
44459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    }
44559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
44659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            } else {
44759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                throw new IOException("TGA: unknown colormap indexing size used: "+bytesPerIndex);
44859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
44959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
45059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            format = dl == 4 ? Format.RGBA8 : Format.RGB8;
45159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else {
45259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new IOException("Grayscale TGA not supported");
45359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
45459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
45559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
45659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        in.close();
45759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Get a pointer to the image memory
45859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        ByteBuffer scratch = BufferUtils.createByteBuffer(rawData.length);
45959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        scratch.clear();
46059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        scratch.put(rawData);
46159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        scratch.rewind();
46259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Create the Image object
46359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Image textureImage = new Image();
46459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        textureImage.setFormat(format);
46559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        textureImage.setWidth(width);
46659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        textureImage.setHeight(height);
46759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        textureImage.setData(scratch);
46859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return textureImage;
46959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
47059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
47159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private static byte getBitsAsByte(byte[] data, int offset, int length) {
47259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int offsetBytes = offset / 8;
47359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int indexBits = offset % 8;
47459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int rVal = 0;
47559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
47659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // start at data[offsetBytes]...  spill into next byte as needed.
47759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for (int i = length; --i >=0;) {
47859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            byte b = data[offsetBytes];
47959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int test = indexBits == 7 ? 1 : 2 << (6-indexBits);
48059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if ((b & test) != 0) {
48159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                if (i == 0)
48259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    rVal++;
48359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                else
48459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    rVal += (2 << i-1);
48559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
48659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            indexBits++;
48759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (indexBits == 8) {
48859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                indexBits = 0;
48959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                offsetBytes++;
49059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
49159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
49259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
49359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return (byte)rVal;
49459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
49559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
49659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
49759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * <code>flipEndian</code> is used to flip the endian bit of the header
49859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * file.
49959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
50059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param signedShort
50159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *            the bit to flip.
50259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return the flipped bit.
50359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
50459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private static short flipEndian(short signedShort) {
50559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int input = signedShort & 0xFFFF;
50659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return (short) (input << 8 | (input & 0xFF00) >>> 8);
50759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
50859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
50959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    static class ColorMapEntry {
51059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        byte red, green, blue, alpha;
51159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
51259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        @Override
51359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public String toString() {
51459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return "entry: "+red+","+green+","+blue+","+alpha;
51559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
51659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
51759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
518