com.github.ryancwilliams.WJ3dPL.graphics.GLUtils.ShaderProgram.java Source code

Java tutorial

Introduction

Here is the source code for com.github.ryancwilliams.WJ3dPL.graphics.GLUtils.ShaderProgram.java

Source

/*
 * Copyright 2013 ryancwilliams.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.ryancwilliams.WJ3dPL.graphics.GLUtils;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextCapabilities;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GLContext;

/**
 * 
 * @author ryancwilliams
 */
public class ShaderProgram {

    public final int program;

    /**
     * Creates a new shader program with the provided vertex and fragment 
     * shader source code.
     * The provided attributes are linked to this program.
     * @param vertexShaderSource the source code of the vertex shader.
     * @param fragmentShaderSource the source code of the fragment shader.
     * @param attributes The Vertex Attributes to bind to this shader program.
     * @throws LWJGLException If their is a issue compiling the shaders or 
     * creating or binding the program.  
     */
    public ShaderProgram(String vertexShaderSource, String fragmentShaderSource, List<VertexAttribute> attributes)
            throws LWJGLException {
        //Check if any of the sourcecode paramaters are null
        if (fragmentShaderSource == null || fragmentShaderSource == null) {
            //If any of the sourcecode paramaters were null
            //throw a exception
            throw new IllegalArgumentException("Shader source may not be null");
        }
        //Check if shaders are not supported
        if (!ShaderProgram.isSupported()) {
            //If shaders are not supported
            //throw a exception
            throw new LWJGLException("Shaders are not supported on this device");
        }

        //Compile the shaders
        int vertexShader = ShaderProgram.compileShader(GL20.GL_VERTEX_SHADER, vertexShaderSource);
        int fragmentShader = ShaderProgram.compileShader(GL20.GL_FRAGMENT_SHADER, fragmentShaderSource);

        //Create the program
        this.program = GL20.glCreateProgram();

        //Bind the attrib locations
        //Check if attributes were provided
        if (attributes != null) {
            //For each attribute
            for (VertexAttribute attribute : attributes) {
                //Check if the attribute is not null
                if (attribute != null) {
                    //bind the attribute
                    GL20.glBindAttribLocation(this.program, attribute.index, attribute.name);
                }
            }
        }

        //Attach the shaders
        GL20.glAttachShader(this.program, vertexShader);
        GL20.glAttachShader(this.program, fragmentShader);

        //Link the program
        GL20.glLinkProgram(this.program);

        //Get if the program link was good
        boolean programLink = GL20.glGetProgrami(this.program, GL20.GL_LINK_STATUS) == GL11.GL_TRUE;

        //Get the log
        String infoLog = GL20.glGetProgramInfoLog(this.program,
                GL20.glGetProgrami(this.program, GL20.GL_INFO_LOG_LENGTH));

        //Log the log if a log is present
        if (infoLog != null && infoLog.trim().length() != 0) {
            Logger.getLogger(ShaderProgram.class.getName()).log(Level.FINEST, infoLog);
        }

        //Check if program link is bad
        if (programLink == false) {
            throw new LWJGLException("Failure in linking program. Error log:\n" + infoLog);
        }

        //detach and delete the shaders which are no longer needed
        GL20.glDetachShader(this.program, vertexShader);
        GL20.glDetachShader(this.program, fragmentShader);
        GL20.glDeleteShader(vertexShader);
        GL20.glDeleteShader(fragmentShader);
    }

    /**
     * Checks if vertex and fragment shaders are supported.
     * @return true if vertex and fragment shaders are supported.
     */
    public static boolean isSupported() {
        // Get Capabilities
        ContextCapabilities capabilities = GLContext.getCapabilities();
        return capabilities.GL_ARB_shader_objects && capabilities.GL_ARB_vertex_shader
                && capabilities.GL_ARB_fragment_shader;
    }

    /**
     * Compiles a shader from the provided source and returns its OpenGL handle.
     * @param type the shader type to use when compiling.
     * @param source the source to compile.
     * @return the OpenGL handle for this shader.
     * @throws LWJGLException if compilation was unsuccessful
     */
    public static int compileShader(int type, String source) throws LWJGLException {
        //Create the shader ponter varable
        int shader;
        //Create the shader
        shader = GL20.glCreateShader(type);

        //load the source
        GL20.glShaderSource(shader, source);
        //compile the source
        GL20.glCompileShader(shader);

        //Get if the compile was good
        boolean compile = GL20.glGetShaderi(shader, GL20.GL_COMPILE_STATUS) == GL11.GL_TRUE;

        //Get the log
        String infoLog = GL20.glGetShaderInfoLog(shader, GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH));

        //Log the log if a log is present
        if (infoLog != null && infoLog.trim().length() != 0) {
            Logger.getLogger(ShaderProgram.class.getName()).log(Level.FINEST, infoLog);
        }

        //Check if the compiling was unsuccessful
        if (compile == false) {
            //throw a exception if unsuccessful
            throw new LWJGLException(
                    "Failure in compiling " + ShaderProgram.typeToString(type) + ". Error log:\n" + infoLog);
        }

        //Return the OpenGL pointer for the shader
        return shader;
    }

    /**
     * Converts the provided shader type value to a string.
     * @param type the type value to convert.
     * @return the type value as a String.
     */
    public static String typeToString(int type) {
        switch (type) {
        case GL20.GL_VERTEX_SHADER:
            return "GL_VERTEX_SHADER";
        case GL20.GL_FRAGMENT_SHADER:
            return "GL_FRAGMENT_SHADER";
        default:
            return "shader";
        }
    }

    /**
     * Make this shader the active program.
     */
    public void use() {
        GL20.glUseProgram(this.program);
    }

    /**
     * Destroy this shader program. 
     * Frees resources used by this program.
     */
    public void destroy() {
        //Flag this program for deletion. Will be deleated when no longer in use. 
        GL20.glDeleteProgram(this.program);
    }

}