LWJGL Forum

Programming => Lightweight Java Gaming Library => Topic started by: Schnitter on October 02, 2007, 22:35:01

Title: I cannot load *.tga files :(
Post by: Schnitter on October 02, 2007, 22:35:01
Hi,

I've trying to load *.tga files, but my texture-class, that I had just copied from a tutorial(looks like this (http://nopaste.info/2174c412fd.html)) didn't support it.
If I try to load such an file, I get the following output:
Quote
java.lang.IllegalArgumentException: Empty region!
   at javax.imageio.ImageReader.computeRegions(Unknown Source)
   at com.sun.imageio.plugins.wbmp.WBMPImageReader.read(Unknown Source)
   at javax.imageio.ImageIO.read(Unknown Source)
   at javax.imageio.ImageIO.read(Unknown Source)
   at TextureLoader.loadImage(TextureLoader.java:203)
   at TextureLoader.getTexture(TextureLoader.java:104)
   at TextureLoader.getTexture(TextureLoader.java:83)
   at Sprite.<init>(Sprite.java:19)
   at Start.<init>(Start.java:52)
   at Start.main(Start.java:94)
java.lang.NullPointerException
   at Sprite.render(Sprite.java:86)
   at Start.<init>(Start.java:67)
   at Start.main(Start.java:94)

Now I ask you, how can I implement the support of tga-files?


EDIT: Here's the Texure-Loader class: ttp://nopaste.info/11afa92c19.html (http://ttp://nopaste.info/11afa92c19.html)

Title: Re: I cannot load *.tga files :(
Post by: bobjob on October 03, 2007, 01:52:14
is the image loading for the wiki tutorial?
http://lwjgl.org/wiki/doku.php/lwjgl/tutorials/devil/loadingtextures (http://lwjgl.org/wiki/doku.php/lwjgl/tutorials/devil/loadingtextures)

if so make sure that you have downloaded the lwjgl_optional package, and that you include lwjgl_devil in with the rest of your jar's
Title: Re: I cannot load *.tga files :(
Post by: Schnitter on October 03, 2007, 07:44:04
No, it's just, because I read that *.tga files are better. And I want to have transparent sprites(Color-Keying/Color-picking).
(Is devil or java better for loading textures?)
Title: Re: I cannot load *.tga files :(
Post by: Matthias on October 03, 2007, 08:36:57
You try to lo0ad TGA files using ImageIO. But ImageIO does not know TGA files and tries to load them as WBMP files - as seen in the stack trace.

Try to download one of the many Java TGA loaders. Or better use PNG - it also supports transparency.

Ciao Matthias
Title: Re: I cannot load *.tga files :(
Post by: Evil-Devil on October 04, 2007, 11:02:09
Loading TGA without DevIL isn't that hard. Here is my TGA-Loader (handles 24/32bit/RLE compresses/uncompressed TGA images). The loader itself refers to some other classes that were posted below the TGA-Loader. It is not optimized in this version :P

TGATextureLoader.java
/* =============================================================================
* TGATextureLoader.java Bubble EngineOld
* Copyright (c) 2004 - 2005 Benjamin "Evil-Devil" Behrendt
* All rights reserved
* -----------------------------------------------------------------------------
* powered by LWJGL - Copyright (c) LWJGL Team (http://www.lwjgl.org)
* powered by JAVA - Copyright (c) Sun Microsystems (http://java.sun.com)
* -------------------------------------------------------------------------- */
package com.evildevil.bubble.core.texture;

//JAVA Imports
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.Arrays;

import com.evildevil.bubble.core.LogManager;
import com.evildevil.bubble.util.BufferUtils;

/**
* @author Benjamin "Evil-Devil" Behrendt
* @version 1.1, 25.03.2006
*/
public final class TGATextureLoader extends TextureLoader {   
    private byte[] uncompressedTGAHeader = new byte[] {           
            0,0,2,0,0,0,0,0,0,0,0,0 }; // header of uncompressed tga image
    private byte[] compressedTGAHeader = new byte[] {           
            0,0,10,0,0,0,0,0,0,0,0,0 }; // header of compressed tga image
    private byte[] compareTGAHeader = new byte[12]; // to check if we really have a tga image
    private byte[] tgaHeader = new byte[6]; // only the first 6 bytes are usefull for us
   
    private byte[] colorBuffer; // used for RLE compression
    private byte[] textureData; // will store the TGA Image data   
   
    public TGATextureLoader() {             
    }
   
    public Texture loadTexture(String  textureName) throws TextureFormatException {
        // call TextureLoader::loadTexture to ensure everything went ok!
        super.loadTexture(textureName);
       
        // determine if it is an compressed or uncompressed tga image
        compareTGAHeader = getRawHeader(compareTGAHeader.length);       
       
        // load the image corresponding to be compressed or not       
        try {
            if (Arrays.equals(compareTGAHeader,uncompressedTGAHeader)) // load uncompressed TGA
                loadUncompressedTexture(textureName);
            else if (Arrays.equals(compareTGAHeader,compressedTGAHeader)) { // load compressed TGA
                loadCompressedTexture(textureName);
            } else // none TGA -> throw new TGA exception
                throw new TGAFormatException("texture \""+textureName+"\" is no tga image");
        } catch (TGAFormatException tgafe) {
            throw tgafe; // rethrow the exception
        }               
        return texture;
    }
   
    /*
     * @see com.evildevil.bubble.core.texture.ITextureLoad#loadUncompressedTexture(java.lang.String)
     * Fixed: 25.03.2006 got the RLE encoding working.
     */
    public int loadUncompressedTexture(String textureName) throws TGAFormatException {
    LogManager.log("Attempting to load a uncompressed TGA Image.");
        texture = new Texture();
        textureFile = new File(textureName);
        try {
            // get the real header ^^
            tgaHeader = getHeader(tgaHeader.length);
            // get the texture format
            getTextureFormat();
        } catch (NullPointerException npe) {
            LogManager.logException(npe);
        } catch (TextureFormatException tfe) {
            LogManager.logException(tfe);
        }
       
        // load the binary texture data and close the stream
        textureData = loadTextureData(texture.width * texture.height * texture.bpp,true);
       
        // swap the r and g values
        /*for (int i=0; i<textureData.length; i+=texture.bpp) {
            textureData[i] ^= textureData[i+2] ^= textureData[i];
            textureData[i+2] ^= textureData[i];
        }*/
        // the image is mirrored vertical, but why?
        // one line
        //byte[] line = new byte[texture.width * texture.bpp];
        //for (int i=0; i<line.length)
       
        return createTexture(textureData);
    }
   
    public int loadCompressedTexture(String textureName) throws TGAFormatException {
        LogManager.log("Attempting to load a compressed TGA Image.");
        texture = new Texture();
        textureFile = new File(textureName);
       
        try {           
            // get the real header ^^
            tgaHeader = getHeader(tgaHeader.length);
            // get the texture format
            getTextureFormat();
        } catch (NullPointerException npe) {
            LogManager.logException(npe);
        } catch (TextureFormatException tfe) {
            LogManager.logException(tfe);
        }
       
        textureData = new byte[texture.width * texture.height * texture.bpp];
       
        final int pixelCount = texture.width * texture.height; // pixels in this image
        int currPixel = 0; // current pixel
        int currByte = 0; // current byte               
        int chunkheader;
       
        do {
        byte chunkHeader = 0; // have to be unsigned -.-
        // read
        chunkheader = loadTextureData(1)[0] & 0xFF;
       
        // RAW Chunk
        if (chunkheader < 128) {
        chunkheader++; // number of raw pixels
       
        // pixel reading
        for (int counter = 0; counter < chunkheader; counter++) {
 
        writeTextureData(loadTextureData(texture.bpp),currByte);       
       
        // increase the currByte counter
        currByte+=texture.bpp;       
        currPixel++;
    }
        } else { // RLE Header
        chunkheader -= 127;
        // read the data
        colorBuffer = loadTextureData(texture.bpp);
       
        // pixel loop
        for (int counter = 0; counter < chunkheader; counter++) {
       
        writeTextureData(colorBuffer,currByte);
       
    // increase the currByte counter
        currByte+=texture.bpp;
        currPixel++;
        }
        }
        } while (currPixel < pixelCount);
       
        return createTexture(textureData);
    }
   
    private int createTexture(byte[] data) {
    // put the data in a bytebuffer
    final ByteBuffer textureBuffer = BufferUtils.createByteBuffer(data);
        // create the glname for the new texture
    final IntBuffer glName = generateGLName();
   
    generateTexture(glName);
    bindTexture(glName.get(0));
   
    setLinearFilter();
    generateTextureImage(textureBuffer);
    texture.setGLName(glName.get(0));
   
    return glName.get(0);
    }
   
    private void writeTextureData(byte[] colorBuffer,int currentByte) {
    textureData[currentByte] = colorBuffer[2]; // R Byte
textureData[currentByte+1] = colorBuffer[1]; // G Byte
textureData[currentByte+2] = colorBuffer[0]; // B Byte

// 32bit (alpha) check
if (texture.bpp == 4)
textureData[currentByte+3] = colorBuffer[3]; // A Byte
    }
   
    public int getWidth(byte[] header) throws TextureFormatException {
        return Math.abs(header[1] * 256 + header[0]);
    }
   
    public int getHeight(byte[] header) throws TextureFormatException {       
        return Math.abs(header[3] * 256 + header[2]);       
    }
   
    public int getBitdepth(byte[] header) throws TextureFormatException {
        // we have to prove the correct bitdepth ourself, because the texture only checks
        // for zero values on width and height       
        if (header[4] != 24 && header[4] != 32)
            throw new TGAFormatException("bitdepth of the tga texture is not 24 or 32");
        return header[4];
    }
   
    public void getTextureFormat() throws TextureFormatException {       
        texture.setWidth(getWidth(tgaHeader));
        texture.setHeight(getHeight(tgaHeader));
        texture.setBitdepth(getBitdepth(tgaHeader));       
    }
}


TextureLoader.java
/* =============================================================================
* TextureLoader.java Bubble EngineOld
* Copyright (c) 2004 - 2005 Benjamin "Evil-Devil" Behrendt
* All rights reserved
* -----------------------------------------------------------------------------
* powered by LWJGL - Copyright (c) LWJGL Team (http://www.lwjgl.org)
* powered by JAVA - Copyright (c) Sun Microsystems (http://java.sun.com)
* -------------------------------------------------------------------------- */
package com.evildevil.bubble.core.texture;

// JAVA Imports
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import org.lwjgl.opengl.EXTBgra;
import org.lwjgl.opengl.GL12;

// LWJGL Imports
import static org.lwjgl.opengl.GL11.*;

// Bubble Engine Imports
import com.evildevil.bubble.core.EngineOld;
import com.evildevil.bubble.core.LogManager;
import com.evildevil.bubble.util.BufferUtils;

/**
* Textureloading implementation will be done in subclasses or within custom classes
* which implements ITextureLoad interface.
*
* @author Evil-Devil
* @version 1.0, 08.02.2005
*/
public abstract class TextureLoader implements ITextureLoad {
    protected Texture texture = null; // the texture that will holds the relevant data
    protected File textureFile = null; // the file that represents the binary texture
    private FileInputStream fis = null; // used for reading the texturedata
    private BufferedInputStream br = null;       // for webstart sucking
    protected static glFilter defaultFilter = glFilter.LINEAR; // the default filter that will used on filtering the texture
   
    public static enum glFilter {
        LINEAR, NEAREST, MIPMAPPED
    }

    /*
     * @see com.evildevil.bubble.texture.ITextureLoad#getRawHeader(byte[])
     */
    public byte[] getRawHeader(int headerSize) throws NullPointerException  {
        if (textureFile == null)
            throw new NullPointerException("texture can't be null");
        // load the raw header
        return loadTextureData(headerSize);
    }

    /*
     * @see com.evildevil.bubble.texture.ITextureLoad#getHeader(byte[])
     * @exception a NullPointerException will be thrown if the textureFile is null
     */
    public byte[] getHeader(int headerSize) {       
        if (textureFile == null)
            throw new NullPointerException("texture can't be null");
        // load the header
        return loadTextureData(headerSize);
    }

    /*
     * @see com.evildevil.bubble.texture.ITextureLoad#getWidth(byte[])
     */
    public int getWidth(byte[] header) throws TextureFormatException {
        return 0;
    }

    /*
     * @see com.evildevil.bubble.texture.ITextureLoad#getHeight(byte[])
     */
    public int getHeight(byte[] header) throws TextureFormatException {
        return 0;
    }

    /*
     * @see com.evildevil.bubble.texture.ITextureLoad#getBitDepth(byte[])
     */
    public int getBitdepth(byte[] header) throws TextureFormatException {
        return 0;
    }

    /*
     * @see com.evildevil.bubble.texture.ITextureLoad#loadTexture(java.lang.String)
     */
    public Texture loadTexture(String textureName) throws TextureFormatException {
        texture = new Texture();
        textureFile = new File(textureName);
        return null;
    }

    /*
     * @see com.evildevil.bubble.texture.ITextureLoad#loadCompressedTexture(java.lang.String)
     */
    public int loadCompressedTexture(String textureName) throws TextureFormatException {       
        return 0;
    }

    /*
     * @see com.evildevil.bubble.texture.ITextureLoad#loadUncompressedTexture(java.lang.String)
     */
    public int loadUncompressedTexture(String textureName) throws TextureFormatException {
        return 0;
    }   
   
    /*
     * use this to handle all obtainable informations with one function :)
     * But you can instead calling themselve and do the error handling :p
     */
    public abstract void getTextureFormat() throws TextureFormatException;
   
    /**
     * obtain the binary data from the texture file and return it to you
     * @param size
     * @return the loaded texturedata
     */
    public byte[] loadTextureData(int size) {       
        final byte[] textureData = new byte[size];
        try {
            if (fis == null) {
                fis = new FileInputStream(textureFile);
                if (EngineOld.isDebugMode())
                    LogManager.logDebug("FIS textureFile is \""+textureFile.getName()+"\"");
            }           
            fis.read(textureData);
            /*if (br == null) {
                br = new BufferedInputStream(
                        getClass().getResourceAsStream(textureFile.toString()));
            }
            br.read(textureData);*/
        } catch (FileNotFoundException fnfe) {
           // LogManager.logException(fnfe);
        } catch (IOException ioe) {
            LogManager.logException(ioe);
        }
        return textureData;
    }
   
    public byte[] loadTextureData(int size, boolean closeStream) {
        final byte[] textureData = loadTextureData(size);
        // close the stream if needed
        if (closeStream) {
            try {
                fis.close();
                //br.close();
            } catch (IOException ioe) {
                LogManager.logException(ioe);
            } finally {
                fis = null; // make sure with the next load there will be a new FIS created
                //br = null;
            }
        }
        return textureData;
    }
   
    protected IntBuffer generateGLName() {
        return BufferUtils.createIntBuffer(1);
    }
   
    protected void setLinearFilter() {
        // Linear Filtering
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    }
   
    protected void setNearestFilter() {
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);       
    }
   
    protected void setMipMappedFilter() {
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    }
   
    protected void setTextureFilter(glFilter filter) {
        if (filter == glFilter.LINEAR)
            setLinearFilter();
        else if (filter == glFilter.NEAREST)
            setNearestFilter();
        else if (filter == glFilter.MIPMAPPED)
            setMipMappedFilter();
    }
   
    protected void bindTexture(int glName) {
        glBindTexture(GL_TEXTURE_2D,glName);
    }
   
    protected void generateTexture(IntBuffer address) {
        glGenTextures(address);
    }
   
    protected void generateAndBindTexture(IntBuffer address) {
        generateTexture(address);
        bindTexture(address.get(0));
    }
   
    protected void generateTextureImage(ByteBuffer textureBuffer) {
        //int glColor = texture.bitdepth == 24 ? GL_RGB : GL_RGBA;
    int glColor = texture.bitdepth == 24 ? GL12.GL_BGR : GL12.GL_BGRA;
        glTexImage2D(GL_TEXTURE_2D,0,glColor,texture.width,texture.height,0,glColor,GL_UNSIGNED_BYTE,textureBuffer);
        // i guess we can free the buffer now, it isn't needed anymore
        //textureBuffer.clear();
    }
   
    protected ByteBuffer generateTextureBuffer(byte[] textureData) {
        return BufferUtils.createByteBuffer(textureData);

    }
   
    /**
     * performs all nessessary steps to create a functional gl texture, excepting texturefiltering, by calling
     * generateTexture(IntBuffer address)
     * @param address the address that is used to create a valid gl name
     * @param textureBuffer the bytebuffer that holds the binary informations about the texture file
     */
    protected void buildTexture(IntBuffer address, ByteBuffer textureBuffer) {
        generateTexture(address);
        bindTexture(address.get(0));
        generateTextureImage(textureBuffer);
    }
   
    protected void buildTexture(IntBuffer address, ByteBuffer textureBuffer, glFilter filter) {
        buildTexture(address,textureBuffer);
        setTextureFilter(filter);
    }
   
    protected void buildTexture(byte[] textureData) {
        final IntBuffer address = generateGLName();
        // assign the glName to the texture
        texture.setGLName(address.get(0));
        System.out.println(address.get());
        // call an overloaded version of buildTexture() to do the rest work
        buildTexture(address,generateTextureBuffer(textureData));
    }
   
    protected void setDefaultFilter(glFilter filter) {
        defaultFilter = filter;
    }
}