diff --git a/src/java/org/lwjgl/test/opengl/shaders/Shader.java b/src/java/org/lwjgl/test/opengl/shaders/Shader.java new file mode 100644 index 00000000..ced24ee9 --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/Shader.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2002 Lightweight Java Game Library Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Created by LWJGL. + * User: spasi + * Date: 2004-03-30 + * Time: 8:41:42 pm + */ +package org.lwjgl.test.opengl.shaders; + +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.ARBProgram; +import org.lwjgl.opengl.ARBShaderObjects; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.Util; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +abstract class Shader { + + protected static IntBuffer programBuffer = BufferUtils.createIntBuffer(1); + protected static ByteBuffer fileBuffer = BufferUtils.createByteBuffer(1024 * 10); + + protected Shader() { + } + + abstract void render(); + + abstract void cleanup(); + + protected static ByteBuffer getShaderText(String file) { + ByteBuffer shader = null; + + try { + ClassLoader loader = ShadersTest.class.getClassLoader(); + InputStream inputStream = loader.getResourceAsStream("org/lwjgl/test/opengl/shaders/" + file); + + if ( inputStream == null ) + ShadersTest.kill("A shader source file could not be found: " + file); + + BufferedInputStream stream = new BufferedInputStream(inputStream); + + byte character; + while ( (character = (byte)stream.read()) != -1 ) + fileBuffer.put(character); + + stream.close(); + + fileBuffer.flip(); + + shader = BufferUtils.createByteBuffer(fileBuffer.limit()); + shader.put(fileBuffer); + + shader.clear(); + fileBuffer.clear(); + } catch (IOException e) { + ShadersTest.kill("Failed to read the shader source file: " + file, e); + } + + return shader; + } + + protected static void checkProgramError(String programFile, ByteBuffer programSource) { + if ( GL11.glGetError() == GL11.GL_INVALID_OPERATION ) { + programSource.clear(); + final byte[] bytes = new byte[programSource.capacity()]; + programSource.get(bytes); + + final int errorPos = Util.glGetInteger(ARBProgram.GL_PROGRAM_ERROR_POSITION_ARB); + int lineStart = 0; + int lineEnd = -1; + for ( int i = 0; i < bytes.length; i++ ) { + if ( bytes[i] == '\n' ) { + if ( i <= errorPos ) { + lineStart = i + 1; + } else { + lineEnd = i; + break; + } + } + } + + if ( lineEnd == -1 ) + lineEnd = bytes.length; + + ShadersTest.kill("Low-level program error in file: " + programFile + + "\n\tError line: " + new String(bytes, lineStart, lineEnd - lineStart) + + "\n\tError message: " + GL11.glGetString(ARBProgram.GL_PROGRAM_ERROR_STRING_ARB)); + } + } + + protected static int getUniformLocation(int ID, String name) { + fileBuffer.clear(); + + int length = name.length(); + + char[] charArray = new char[length]; + name.getChars(0, length, charArray, 0); + + for ( int i = 0; i < length; i++ ) + fileBuffer.put((byte)charArray[i]); + fileBuffer.put((byte)0); // Must be null-terminated. + fileBuffer.flip(); + + final int location = ARBShaderObjects.glGetUniformLocationARB(ID, fileBuffer); + + if ( location == -1 ) + throw new IllegalArgumentException("The uniform \"" + name + "\" does not exist in the Shader Program."); + + return location; + } + + protected static void printShaderObjectInfoLog(String file, int ID) { + ARBShaderObjects.glGetObjectParameterARB(ID, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB, programBuffer); + + final int logLength = programBuffer.get(0); + + if ( logLength <= 1 ) + return; + + final ByteBuffer log = BufferUtils.createByteBuffer(logLength); + + ARBShaderObjects.glGetInfoLogARB(ID, null, log); + + final char[] charArray = new char[logLength]; + for ( int i = 0; i < logLength; i++ ) + charArray[i] = (char)log.get(); + + System.out.println("\nInfo Log of Shader Object: " + file); + System.out.println("--------------------------"); + System.out.println(new String(charArray, 0, logLength)); + } + + protected static void printShaderProgramInfoLog(int ID) { + ARBShaderObjects.glGetObjectParameterARB(ID, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB, programBuffer); + + final int logLength = programBuffer.get(0); + + if ( logLength <= 1 ) + return; + + final ByteBuffer log = BufferUtils.createByteBuffer(logLength); + + ARBShaderObjects.glGetInfoLogARB(ID, null, log); + + final char[] charArray = new char[logLength]; + for ( int i = 0; i < logLength; i++ ) + charArray[i] = (char)log.get(); + + System.out.println("\nShader Program Info Log: "); + System.out.println("--------------------------"); + System.out.println(new String(charArray, 0, logLength)); + } + +} \ No newline at end of file diff --git a/src/java/org/lwjgl/test/opengl/shaders/ShaderFP.java b/src/java/org/lwjgl/test/opengl/shaders/ShaderFP.java new file mode 100644 index 00000000..40e7e77c --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/ShaderFP.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2002 Lightweight Java Game Library Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Created by LWJGL. + * User: spasi + * Date: 2004-03-30 + * Time: 9:55:38 pm + */ + +package org.lwjgl.test.opengl.shaders; + +import org.lwjgl.opengl.ARBFragmentProgram; +import org.lwjgl.opengl.ARBProgram; +import org.lwjgl.opengl.ARBVertexProgram; +import org.lwjgl.opengl.GL11; + +import java.nio.ByteBuffer; + +final class ShaderFP extends Shader { + + final String vpFile; + final ByteBuffer vpSource; + + final int vpID; + + final String fpFile; + final ByteBuffer fpSource; + + final int fpID; + + ShaderFP(final String vpShaderFile, final String fpShaderFile) { + // Initialize the vertex program. + vpFile = vpShaderFile; + vpSource = getShaderText(vpShaderFile); + + ARBProgram.glGenProgramsARB(programBuffer); + + vpID = programBuffer.get(0); + + ARBProgram.glBindProgramARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, vpID); + ARBProgram.glProgramStringARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, ARBProgram.GL_PROGRAM_FORMAT_ASCII_ARB, vpSource); + + checkProgramError(vpFile, vpSource); + + // Initialize the fragment program. + fpFile = fpShaderFile; + fpSource = getShaderText(fpShaderFile); + + ARBProgram.glGenProgramsARB(programBuffer); + + fpID = programBuffer.get(0); + + ARBProgram.glBindProgramARB(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB, fpID); + ARBProgram.glProgramStringARB(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB, ARBProgram.GL_PROGRAM_FORMAT_ASCII_ARB, fpSource); + + checkProgramError(fpFile, fpSource); + } + + void render() { + GL11.glEnable(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB); + ARBProgram.glBindProgramARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, vpID); + + GL11.glEnable(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB); + ARBProgram.glBindProgramARB(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB, fpID); + + ARBProgram.glProgramLocalParameter4fARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, 0, + ShadersTest.getSin(), ShadersTest.getSpecularity() * 8.0f, 0.0f, 0.0f); + + ARBProgram.glProgramLocalParameter4fARB(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB, 0, + ShadersTest.getSin(), ShadersTest.getSpecularity() * 8.0f, + -ShadersTest.getDisplayWidth() * 0.5f, -ShadersTest.getDisplayHeight() * 0.5f); + + ShadersTest.renderObject(); + + GL11.glDisable(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB); + GL11.glDisable(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB); + } + + void cleanup() { + programBuffer.put(0, vpID); + ARBProgram.glDeleteProgramsARB(programBuffer); + + programBuffer.put(0, fpID); + ARBProgram.glDeleteProgramsARB(programBuffer); + } + +} \ No newline at end of file diff --git a/src/java/org/lwjgl/test/opengl/shaders/ShaderFSH.java b/src/java/org/lwjgl/test/opengl/shaders/ShaderFSH.java new file mode 100644 index 00000000..7ccb1461 --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/ShaderFSH.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2002 Lightweight Java Game Library Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Created by LWJGL. + * User: spasi + * Date: 2004-03-30 + * Time: 9:55:38 pm + */ + +package org.lwjgl.test.opengl.shaders; + +import org.lwjgl.opengl.ARBShaderObjects; +import org.lwjgl.opengl.ARBVertexShader; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.ARBFragmentShader; + +import java.nio.ByteBuffer; + +final class ShaderFSH extends Shader { + + final String vshFile; + final ByteBuffer vshSource; + + final int vshID; + + final String fshFile; + final ByteBuffer fshSource; + + final int fshID; + + final int programID; + + final int uniformLocation; + + ShaderFSH(final String vshFile, final String fshFile) { + // Initialize the vertex shader. + this.vshFile = vshFile; + vshSource = getShaderText(vshFile); + + vshID = ARBShaderObjects.glCreateShaderObjectARB(ARBVertexShader.GL_VERTEX_SHADER_ARB); + ARBShaderObjects.glShaderSourceARB(vshID, vshSource); + ARBShaderObjects.glCompileShaderARB(vshID); + + printShaderObjectInfoLog(this.vshFile, vshID); + + ARBShaderObjects.glGetObjectParameterARB(vshID, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, programBuffer); + if ( programBuffer.get(0) == GL11.GL_FALSE ) + ShadersTest.kill("A compilation error occured in a vertex shader."); + + // Initialize the fragment shader. + this.fshFile = fshFile; + fshSource = getShaderText(fshFile); + + fshID = ARBShaderObjects.glCreateShaderObjectARB(ARBFragmentShader.GL_FRAGMENT_SHADER_ARB); + ARBShaderObjects.glShaderSourceARB(fshID, fshSource); + ARBShaderObjects.glCompileShaderARB(fshID); + + printShaderObjectInfoLog(this.fshFile, fshID); + + ARBShaderObjects.glGetObjectParameterARB(fshID, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, programBuffer); + if ( programBuffer.get(0) == GL11.GL_FALSE ) + ShadersTest.kill("A compilation error occured in a fragment shader."); + + // Initialize the shader program. + programID = ARBShaderObjects.glCreateProgramObjectARB(); + + ARBShaderObjects.glAttachObjectARB(programID, vshID); + ARBShaderObjects.glAttachObjectARB(programID, fshID); + + ARBShaderObjects.glLinkProgramARB(programID); + + printShaderProgramInfoLog(programID); + + ARBShaderObjects.glGetObjectParameterARB(programID, ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB, programBuffer); + if ( programBuffer.get(0) == GL11.GL_FALSE ) + ShadersTest.kill("A linking error occured in a shader program."); + + uniformLocation = getUniformLocation(programID, "UNIFORMS"); + } + + void render() { + ARBShaderObjects.glUseProgramObjectARB(programID); + + ARBShaderObjects.glUniform4fARB(uniformLocation, + ShadersTest.getSin(), ShadersTest.getSpecularity() * 8.0f, + -ShadersTest.getDisplayWidth() * 0.5f, -ShadersTest.getDisplayHeight() * 0.5f); + + ShadersTest.renderObject(); + + ARBShaderObjects.glUseProgramObjectARB(0); + } + + void cleanup() { + ARBShaderObjects.glDetachObjectARB(programID, vshID); + ARBShaderObjects.glDetachObjectARB(programID, fshID); + + ARBShaderObjects.glDeleteObjectARB(vshID); + ARBShaderObjects.glDeleteObjectARB(fshID); + + ARBShaderObjects.glDeleteObjectARB(programID); + } + +} \ No newline at end of file diff --git a/src/java/org/lwjgl/test/opengl/shaders/ShaderVP.java b/src/java/org/lwjgl/test/opengl/shaders/ShaderVP.java new file mode 100644 index 00000000..1f28b2d2 --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/ShaderVP.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002 Lightweight Java Game Library Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Created by LWJGL. + * User: spasi + * Date: 2004-03-30 + * Time: 9:55:38 pm + */ + +package org.lwjgl.test.opengl.shaders; + +import org.lwjgl.opengl.ARBProgram; +import org.lwjgl.opengl.ARBVertexProgram; +import org.lwjgl.opengl.GL11; + +import java.nio.ByteBuffer; + +final class ShaderVP extends Shader { + + final String file; + final ByteBuffer source; + + final int ID; + + ShaderVP(final String shaderFile) { + file = shaderFile; + source = getShaderText(shaderFile); + + ARBProgram.glGenProgramsARB(programBuffer); + + ID = programBuffer.get(0); + + ARBProgram.glBindProgramARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, ID); + ARBProgram.glProgramStringARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, ARBProgram.GL_PROGRAM_FORMAT_ASCII_ARB, source); + + checkProgramError(file, source); + } + + void render() { + GL11.glEnable(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB); + ARBProgram.glBindProgramARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, ID); + + ARBProgram.glProgramLocalParameter4fARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, 0, + ShadersTest.getSin(), ShadersTest.getSpecularity() * 8.0f, 0.0f, 0.0f); + + ShadersTest.renderObject(); + + GL11.glDisable(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB); + } + + void cleanup() { + programBuffer.put(0, ID); + ARBProgram.glDeleteProgramsARB(programBuffer); + } + +} \ No newline at end of file diff --git a/src/java/org/lwjgl/test/opengl/shaders/ShaderVSH.java b/src/java/org/lwjgl/test/opengl/shaders/ShaderVSH.java new file mode 100644 index 00000000..f3a173cb --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/ShaderVSH.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2002 Lightweight Java Game Library Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Created by LWJGL. + * User: spasi + * Date: 2004-03-30 + * Time: 9:55:38 pm + */ + +package org.lwjgl.test.opengl.shaders; + +import org.lwjgl.opengl.ARBShaderObjects; +import org.lwjgl.opengl.ARBVertexShader; +import org.lwjgl.opengl.GL11; + +import java.nio.ByteBuffer; + +final class ShaderVSH extends Shader { + + final String file; + final ByteBuffer source; + + final int shaderID; + final int programID; + + final int uniformLocation; + + ShaderVSH(final String shaderFile) { + file = shaderFile; + source = getShaderText(shaderFile); + + shaderID = ARBShaderObjects.glCreateShaderObjectARB(ARBVertexShader.GL_VERTEX_SHADER_ARB); + ARBShaderObjects.glShaderSourceARB(shaderID, source); + ARBShaderObjects.glCompileShaderARB(shaderID); + + printShaderObjectInfoLog(file, shaderID); + + ARBShaderObjects.glGetObjectParameterARB(shaderID, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, programBuffer); + if ( programBuffer.get(0) == GL11.GL_FALSE ) + ShadersTest.kill("A compilation error occured in a vertex shader."); + + programID = ARBShaderObjects.glCreateProgramObjectARB(); + + ARBShaderObjects.glAttachObjectARB(programID, shaderID); + ARBShaderObjects.glLinkProgramARB(programID); + + printShaderProgramInfoLog(programID); + + ARBShaderObjects.glGetObjectParameterARB(programID, ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB, programBuffer); + if ( programBuffer.get(0) == GL11.GL_FALSE ) + ShadersTest.kill("A linking error occured in a shader program."); + + uniformLocation = getUniformLocation(programID, "UNIFORMS"); + } + + void render() { + ARBShaderObjects.glUseProgramObjectARB(programID); + + ARBShaderObjects.glUniform2fARB(uniformLocation, ShadersTest.getSin(), ShadersTest.getSpecularity() * 8.0f); + + ShadersTest.renderObject(); + + ARBShaderObjects.glUseProgramObjectARB(0); + } + + void cleanup() { + ARBShaderObjects.glDetachObjectARB(programID, shaderID); + + ARBShaderObjects.glDeleteObjectARB(shaderID); + ARBShaderObjects.glDeleteObjectARB(programID); + } + +} \ No newline at end of file diff --git a/src/java/org/lwjgl/test/opengl/shaders/ShadersTest.java b/src/java/org/lwjgl/test/opengl/shaders/ShadersTest.java new file mode 100644 index 00000000..39a15760 --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/ShadersTest.java @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2002 Lightweight Java Game Library Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Created by LWJGL. + * User: spasi + * Date: 2004-03-30 + * Time: 8:41:42 pm + */ + +package org.lwjgl.test.opengl.shaders; + +import org.lwjgl.*; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GLContext; +import org.lwjgl.opengl.Window; +import org.lwjgl.opengl.glu.GLU; +import org.lwjgl.opengl.glu.Sphere; + +import java.nio.FloatBuffer; + +public final class ShadersTest { + + private static DisplayMode displayMode; + + private static boolean run = true; + + private static final FloatBuffer vectorBuffer = BufferUtils.createFloatBuffer(4); + + private static Sphere sphere; + + private static Shader shader; + + private static float frameTime; + + private static float angle; + private static float sin; + private static int specularity = 4; + + private ShadersTest() { + } + + public static void main(String[] args) { + initialize(args); + + long frameStart; + long lastFrameTime = 0; + + while ( run ) { + if ( Window.isMinimized() ) + Thread.yield(); + else { + // This is the current frame time. + frameStart = Sys.getTime(); + + // How many seconds passed since last frame. + frameTime = (float)((frameStart - lastFrameTime) / (double)Sys.getTimerResolution()); + + lastFrameTime = frameStart; + + angle += frameTime * 90.0f; + sin = (float)Math.sin(Math.toRadians(angle)); + + handleIO(); + + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); + + if ( shader != null ) + shader.render(); + else + renderObject(); + + // Restore camera position. + GL11.glPopMatrix(); + GL11.glPushMatrix(); + } + + Window.update(); + + if ( Window.isCloseRequested() ) + break; + } + + cleanup(); + } + + private static void initialize(String[] args) { + if ( args.length != 1 ) + argsError(); + + DisplayMode[] modes = Display.getAvailableDisplayModes(); + + DisplayMode displayMode; + + displayMode = chooseMode(modes, 1024, 768, 32); + if ( displayMode == null ) + displayMode = chooseMode(modes, 800, 600, 32); + if ( displayMode == null ) + displayMode = chooseMode(modes, 1024, 768, 16); + if ( displayMode == null ) + displayMode = chooseMode(modes, 800, 600, 16); + if ( displayMode == null ) + kill("Failed to set an appropriate display mode."); + + try { + System.out.println("Setting display mode to: " + displayMode); + Display.setDisplayMode(displayMode); + Window.create("OpenGL Shaders Test", displayMode.bpp, 8, 24, 0); + } catch (LWJGLException e) { + kill(e.getMessage()); + } + + ShadersTest.displayMode = displayMode; + + if ( "NONE".equalsIgnoreCase(args[0]) ) { + shader = null; + } else if ( "VP".equalsIgnoreCase(args[0]) ) { + if ( !GLContext.GL_ARB_vertex_program ) + kill("The ARB_vertex_program extension is not supported."); + + shader = new ShaderVP("shaderVP.vp"); + } else if ( "FP".equalsIgnoreCase(args[0]) ) { + if ( !GLContext.GL_ARB_vertex_program ) + kill("The ARB_vertex_program extension is not supported."); + if ( !GLContext.GL_ARB_fragment_program ) + kill("The ARB_fragment_program extension is not supported."); + + shader = new ShaderFP("shaderFP.vp", "shaderFP.fp"); + } else if ( "VSH".equalsIgnoreCase(args[0]) ) { + if ( !GLContext.GL_ARB_vertex_shader ) + kill("The ARB_vertex_shader extension is not supported."); + + shader = new ShaderVSH("shaderVSH.vsh"); + } else if ( "FSH".equalsIgnoreCase(args[0]) ) { + if ( !GLContext.GL_ARB_vertex_shader ) + kill("The ARB_vertex_shader extension is not supported."); + if ( !GLContext.GL_ARB_fragment_shader ) + kill("The ARB_fragment_shader extension is not supported."); + + shader = new ShaderFSH("shaderFSH.vsh", "shaderFSH.fsh"); + } else { + argsError(); + } + + GL11.glViewport(0, 0, displayMode.width, displayMode.height); + + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glLoadIdentity(); + GLU.gluPerspective(45, displayMode.width / (float)displayMode.height, 1.0f, 10.0f); + + GL11.glMatrixMode(GL11.GL_MODELVIEW); + GL11.glLoadIdentity(); + + // Setup camera position. + GL11.glTranslatef(0.0f, 0.0f, -4.0f); + GL11.glRotatef(15.0f, 1.0f, 0.0f, 0.0f); + GL11.glPushMatrix(); + + GL11.glClearDepth(1.0f); + GL11.glDepthFunc(GL11.GL_LEQUAL); + + GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST); + + GL11.glFrontFace(GL11.GL_CCW); + GL11.glPolygonMode(GL11.GL_FRONT, GL11.GL_FILL); + + GL11.glCullFace(GL11.GL_BACK); + GL11.glEnable(GL11.GL_CULL_FACE); + + GL11.glAlphaFunc(GL11.GL_NOTEQUAL, 0.0f); + GL11.glEnable(GL11.GL_ALPHA_TEST); + + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glEnable(GL11.GL_BLEND); + + // Setup lighting for when we have fixed function fragment rendering. + GL11.glShadeModel(GL11.GL_SMOOTH); + + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_LIGHT0); + + vectorBuffer.clear(); + vectorBuffer.put(1.0f).put(1.0f).put(1.0f).put(1.0f); + vectorBuffer.clear(); + GL11.glLight(GL11.GL_LIGHT0, GL11.GL_DIFFUSE, vectorBuffer); + + vectorBuffer.put(1.0f).put(1.0f).put(1.0f).put(1.0f); + vectorBuffer.clear(); + GL11.glLight(GL11.GL_LIGHT0, GL11.GL_AMBIENT, vectorBuffer); + + vectorBuffer.put(1.0f).put(1.0f).put(0.5f).put(1.0f); + vectorBuffer.clear(); + GL11.glLight(GL11.GL_LIGHT0, GL11.GL_SPECULAR, vectorBuffer); + + vectorBuffer.put(-1.0f / 3.0f).put(1.0f / 3.0f).put(1.0f / 3.0f).put(0.0f); // Infinite + vectorBuffer.clear(); + GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, vectorBuffer); + + vectorBuffer.put(0.2f).put(0.2f).put(0.2f).put(1.0f); + vectorBuffer.clear(); + GL11.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, vectorBuffer); + + sphere = new Sphere(); + } + + private static void handleIO() { + if ( Keyboard.getNumKeyboardEvents() != 0 ) { + while ( Keyboard.next() ) { + if ( Keyboard.getEventKeyState() ) + continue; + + switch ( Keyboard.getEventKey() ) { + case Keyboard.KEY_EQUALS: + if ( specularity < 8 ) + specularity++; + break; + case Keyboard.KEY_MINUS: + if ( specularity > 1 ) + specularity--; + break; + case Keyboard.KEY_ESCAPE: + run = false; + break; + } + } + } + + while ( Mouse.next() ) ; + } + + static int getDisplayWidth() { + return displayMode.width; + } + + static int getDisplayHeight() { + return displayMode.height; + } + + static float getSin() { + return sin; + } + + static int getSpecularity() { + return specularity; + } + + static void renderObject() { + GL11.glColor3b((byte)255, (byte)255, (byte)255); + sphere.draw(1.0f, 32, 32); + } + + private static DisplayMode chooseMode(DisplayMode[] modes, int width, int height, int bpp) { + DisplayMode bestMode = null; + + for ( int i = 0; i < modes.length; i++ ) { + DisplayMode mode = modes[i]; + if ( mode.width == width && mode.height == height && mode.bpp == bpp && mode.freq <= 85 ) { + if ( bestMode == null || bestMode.freq < mode.freq ) + bestMode = mode; + } + } + + return bestMode; + } + + private static void cleanup() { + // This is not necessary, just showing how to properly delete a program/shader. + if ( shader != null ) + shader.cleanup(); + + if ( Window.isCreated() ) + Window.destroy(); + + Display.resetDisplayMode(); + } + + private static void argsError() { + System.out.println("\nInvalid program arguments."); + System.out.println("\nUsage: ShadersTest , where argument can be one of the following:\n"); + System.out.println("none\t- Use fixed function rendering."); + System.out.println("vp\t- Use ARB_vertex_program (low-level) only."); + System.out.println("vsh\t- Use ARB_vertex_shader (GLSL) only."); + System.out.println("fp\t- Use ARB_vertex_program + ARB_fragment_program (low-level)."); + System.out.println("fsh\t- Use ARB_vertex_shader + ARB_fragment_shader (GLSL)."); + + cleanup(); + System.exit(-1); + } + + static void kill(String reason) { + System.out.println("The ShaderTest program was terminated because an error occured.\n"); + System.out.println("Reason: " + (reason == null ? "Unknown" : reason)); + + cleanup(); + System.exit(-1); + } + + static void kill(String reason, Throwable t) { + System.out.println("The ShaderTest program was terminated because an exception occured.\n"); + System.out.println("Reason: " + reason == null ? "Unknown" : reason); + + System.out.println("Exception message: " + t.getMessage()); + + cleanup(); + System.exit(-1); + } + +} \ No newline at end of file diff --git a/src/java/org/lwjgl/test/opengl/shaders/shaderFP.fp b/src/java/org/lwjgl/test/opengl/shaders/shaderFP.fp new file mode 100644 index 00000000..65c3ed2e --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/shaderFP.fp @@ -0,0 +1,40 @@ +!!ARBfp1.0 +OPTION ARB_precision_hint_fastest; + +ATTRIB winPos = fragment.position; +ATTRIB iDots = fragment.texcoord[0]; + +PARAM ambience = state.lightmodel.ambient; + +PARAM specularColor = state.light[0].specular; + +PARAM UNIFORMS = program.local[0]; + +TEMP temp; + +OUTPUT oColor = result.color; + +# Offset window-space fragment position. +ADD temp.xyz, winPos, UNIFORMS.zwxx; +# Normalize position. +DP3 temp.w, temp, temp; +RSQ temp.w, temp.w; +MUL temp.xy, temp, temp.w; + +# Multiply with current sin. +MUL temp.xy, temp, UNIFORMS.x; +# {-1..1} => {0..1} +MAD temp.xy, temp, 0.5, 0.5; +# Intensify colors. +MUL temp.xy, temp, 2.0; +MOV temp.z, 1.0; + +# Accumulate color contributions. +MAD temp.xyz, iDots.x, temp, ambience; +# Calculate ^ +POW temp.w, iDots.y, UNIFORMS.y; +MAD oColor.xyz, temp.w, specularColor, temp; + +MOV oColor.w, 1.0; + +END \ No newline at end of file diff --git a/src/java/org/lwjgl/test/opengl/shaders/shaderFP.vp b/src/java/org/lwjgl/test/opengl/shaders/shaderFP.vp new file mode 100644 index 00000000..d6407f9d --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/shaderFP.vp @@ -0,0 +1,37 @@ +!!ARBvp1.0 + +ATTRIB iPos = vertex.position; +ATTRIB iNormal = vertex.normal; + +PARAM mvp[4] = { state.matrix.mvp }; +PARAM mvIT[4] = { state.matrix.modelview.invtrans }; + +PARAM lightDir = state.light[0].position; +PARAM halfDir = state.light[0].half; + +PARAM UNIFORMS = program.local[0]; + +TEMP normal, dots; + +OUTPUT oPos = result.position; +OUTPUT oDots = result.texcoord[0]; + +# Transform the vertex to clip coordinates. +DP4 oPos.x, mvp[0], iPos; +DP4 oPos.y, mvp[1], iPos; +DP4 oPos.z, mvp[2], iPos; +DP4 oPos.w, mvp[3], iPos; + +# Transform the normal to eye coordinates. +DP3 normal.x, mvIT[0], iNormal; +DP3 normal.y, mvIT[1], iNormal; +DP3 normal.z, mvIT[2], iNormal; + +# Compute diffuse and specular dot products and clamp them. +DP3 dots.x, normal, lightDir; +MAX oDots.x, dots.x, 0.0; + +DP3 dots.y, normal, halfDir; +MAX oDots.y, dots.y, 0.0; + +END \ No newline at end of file diff --git a/src/java/org/lwjgl/test/opengl/shaders/shaderFSH.fsh b/src/java/org/lwjgl/test/opengl/shaders/shaderFSH.fsh new file mode 100644 index 00000000..9971f980 --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/shaderFSH.fsh @@ -0,0 +1,21 @@ +uniform vec4 UNIFORMS; + +varying vec2 dots; + +void main(void) { + // Offset window-space fragment position. + vec3 color2D = vec3(gl_FragCoord + UNIFORMS.zwxx); + + // Normalize position. + // Multiply with current sin. + color2D.xy = normalize(color2D) * UNIFORMS.x; + // {-1..1} => {0..1} & Intensify colors. + color2D.xy = (vec2(color2D) * 0.5 + 0.5) * 2.0; + color2D.z = 1.0; + + // Accumulate color contributions. + // Hardcoded ambience and specular color, due to buggy drivers. + color2D = dots.x * color2D + vec3(0.2, 0.2, 0.2); + gl_FragColor.rgb = pow(dots.y, UNIFORMS.y) * vec3(1.0, 1.0, 0.5) + color2D; + gl_FragColor.a = 1.0; +} \ No newline at end of file diff --git a/src/java/org/lwjgl/test/opengl/shaders/shaderFSH.vsh b/src/java/org/lwjgl/test/opengl/shaders/shaderFSH.vsh new file mode 100644 index 00000000..b64c94ab --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/shaderFSH.vsh @@ -0,0 +1,11 @@ +varying vec2 dots; + +void main(void) { + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + + vec3 normal = gl_NormalMatrix * gl_Normal; + + // Pass the dot products to the fragment shader. + dots.x = max(dot(normal, gl_LightSource[0].position), 0.0); + dots.y = max(dot(normal, gl_LightSource[0].halfVector), 0.0); +} \ No newline at end of file diff --git a/src/java/org/lwjgl/test/opengl/shaders/shaderVP.vp b/src/java/org/lwjgl/test/opengl/shaders/shaderVP.vp new file mode 100644 index 00000000..efb5ed12 --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/shaderVP.vp @@ -0,0 +1,59 @@ +!!ARBvp1.0 + +ATTRIB iPos = vertex.position; +ATTRIB iNormal = vertex.normal; + +PARAM mvp[4] = { state.matrix.mvp }; +PARAM mvIT[4] = { state.matrix.modelview.invtrans }; + +PARAM ambience = state.lightmodel.ambient; + +PARAM lightDir = state.light[0].position; +PARAM halfDir = state.light[0].half; +PARAM diffuseColor = state.light[0].diffuse; +PARAM specularColor = state.light[0].specular; + +PARAM UNIFORMS = program.local[0]; + +TEMP temp, temp2, normal, dots; + +OUTPUT oPos = result.position; +OUTPUT oColor = result.color; + +# Transform the vertex to clip coordinates. +DP4 oPos.x, mvp[0], iPos; +DP4 oPos.y, mvp[1], iPos; +DP4 oPos.z, mvp[2], iPos; +DP4 oPos.w, mvp[3], iPos; + +# Transform the normal to eye coordinates. +DP3 normal.x, mvIT[0], iNormal; +DP3 normal.y, mvIT[1], iNormal; +DP3 normal.z, mvIT[2], iNormal; + +# Compute diffuse and specular dot products and use LIT to compute +# lighting coefficients. +DP3 dots.x, normal, lightDir; +DP3 dots.y, normal, halfDir; +MOV dots.w, UNIFORMS.y; +LIT dots, dots; + +# Normalize position, to get a {-1..1} value for each vertex. +DP3 temp.w, iPos, iPos; +RSQ temp.w, temp.w; +MUL temp.xyz, iPos, temp.w; + +# Multiply with current sin. +MUL temp.xyz, temp, UNIFORMS.x; +# {-1..1} => {0..1} +MAD temp.xyz, temp, 0.5, 0.5; +# Intensify colors. +MUL temp.xyz, temp, 2.0; + +# Accumulate color contributions. +MAD temp.xyz, dots.y, temp, ambience; +MAD oColor.xyz, dots.z, specularColor, temp; +MOV oColor.w, 1.0; + + +END \ No newline at end of file diff --git a/src/java/org/lwjgl/test/opengl/shaders/shaderVSH.vsh b/src/java/org/lwjgl/test/opengl/shaders/shaderVSH.vsh new file mode 100644 index 00000000..e33fca3c --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/shaders/shaderVSH.vsh @@ -0,0 +1,22 @@ +uniform vec2 UNIFORMS; + +void main(void) { + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + + vec3 normal = gl_NormalMatrix * gl_Normal; + + float diffuseDot = max(dot(normal, gl_LightSource[0].position), 0.0); + float specularDot = max(dot(normal, gl_LightSource[0].halfVector), 0.0); + specularDot = pow(specularDot, UNIFORMS.y); + + // Normalize position, to get a {-1..1} value for each vertex. + // Multiply with current sin. + vec3 color3D = normalize(vec3(gl_Vertex)) * UNIFORMS.x; + // {-1..1} => {0..1} & Intensify colors. + color3D = (color3D * 0.5 + 0.5) * 2.0; + + // Accumulate color contributions. + color3D = diffuseDot * color3D + gl_LightModel.ambient; + gl_FrontColor.rgb = specularDot * gl_LightSource[0].specular + color3D; + gl_FrontColor.a = 1.0; +} \ No newline at end of file