How to load an external shader from disk to use it in JOGL?

hello

I’m looking for code how to load an external shader file from disk to use it in my JOGL program.
There is a very good code i found, while searching for hours, but that one doesn’t work.
Here is the link:
http://www.davidcornette.com/glsl/
& code:

            int v = gl.glCreateShader(GL.GL_VERTEX_SHADER);
	int f = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);

	BufferedReader brv = new BufferedReader(new FileReader("./shader/vertex.shader"));
	String vsrc = "";
	String line;
	while ((line=brv.readLine()) != null) {
	  vsrc += line + "\n";
	}
	gl.glShaderSource(v, 1, vsrc, (int[])null);
	gl.glCompileShader(v);

	BufferedReader brf = new BufferedReader(new FileReader("./shader/fragment.shader"));
	String fsrc = "";
	while ((line=brf.readLine()) != null) {
	  fsrc += line + "\n";
	}
	gl.glShaderSource(f, 1, fsrc, (int[])null);
	gl.glCompileShader(f);
	int shaderprogram = gl.glCreateProgram();
	gl.glAttachShader(shaderprogram, v);
	gl.glAttachShader(shaderprogram, f);
	gl.glLinkProgram(shaderprogram);
	gl.glValidateProgram(shaderprogram);
	gl.glUseProgram(shaderprogram);	

Unfortunately, this doesn’t work, coz of some string vs. string array issue. Does anyone have a clue how to do that properly??!?!?

Thanks very much,

Shader.java


public class Shader {

    private int id;

    public Shader(int shaderType, String path) throws IOException {
        InputStream inputStream = getClass().getResourceAsStream(path);
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

        ArrayList<String> source = new ArrayList<String>();

        while (bufferedReader.ready()) {
            source.add(bufferedReader.readLine()+"\n");
        }

        init(shaderType, source.toArray(new String[source.size()]));
    }

    public Shader(int shaderType, String[] source) {
        init(shaderType, source);
    }

    private void init(int shaderType, String[] source) {
        GL gl = GLU.getCurrentGL();

        id = gl.glCreateShader(shaderType);

        gl.glShaderSource(id, source.length, source, getLengths(source));
        gl.glCompileShader(id);

        checkCompileError(gl);
    }

    private void checkCompileError(GL gl) {
        IntBuffer status = BufferUtil.newIntBuffer(1);
        gl.glGetShaderiv(id, GL.GL_COMPILE_STATUS, status);

        if (status.get() == GL.GL_FALSE) {
            getInfoLog(gl);
        } else {
            System.out.println("Successfully compiled shader " + id);
        }
    }

    private void getInfoLog(GL gl) {
        IntBuffer infoLogLength = BufferUtil.newIntBuffer(1);
        gl.glGetShaderiv(id, GL.GL_INFO_LOG_LENGTH, infoLogLength);
        int infoLogLengthInt = infoLogLength.get();

        ByteBuffer infoLog = BufferUtil.newByteBuffer(infoLogLengthInt);
        gl.glGetShaderInfoLog(id, infoLogLengthInt, null, infoLog);

        String infoLogString =
                Charset.forName("US-ASCII").decode(infoLog).toString();
        throw new Error("Shader compile error\n" + infoLogString);
    }

    public void delete() {
        GL gl = GLU.getCurrentGL();
        gl.glDeleteShader(id);
    }

    public int getID() {
        return id;
    }

    private static IntBuffer getLengths(String[] strings) {
        IntBuffer intBuffer = BufferUtil.newIntBuffer(strings.length);
        for (int i = 0; i < strings.length; i++) {
            intBuffer.put(strings[i].length());
        }
        intBuffer.rewind();
        return intBuffer;
    }
}

Program.java

public class Program {

    private Shader[] attachedShaders = null;
    private int id;

    public Program(Shader... shaders) {
        GL gl = GLU.getCurrentGL();

        id = gl.glCreateProgram();

        attachedShaders = shaders;
        for (Shader shader : attachedShaders) {
            gl.glAttachShader(id, shader.getID());
        }
    }

    public void link() {
        GL gl = GLU.getCurrentGL();
        gl.glLinkProgram(id);
        checkLinkAndValidationErrors(gl);
    }

    private void checkLinkAndValidationErrors(GL gl) {
        IntBuffer status = BufferUtil.newIntBuffer(1);
        gl.glGetProgramiv(id, GL.GL_LINK_STATUS, status);

        if (status.get() == GL.GL_FALSE) {
            getInfoLog(gl);
        } else {
            status.rewind();
            gl.glValidateProgram(id);
            gl.glGetProgramiv(id, GL.GL_VALIDATE_STATUS, status);
            if (status.get() == GL.GL_FALSE) {
                getInfoLog(gl);
            } else {
                System.out.println("Successfully linked program " + id);
            }
        }
    }

    private void getInfoLog(GL gl) {
        IntBuffer infoLogLength = BufferUtil.newIntBuffer(1);
        gl.glGetProgramiv(id, GL.GL_INFO_LOG_LENGTH, infoLogLength);
        int infoLogLengthInt = infoLogLength.get();

        ByteBuffer infoLog = BufferUtil.newByteBuffer(infoLogLengthInt);
        gl.glGetProgramInfoLog(id, infoLogLengthInt, null, infoLog);

        String infoLogString =
                Charset.forName("US-ASCII").decode(infoLog).toString();
        throw new Error("Program compile error\n" + infoLogString);
    }

    public void delete() {
        GL gl = GLU.getCurrentGL();

        for (Shader shader : attachedShaders) {
            shader.delete();
        }

        gl.glDeleteProgram(id);
    }

    public int getID() {
        return id;
    }
}

Then you can do

            Shader vertexShader = new Shader(GL.GL_VERTEX_SHADER, "/shaders/normalizer.vert");
            Shader fragmentShader = new Shader(GL.GL_FRAGMENT_SHADER, "/shaders/normalizer.frag");

            Program normalizerProgram = new Program(vertexShader, fragmentShader);

(You must ensure you create instances of Shader and Program on the GL Thread)

Thanks very much! :wink:
Allthough by creating instances of Program & Shader in my GL Thread, i suppose you mean the init method or just below the class declaration by typing:

Program prg = new program();
Shader shady = new Shader();

??
Unfortunately, he don’t like it to create an instance of Shader. It says ‘cannot find symbol…’
I use Netbeans 6.5 with OpenGL Pack. I just creates two subclasses and put your code into it. Subclass ‘Program’ looks good but not ‘Shader’. Do you got any Idea?
Thanks anyway;-)!!

Obviously you can’t type that since both Program and Shader do not have constructors that take no arguments.

Yes I mean in either your init or display method.

        try {
            Shader vertexShader = new Shader(GL.GL_VERTEX_SHADER, "/shaders/normalizer.vert");
            Shader fragmentShader = new Shader(GL.GL_FRAGMENT_SHADER, "/shaders/normalizer.frag");

            normalizerProgram = new Program(vertexShader, fragmentShader);
            normalizerProgram.link();
        } catch (IOException ex) {
            System.out.println("Error creating normalizer program : " + ex);
        }
gl.glUseProgram(normalizerProgram.getID());

What is the exact error?

heyho!
The error is gone;-) I got an error message when i tried to create an instance of Shader by typing: "Shader shady = new Shader();
Therefore you said, thats not possible, coz i got the error message:
cannot find symbol
symbol: constructor Shader ();
location: bla.blu.bla.Shader

So right now without this, my program, including your subclasses at least show no errors at all. I can run them with of course no effect at all;-)
I just test this by let the prg loading some shaders which comes with the Shader Designer.
What i’m trying to do is:

I wrote an little scene with a texture mapping planet, over it an rotating, blended cloud sphere, including an third little texture moon, which rotate around the planet.
My FINAL Goal is: Rayleigh Scattering! So i want to setup an basic prg, where i’m able to experiment with the shaders to get that effect. There are tons of papers & stuff which explain how to program that fancy atmospheric look. Thats why i need to setup and load the functionality of shaders. Due to the Orange Book, it looked soo easy to setup the shaders;-) lol

Right now, when i move the code where the prg loads the shaderfiles into the Init method, nothing happens.
When i put that snippet into my Display Method, the program hangs instantly and throws a ‘NullPointerException’.
Thanks anyway, i think, that Shader Issue is just to high for me right now. :wink:

you just need to catch IO exception…

try {
	BufferedReader reader = new BufferedReader(new FileReader(new File( fileName)));
	String shader = "";
	String text = reader.readLine();
		
             while (text != null) {
		shader += text + "\n";
	        text = reader.readLine();
	}
	return shader;

	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}