/*
* Copyright (c) 2016, Metron, Inc.
* 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 Metron, Inc. 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 METRON, INC. 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.
*/
package com.metsci.glimpse.dnc.util;
import static com.google.common.base.Charsets.UTF_8;
import static com.metsci.glimpse.util.GeneralUtils.array;
import static javax.media.opengl.GL.GL_NO_ERROR;
import static javax.media.opengl.GL.GL_TRUE;
import static javax.media.opengl.GL2ES2.GL_COMPILE_STATUS;
import static javax.media.opengl.GL2ES2.GL_FRAGMENT_SHADER;
import static javax.media.opengl.GL2ES2.GL_INFO_LOG_LENGTH;
import static javax.media.opengl.GL2ES2.GL_LINK_STATUS;
import static javax.media.opengl.GL2ES2.GL_VERTEX_SHADER;
import static javax.media.opengl.GL3.GL_GEOMETRY_SHADER;
import static jogamp.opengl.glu.error.Error.gluErrorString;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import com.metsci.glimpse.util.primitives.IntsArray;
public class Shaders
{
public static int createProgram( GL2ES2 gl, String vertSource, String geomSource, String fragSource )
{
IntsArray shaders = new IntsArray( );
try
{
if ( vertSource != null ) shaders.append( compileShader( gl, GL_VERTEX_SHADER, vertSource ) );
if ( geomSource != null ) shaders.append( compileShader( gl, GL_GEOMETRY_SHADER, geomSource ) );
if ( fragSource != null ) shaders.append( compileShader( gl, GL_FRAGMENT_SHADER, fragSource ) );
return linkProgram( gl, shaders.a );
}
finally
{
for ( int i = 0; i < shaders.n; i++ )
{
gl.glDeleteShader( shaders.v( i ) );
}
}
}
public static int compileShader( GL2ES2 gl, int shaderType, String source )
{
return compileShader( gl, shaderType, array( source ) );
}
public static int compileShader( GL2ES2 gl, int shaderType, String[] sources )
{
int shader = gl.glCreateShader( shaderType );
gl.glShaderSource( shader, 1, sources, null );
gl.glCompileShader( shader );
int[] compileStatus = new int[ 1 ];
gl.glGetShaderiv( shader, GL_COMPILE_STATUS, compileStatus, 0 );
if ( compileStatus[ 0 ] != GL_TRUE ) throw new RuntimeException( getShaderInfoLog( gl, shader ) );
return shader;
}
public static String getShaderInfoLog( GL2ES2 gl, int shader )
{
int[] maxLength = new int[ 1 ];
gl.glGetShaderiv( shader, GL_INFO_LOG_LENGTH, maxLength, 0 );
if ( maxLength[ 0 ] == 0 ) return "";
int[] length = new int[ 1 ];
byte[] bytes = new byte[ maxLength[ 0 ] ];
gl.glGetShaderInfoLog( shader, maxLength[ 0 ], length, 0, bytes, 0 );
return new String( bytes, 0, length[ 0 ], UTF_8 );
}
public static void requireNoErrors( GL gl )
{
int error = gl.glGetError( );
if ( error != GL_NO_ERROR )
{
throw new RuntimeException( gluErrorString( error ) );
}
}
public static int linkProgram( GL2ES2 gl, int... shaders )
{
int program = gl.glCreateProgram( );
for ( int s : shaders ) gl.glAttachShader( program, s );
try
{
gl.glLinkProgram( program );
int[] linkStatus = new int[ 1 ];
gl.glGetProgramiv( program, GL_LINK_STATUS, linkStatus, 0 );
if ( linkStatus[ 0 ] != GL_TRUE ) throw new RuntimeException( getProgramInfoLog( gl, program ) );
return program;
}
finally
{
for ( int s : shaders ) gl.glDetachShader( program, s );
}
}
public static String getProgramInfoLog( GL2ES2 gl, int program )
{
int[] maxLength = new int[ 1 ];
gl.glGetProgramiv( program, GL_INFO_LOG_LENGTH, maxLength, 0 );
if ( maxLength[ 0 ] == 0 ) return "";
int[] length = new int[ 1 ];
byte[] bytes = new byte[ maxLength[ 0 ] ];
gl.glGetProgramInfoLog( program, maxLength[ 0 ], length, 0, bytes, 0 );
return new String( bytes, 0, length[ 0 ], UTF_8 );
}
}