Help! My Simple LWJGL Application won't run outside of IDE

Started by Labrasones, June 03, 2011, 22:37:20

Previous topic - Next topic

Labrasones

I'm using NetBeans to program my code, and when I run from inside the program, everything works fine. The program creates an empty window like it should. However, when I use the clean and build function, and then try and run the application outside of the IDE, nothing happens. I believe it may have something to do with the LWJGL code I have (Might be wrong). I tried giving the program a splash image, and the image pops up for a fraction of a second, and then disapears, followed by nothing. I'm still new at programming in general, so if you know whats wrong, or would like some extra information, please let me know how to get it. (For example, how do I open a console window when I run my program?) I'll post the code that I have. I've tried following all of the tutorials on building finished scripts I could find, and I'm still having this problem. Please let me know if you know whats wrong.
package test;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
public class Main {
    public static void main(String[] args) {
        Main run = new Main();
        run.start();
    }
    public void start(){
        try {
		Display.setDisplayMode(new DisplayMode(800,600));
		Display.create();
		Display.setVSyncEnabled(true);
	} catch (LWJGLException e) {
		e.printStackTrace();
		System.exit(0);
	}
        GL11.glEnable(GL11.GL_TEXTURE_2D);
	GL11.glClearColor(0.6f, 0.3f, 0.3f, 0.0f);
        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        GL11.glViewport(0,0,800,600);
	GL11.glMatrixMode(GL11.GL_MODELVIEW);
	GL11.glMatrixMode(GL11.GL_PROJECTION);
	GL11.glLoadIdentity();
	GL11.glOrtho(0, 800, 600, 0, 1, -1);
	GL11.glMatrixMode(GL11.GL_MODELVIEW);
        while(true){
            GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
            Display.update();
            Display.sync(100);
            if (Display.isCloseRequested()) {
		Display.destroy();
		System.exit(0);
            }
        }
    }
}

CodeBunny

Open command prompt, change your directory to the folder your jar is in, and use

java -jar NAME_OF_JAR.jar


That will run it in the console, and you'll see everything printed out for you.

I'm guessing the problem is you don't adequately set up LWJGL for your program; you have to make sure all of the required libraries are given to the JVM, and it requires jumping through some loops to do so. If this is the case, you'll see errors saying "no lwjgl".

Labrasones

Well, I tried the command prompt, but it gives me an error that "'java' is not recognized as an internal orexternal command, operable program or batch file."
Like I said, I'm rather new at all of this. I'm not quite sure how to get the command prompt to recognize java as something.

EDIT:A google search has shown me how to get that to work, and yes, it is giving me the no lwjgl in java.library.path. Now how do I fix it? As far as I know, I imported all the lwjgl bits I needed for my code. And you mentioned how you have to jump through some loops. Could you give me some advice on where to go from here?

CodeBunny

Okay, it's a bit involved, but here goes.

As you probably know, Java is fully cross-platform (as long as the target platform supports the JVM). However, LWJGL is a Java-OpenGL binding, and OpenGL is not cross-platform. The result is that LWJGL uses system libraries (.DLL files on windows) to manage OpenGL. It has different libraries for Windows, Mac, Linux, and Solaris (though I think we're dropping that one). To run LWJGL, you need to let the JVM have access to those libraries.

There are various ways of doing this with Java Webstart and via Applets, those are covered in tutorials. However, to get the program to run from the desktop itself, you have to do a bit of legwork. There's one magic command you need to utilize, that needs to be called in code before LWJGL is managed:

System.setProperty("org.lwjgl.librarypath", PATH_TO_DIRECTORY_CONTAINING_LIBRARIES);


This tells the JVM that the required libraries for LWJGL to function are contained in the indicated location. Point the JVM to a folder containing all needed files, and LWJGL does the rest.

However, there's still a problem. You need to ensure that the libraries are on the user's computer. A lovely solution would be to package them into a .jar file, and access them from there (it would be amazing if that worked, it really would), but the OS cannot use libraries within archive files (which a JAR is).

What I do is (in my opinion) the next best thing - I package all possible LWJGL libraries into a JAR, then, on program startup, detect which need to be given to the OS. I then use JavaIO to write them to a location on the user's computer, then pass that location to the JVM. The delay caused by this is really not very noticeable, and since all required data stays inside the JAR, the user can delete the archived libraries after each run of the program and everything still works on the next run.

Alternatively, you can run your program by passing the aforementioned library location to the JVM as a command-line argument; however that requires you to mess around with the command line. Not really difficult, but I find the method I mentioned earlier more rigorous (you can manage things in your application itself, and can detect problems and handle them when they occur) and less complicated once it works out (you run it like any other Java program, and never worry again).

Does that all make sense?

kappa

There is a tool called JarSplice that can help you with the above task. It basically creates a single executable jar for you.

To use the tool you simply select all the jars your using (your own game jar, lwjgl.jar and any other library jars). You then select all the natives you are using (all the *.dll, *.so, *.dylib, *.jnilib files) these will also be put into the jar. You then specify your main class and create the single executable jar.

Behind the scenes when this is run, it will automatically extract only the relevant OS natives and add them to the jvm, after your game is done, it will also clean up (delete) the extracted native files.

Labrasones

Thanks for your suggestions. At first read through I think I understand what to do. It may take me a while, but I think I can get it working. Thanks so much. It was really holding me back. I mean, makeing the game was fun and all, but if I can't distribute it, it makes it sort of pointless. Even if I can't get my program to work, you have explained why it didn't work, which is already a big help.

I do have one question though. If I know where the lwjgl libraries and dlls are on the target computer (which have been downloaded already), would the code snippit work without all the other fancy file work?

kappa

Quote from: Labrasones on June 04, 2011, 23:37:07
I do have one question though. If I know where the lwjgl libraries and dlls are on the target computer (which have been downloaded already), would the code snippit work without all the other fancy file work?

One thing to note is that lwjgl is a library that you need to distribute with your application and not something that has to already be present on a target computer, so yes your snippit will work provided that you bundle lwjgl with it.

CodeBunny

Yes - that's actually an important point in the method I mentioned - you store the file location to which you extracted the libraries, and you can check to see if they are there. If so, you don't have to bother extracting them, you can just jump ahead and set the JVM path.

Labrasones

Thanks for all your help. The simple program works now. Unfortunately, my main program is giving me an error that doesn't show up in the IDE >.> However, that doesn't have anything to do with no lwjgl, so I'll make a new thread if I can't get it to work. As a side note, I'll post my plan for the final program. Instead of creating the files, and then removeing them every time you start the program. I was thinking, is it possible to use a conditional path for the script? Ie. the program would find the folder the jar is in, and then add on to it /lwjgl/native/windows/dlls or something. Then, use that as the path to look for the required dlls. However, is the System.setProperty only used when you compile the program, and will always look to where the path was set to when I compile it? Because that would mean that this idea wouldent work.

CodeBunny

I think you're over-complicating it a bit. The big advantage of System.setProperty() is that you can manage it in-code (as long as you set it before you call Display.create(), you can do whatever you want), so you can get creative. However, the overall process I'm describing is very simple.

Here's a walkthrough of how I manage it:

You have a target location you want on the user's computer, either based on OS or recevied from the JVM. 2 examples:

1: Retrieving the current directory from the JVM (will cause the library to appear in the same folder from which the program is run):
String libraryPath = System.getProperty("user.dir");


2: Attempting to locate the "Application data" directory on the user's computer (varies by OS) with a fall-back value of the above (my choice):
private static String defaultDirectory()
{
	String OS = System.getProperty("os.name").toUpperCase();
	if (OS.contains("WIN"))
		return System.getenv("APPDATA");
	else if (OS.contains("MAC"))
		return System.getProperty("user.home") + "/Library/Application Support";
	else if (OS.contains("NUX"))
		return System.getProperty("user.home") + "/local";
	return System.getProperty("user.dir");
}


Then, create a File object based on this path. This will represent the directory you wish to extract to.

Then, you check if the directory has already been made. If it has, you simply set the JVM's path to the File's absolute path - you can assume that if the directory exists, you were the one who created it! If it doesn't, then and only then do you need to run the extraction.

So:

String libraryPath = defaultDirectory(); // From above.
		File library = new File(libraryPath + "/LWJGL Data");
		if (!library.exists() && library.mkdir())
			extractLibraries(library); // Extract the natives
		System.setProperty("org.lwjgl.librarypath", library.getAbsolutePath());


Make sense?

Labrasones

Well, I was hoping I wouldent have to extract anything. I'm planning on distributing this as a zip file, so my idea was that after the user extracts the entire zip folder, I could include the required files in that folder, than use the script to point to itself, wherever the user extracts it to.

CodeBunny

It'd probably be better to distribute it as a JAR file, you know - the user can double-click the file and run the application.

Don't worry about the extraction in and of itself. It really is quite fast (on my machine, initializing the Display takes longer), and it allows you to have a single JAR file as your application and be entirely self-sufficient (the user can even delete the old archive, and everything will still run fine).

That said, if you've got a working setup, go for it. I'm just pointing out that this is roughly the setup I use, and it works wonderfully in my experience.

jediTofu

I believe that you can create a JNLP file with offline file locations as well.
cool story, bro

Labrasones

Whatever I end up doing in the end, this thread has definately given me a lot of answers to some big questions I had. Thanks! My game development can continue :D

CodeBunny

:D Good to hear it was helpful.

Good luck in development!