Load texture from jar

Hello everyone, I have a problem with jogl’s TextureLoader. I don’t even remember where I found the TextureLoader class, but it is using jogls texture-utilities to load a texture given a filename as a string.

I am using it with a relative path, and it works when I run it inside netbeans. However, when deploying the jar file and running it, it can’t reach the sprite file (a .png picture).

So, it works inside netbeans, but running my jar gives me this error:


felix@felix-laptop:~/NetBeansProjects/GameEngine/dist$ ./run_linux 
New Device: ALSA Software on default
New Device: ALSA Software on HDA Intel
New Device: OSS Software
New Device: Wave File Writer
file:/home/felix/NetBeansProjects/GameEngine/dist/GameEngine.jar!/com/gameengine/res/sprites/particle.png (No such file or directory)
Error loading texture file:/home/felix/NetBeansProjects/GameEngine/dist/GameEngine.jar!/com/gameengine/res/sprites/particle.png
Exception in thread "Timer-0" javax.media.opengl.GLException: java.lang.NullPointerException
	at javax.media.opengl.Threading.invokeOnOpenGLThread(Threading.java:271)
	at javax.media.opengl.GLCanvas.maybeDoSingleThreadedWorkaround(GLCanvas.java:410)
	at javax.media.opengl.GLCanvas.display(GLCanvas.java:244)
	at com.sun.opengl.util.Animator.display(Animator.java:144)
	at com.sun.opengl.util.FPSAnimator$1.run(FPSAnimator.java:95)
	at java.util.TimerThread.mainLoop(Timer.java:512)
	at java.util.TimerThread.run(Timer.java:462)
Caused by: java.lang.NullPointerException
	at com.gameengine.gutils.SpriteBuffer.<init>(SpriteBuffer.java:30)
	at com.gameengine.actors.TestPlayer.<init>(TestPlayer.java:19)
	at com.gameengine.env.GLListener.init(GLListener.java:50)
	at com.sun.opengl.impl.GLDrawableHelper.init(GLDrawableHelper.java:72)
	at javax.media.opengl.GLCanvas$InitAction.run(GLCanvas.java:418)
	at com.sun.opengl.impl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:189)
	at javax.media.opengl.GLCanvas$DisplayOnEventDispatchThreadAction.run(GLCanvas.java:452)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)


The peculiar thing is, the code for getting the relative path is identical to the code I use for getting relative paths for my sound/music files. And it works perfectly with my sound files in the jar file…

I encourage you to have a look at my gameengine if you are interested in helping me, here is the entire thing with source and compiled classes: http://www.sendspace.com/file/i9ck2w

here are the classes using the path-method, the sound-class is working, the texture one isnt:


package com.gameengine.gutils;


import com.sun.opengl.util.texture.*;
import javax.media.opengl.GL;

public class SpriteBuffer {

    private Texture spriteSheet;
    private int dimX,dimY;
    private int dimension;
    private double memory;
    private double frameWidth,frameHeight;
    public int rows,cols;
    private int[][] frames;
    private DisplaylistManager dm;
    private double pixelX,pixelY;

    /*
     * Her tager vi dimensionerne ind, og går ud fra at vi har en kvadratisk tekstur.
     * Det viser sig at være nødvendigt på ældre og dårligere grafik-chipset.
     */

    public SpriteBuffer(String filename, int rows, int cols, int dimension)
    {
        ClassLoader cl = this.getClass().getClassLoader();
        String fname = cl.getResource("com/gameengine/res/sprites/"+filename).getFile();
//        System.out.println(fname);
        spriteSheet = TextureLoader.load(fname);
        dimX = spriteSheet.getImageWidth();
        dimY = spriteSheet.getImageHeight();
        memory = spriteSheet.getEstimatedMemorySize();
        this.rows = rows;
        this.cols = cols;
        this.frameHeight = (double)dimension/dimY;
        this.frameWidth = (double)dimension/dimX;
        this.dimension = dimension/2;
        this.dm = DisplaylistManager.getInstance();
        frames = dm.getSpriteList(this);
    }



    public void dump(String filename){
        System.out.println("Filename: "+filename);
        System.out.println("pixelX: "+pixelX+" pixelY: "+pixelY);
        System.out.println("Framewidth: "+frameWidth+ " Frameheight: "+frameHeight);
        System.out.println("rows: "+rows+" cols: "+cols);
        System.out.println("dimX: "+dimX+" dimY: "+dimY);
        System.out.println("1/cols: "+frameWidth);
    }

    public int[][] getFrames(){
        return frames;
    }

    public void drawFrameNoBind(GL gl,int x, int y)
    {
        gl.glScaled(dimension, dimension, 1);
        gl.glCallList(frames[x][y]);
    }

    public void drawFrameWithBind(GL gl,int x, int y)
    {
        spriteSheet.bind();
        drawFrameNoBind(gl,x,y);
        spriteSheet.disable();
    }

    public void drawWithoutDisplaylist(GL gl,int x, int y)
    {
        spriteSheet.bind();
        dm.drawQuad(this, x, y, dimension);
    }

    public double getFrameHeight(){ return frameHeight;}
    public double getFrameWidth(){ return frameWidth;}

}


package com.gameengine.gutils;

import javax.media.opengl.*;
import com.sun.opengl.util.texture.*;
import com.sun.opengl.util.*;
import java.io.*;
 
public class TextureLoader{
 
 
	/**
	* Texture loader utilizes JOGL's provided utilities to produce a texture.
	*
	* @param fileName relative filename from execution point
	* @return a texture binded to the OpenGL context
	*/
 
	public static Texture load(String fileName){
		Texture text = null;
		try{
//                                            TextureIO.setTexRectEnabled(true);
			text = TextureIO.newTexture(new File(fileName), true);
			text.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
			text.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
		}catch(Exception e){
			System.out.println(e.getMessage());
			System.out.println("Error loading texture " + fileName);
		}
		return text;
	}
 
}


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.gameengine.sound.facade;

/**
 *
 * @author felix
 */
public class Sound
{

    private String filename;
    private boolean SFX; //true if SFX, false if BGM
    private SoundBuffer buffer;
    private int bufferNumber = -1;
    private int sourceNumber = -1;

    public Sound(String filename, boolean SFX)
    {
        ClassLoader cl = this.getClass().getClassLoader();
        if(SFX)
            this.filename = cl.getResource("com/gameengine/res/sound/sfx/"+filename).getFile();
        else
            this.filename = cl.getResource("com/gameengine/res/sound/bgm/"+filename).getFile();
        this.SFX = SFX;
        buffer = SoundBuffer.getInstance();
        bufferNumber = buffer.cacheFile(this);
        if(!isSFX())
            sourceNumber = buffer.getNextSource();
    }

    public void play()
    {
        buffer.playFile(this, 1.0f, 1.0f, false);
    }

    public void play(float pitch)
    {
        buffer.playFile(this, pitch, 1.0f, false);
    }

    public void play(float pitch, float volume)
    {
        buffer.playFile(this, pitch, volume, false);
    }

    public void play(float pitch, float volume, boolean looping)
    {
        buffer.playFile(this, pitch, volume, looping);
    }
    
    public void playAsMusic(float volume, boolean looping){
        buffer.playFile(this, 1.0f, volume, looping);        
    }

    public void changeVolume(float volume)
    {
        if(!isSFX())
        buffer.changeVolume(this, volume);
    }
    
    public int getSource(){
        return sourceNumber;
    }
    // Lav overloads
    public String getFilename()
    {
        return filename;
    }

    public boolean isSFX()
    {
        return SFX;
    }

    public boolean hasBufferNumber()
    {
        return (bufferNumber > -1);
    }

    public int getBufferNumber()
    {
        return bufferNumber;
    }
}


Hi!

Use myClass.getClassLoader().getResource(…) when the file you want to read is in another JAR than myClass, otherwise use myClass.getResource(…) (if your file is in the same JAR). I advise you to look at my source code if you don’t succeed in fixing your bug, it works both for the sounds, the textures, the WaveFront OBJ models, … I am reading yours now.

running it simply with myClass.getClassLoader().getResource(…) gives me a filenotfound, it’s strange because when I compile to jar with the original code, I also get a filenotfound with this path : “file:/home/felix/NetBeansProjects/GameEngine/dist/GameEngine.jar!/com/gameengine/res/sprites/particle.png”, which is in fact the correct path. The jar contains the particle.png in that exact position.

And the class and the resource are in the same .jar file if that helps anyone. gouessej, where exactly in your sourcecode can I find the class that loads a Texture with a relative path? I looked around in there but couldnt really find it.

this.levelTexture=TextureIO.newTexture(getClass().getResource("/pic1024/wallTexture.png"),false,TextureIO.PNG);

Hey I did a copy of your code there, replacing the path of course, and it worked like magic. I really don’t see the difference… The only thing I can think of is the fact that I was using the URL.getFile(); method before. It still gets me how it works for my ogg stuff and not for sprites, but it’s not really interesting as long as it works :slight_smile: Code like this just has to work, theres alot more difficult stuff to focus on hehe :smiley:

Thanks !

You’re welcome. My project is open source; it is better when it is useful ;D